Add gstreamer-vaapi
authorEunhye Choi <eunhae1.choi@samsung.com>
Tue, 23 Jul 2024 06:38:12 +0000 (15:38 +0900)
committerEunhye Choi <eunhae1.choi@samsung.com>
Tue, 23 Jul 2024 06:38:18 +0000 (15:38 +0900)
Change-Id: Ib828273898e124c3ab74db23aed2c9b243d3196e

282 files changed:
meson_options.txt
packaging/gstreamer.spec
subprojects/gstreamer-vaapi/AUTHORS [new file with mode: 0644]
subprojects/gstreamer-vaapi/COPYING [new file with mode: 0644]
subprojects/gstreamer-vaapi/COPYING.LIB [new file with mode: 0644]
subprojects/gstreamer-vaapi/NEWS [new file with mode: 0644]
subprojects/gstreamer-vaapi/README [new file with mode: 0644]
subprojects/gstreamer-vaapi/RELEASE [new file with mode: 0644]
subprojects/gstreamer-vaapi/docs/gst_plugins_cache.json [new file with mode: 0644]
subprojects/gstreamer-vaapi/docs/index.md [new file with mode: 0644]
subprojects/gstreamer-vaapi/docs/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/docs/sitemap.txt [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/egl_compat.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/egl_vtable.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiblend.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiblend.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapibufferproxy.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapibufferproxy.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodec_objects.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodec_objects.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbuffer.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbuffer.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbuffer_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferpool.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferpool.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferproxy_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicompat.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicontext.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicontext.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidebug.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_av1.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_av1.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_dpb.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_dpb.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h264.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h264.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h265.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h265.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_objects.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_objects.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_unit.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_unit.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vc1.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp8.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp8.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp9.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp9.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_drm.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_drm.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_egl.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_egl.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_glx.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_glx.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_wayland.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_wayland.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_x11.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_x11.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h264.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h264.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h265.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h265.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_objects.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_objects.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp8.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp8.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapifilter.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapifilter.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimage.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimage.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimage_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimagepool.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimagepool.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiminiobject.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiminiobject.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiparser_frame.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiparser_frame.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofile.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofile.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofilecaps.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofilecaps.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisubpicture.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisubpicture.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_drm.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_drm.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_egl.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_egl.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfacepool.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfacepool.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfaceproxy.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfaceproxy.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_egl.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_egl.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_glx.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_glx.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexturemap.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexturemap.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitypes.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_core.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_core.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_egl.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_egl.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_glx.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_glx.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h264.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h264.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h265.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h265.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h26x.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_vpx.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_vpx.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_x11.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_x11.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivalue.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivalue.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivideopool.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivideopool.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivideopool_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_drm.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_drm.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_egl.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_egl.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_glx.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_glx.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_wayland.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_x11.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_x11.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiworkarounds.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/ogl_compat.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/sysdeps.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/video-format.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/video-format.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst-libs/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstcompat.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapi.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapi.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode_props.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode_props.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecodebin.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecodebin.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecodedoc.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h264.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h264.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h265.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h265.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_jpeg.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_jpeg.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_mpeg2.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_mpeg2.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp8.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp8.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp9.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp9.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapioverlay.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapioverlay.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginbase.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginbase.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginutil.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginutil.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostproc.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostproc.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostprocutil.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostprocutil.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapisink.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapisink.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobuffer.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobuffer.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobufferpool.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobufferpool.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideocontext.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideocontext.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideomemory.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideomemory.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa_texture.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa_texture.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/gst/vaapi/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/gstreamer-vaapi.doap [new file with mode: 0644]
subprojects/gstreamer-vaapi/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/meson_options.txt [new file with mode: 0644]
subprojects/gstreamer-vaapi/scripts/extract-release-date-from-doap-file.py [new file with mode: 0644]
subprojects/gstreamer-vaapi/scripts/gen-changelog.py [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/check/elements/vaapioverlay.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/check/elements/vaapipostproc.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/check/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/examples/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/examples/test-roi.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/examples/test-vaapicontext.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/examples/test-vaapipostproc.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/examples/test-vaapisink.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/codec.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/codec.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/decoder.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/decoder.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/image.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/image.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/meson.build [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/output.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/output.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/simple-decoder.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/simple-encoder.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-decode.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-decode.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-display.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-filter.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-h264.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-h264.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-jpeg.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-jpeg.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-mpeg2.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-mpeg2.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-mpeg4.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-mpeg4.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-subpicture-data.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-subpicture-data.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-subpicture.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-surfaces.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-textures.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-vc1.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-vc1.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/test-windows.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/y4mreader.c [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/internal/y4mreader.h [new file with mode: 0644]
subprojects/gstreamer-vaapi/tests/meson.build [new file with mode: 0644]

index 7c39018d67793cb52dd9dbf3f66dba2a013c969a..2b4b50d4ef90efae138946c49b1d45c75011b0bf 100644 (file)
@@ -10,7 +10,7 @@ option('devtools', type : 'feature', value : 'auto')
 option('ges', type : 'feature', value : 'enabled')
 option('rtsp_server', type : 'feature', value : 'enabled')
 option('omx', type : 'feature', value : 'enabled')
-option('vaapi', type : 'feature', value : 'disabled')
+option('vaapi', type : 'feature', value : 'enabled')
 option('sharp', type : 'feature', value : 'disabled')
 option('rs', type : 'feature', value : 'disabled')
 option('gst-examples', type : 'feature', value : 'auto', description : 'Build gst-examples')
index 298a09ab01abdcd2a0a61ae0632d94a4db9fd4f2..c16b110e7e8114a3b970a00266f66f946ae63881 100644 (file)
@@ -1,5 +1,5 @@
 %bcond_with x
-%bcond_with wayland
+%bcond_without wayland
 
 %define gst_branch 1.0
 %define _lib_gstreamer_dir %{_libdir}/gstreamer-%{gst_branch}
     %define _name gst-editing-services
     %define _es_opt ""
   %endif
+  %if "%{plugin}" == "va"
+    %define _name gstreamer-vaapi
+    %define _va_opt ""
+  %endif
 
   %define _source_path subprojects/%{_name}
 
@@ -57,6 +61,7 @@
   %define _libav_opt gst-libav:
   %define _rs_opt gst-rtsp-server:
   %define _es_opt gst-editing-services:
+  %define _va_opt gstreamer-vaapi:
 
 %endif
 
@@ -328,6 +333,7 @@ BuildRequires:  pkgconfig(libxml-2.0)
 BuildRequires:  pkgconfig(wayland-client) >= 1.0.0
 BuildRequires:  pkgconfig(wayland-cursor) >= 1.0.0
 BuildRequires:  pkgconfig(wayland-protocols)
+BuildRequires:  pkgconfig(libva)
 %endif
 %if %{with x}
 BuildRequires:  pkgconfig(x11)
@@ -516,6 +522,40 @@ developing applications that use %{name}
 
 %endif # profile
 
+
+#######################################################
+## Package info of vaapi Plugin
+#######################################################
+
+%if "%{plugin}" == "all"
+%package -n gstreamer-vaapi
+Summary:        GStreamer VA API Plug-Ins
+Group:          Multimedia/Framework
+%endif
+
+%if "%{plugin}" == "all" || "%{plugin}" == "va"
+BuildRequires:  pkgconfig(gstreamer-plugins-bad-1.0)
+BuildRequires:  pkgconfig(libva)
+BuildRequires:  pkgconfig(libudev)
+#BuildRequires:  pkgconfig(gstreamer-codecparsers-1.0)
+%if %{with wayland}
+%if 0%{?enable_gl:1}
+BuildRequires:  pkgconfig(gles20)
+BuildRequires:  pkgconfig(wayland-egl) >= 9.0
+#BuildRequires:  pkgconfig(gstreamer-gl-1.0)
+%endif # gl
+BuildRequires:  pkgconfig(libdrm)
+BuildRequires:  pkgconfig(libxml-2.0)
+BuildRequires:  pkgconfig(wayland-client) >= 1.0.0
+BuildRequires:  pkgconfig(wayland-cursor) >= 1.0.0
+BuildRequires:  pkgconfig(wayland-protocols)
+%endif # wayland
+
+%description -n gstreamer-vaapi
+This is a gstreamer vaapi library
+
+%endif # plugin
+
 #######################################################
 ## Prep
 #######################################################
@@ -533,6 +573,7 @@ cp %{SOURCE1001} ./gst-rtsp-server.manifest
 cp %{SOURCE1001} ./gst-omx.manifest
 cp %{SOURCE1001} ./gst-editing-services.manifest
 %endif
+cp %{SOURCE1001} ./gstreamer-vaapi.manifest
 
 #######################################################
 ## Build
@@ -700,7 +741,6 @@ meson --auto-features=disabled --prefix=/usr --libdir=%{_libdir} --datadir=%{_da
   -D %{_bad_opt}timecode=enabled \
   -D %{_bad_opt}videoframe_audiolevel=enabled \
   -D %{_bad_opt}videoparsers=enabled \
-  -D %{_bad_opt}wayland=enabled \
   -D %{_bad_opt}webrtc=enabled \
   %if %{with wayland}
     -D %{_bad_opt}wayland=enabled \
@@ -722,6 +762,7 @@ meson --auto-features=disabled --prefix=/usr --libdir=%{_libdir} --datadir=%{_da
     -D %{_bad_opt}rtp=enabled \
     -D %{_bad_opt}srt=enabled \
     -D %{_bad_opt}smoothstreaming=enabled \
+    -D %{_bad_opt}va=enabled \
     %if 0%{?enable_gl:1}
       -D %{_bad_opt}gl=enabled \
     %endif # gl
@@ -776,6 +817,17 @@ meson --auto-features=disabled --prefix=/usr --libdir=%{_libdir} --datadir=%{_da
     -D %{_es_opt}python=enabled \
   %endif # plugin
 %endif # profile
+%if "%{plugin}" == "all" || "%{plugin}" == "va"
+  -D %{_va_opt}drm=enabled \
+  %if %{with wayland}
+    %if 0%{?enable_gl:1}
+      -D %{_va_opt}egl=enabled \
+    %endif # gl
+    -D %{_va_opt}wayland=enabled \
+  %endif # wayland
+  -D %{_va_opt}x11=disabled \
+  -D %{_va_opt}glx=disabled \
+%endif # plugin
   build
 
 ninja -C build all %{?_smp_mflags}
@@ -1170,6 +1222,9 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/libgstwebrtc-%{gst_branch}.so.0*
 %{_libdir}/libgstwebrtcnice-%{gst_branch}.so.0*
 %exclude %{_bindir}/gst-transcoder-%{gst_branch}
+# VA
+%{_lib_gstreamer_dir}/libgstva.so
+%{_libdir}/libgstva-%{gst_branch}.so.*
 
 %files -n gst-plugins-bad-devel
 %manifest gst-plugins-bad.manifest
@@ -1241,6 +1296,11 @@ rm -rf $RPM_BUILD_ROOT
 %{_libdir}/pkgconfig/gstreamer-webrtc-%{gst_branch}.pc
 %{_libdir}/pkgconfig/gstreamer-webrtc-nice-%{gst_branch}.pc
 
+# VA
+%{_libdir}/libgstva-%{gst_branch}.so
+%{_includedir}/gstreamer-%{gst_branch}/gst/va/*
+%{_libdir}/pkgconfig/gstreamer-va-%{gst_branch}.pc
+
 %endif # plugin
 
 ###################### gst-plugins-ugly ######################
@@ -1332,3 +1392,15 @@ rm -rf $RPM_BUILD_ROOT
 %endif # plugin
 
 %endif # profile
+
+###################### gstreamer-vaapi #######################
+
+%if "%{plugin}" == "all" || "%{plugin}" == "va"
+
+%files -n gstreamer-vaapi
+%manifest gstreamer-vaapi.manifest
+%defattr(-,root,root,-)
+%license subprojects/gstreamer-vaapi/COPYING.LIB
+%{_lib_gstreamer_dir}/libgstvaapi.so
+
+%endif # plugin
diff --git a/subprojects/gstreamer-vaapi/AUTHORS b/subprojects/gstreamer-vaapi/AUTHORS
new file mode 100644 (file)
index 0000000..cb1e39b
--- /dev/null
@@ -0,0 +1,45 @@
+Maintainers:
+
+Gwenole Beauchesne      - Lead developer
+Sreerenj Balachandran   - Lead developer
+Halley Zhao             - MPEG-4:2 decoder
+
+This project is maintained by Intel Corporation.
+
+Contributors (sorted by first name):
+
+Adrian Cox
+Alban Browaeys
+Changzhi Wei
+Cong Zhong
+Emilio Lopez
+Fabrice Bellet
+Feng Yuan
+Guangxin Xu
+Haihao Xiang
+Holger Kaelberer
+Jacobo Aragunde Pérez
+Jan Schmidt
+Javier Jardon
+Julien Isorce
+Junfeng Xu
+Kristian Hogsberg
+Lim Siew Hoon
+Lionel Landwerlin
+Mark Nauwelaerts
+Martin Sherburn
+Matthew Waters
+Matthieu Bouron
+Michael Olbrich
+Nicolas Dufresne
+Olivier Crete
+Philip Lorenz
+Robert Bradford
+Ross Burton
+Sebastian Dröge
+Simon Farnsworth
+Thibault Saunier
+Victor Manuel Jaquez Leal
+Warly
+Xiaowei Li
+Yan Yin
diff --git a/subprojects/gstreamer-vaapi/COPYING b/subprojects/gstreamer-vaapi/COPYING
new file mode 100644 (file)
index 0000000..efce2a8
--- /dev/null
@@ -0,0 +1,503 @@
+                 GNU LESSER GENERAL PUBLIC LICENSE
+                      Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+     51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                           Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                 GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+  
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                           NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                    END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
+
diff --git a/subprojects/gstreamer-vaapi/COPYING.LIB b/subprojects/gstreamer-vaapi/COPYING.LIB
new file mode 100644 (file)
index 0000000..4362b49
--- /dev/null
@@ -0,0 +1,502 @@
+                  GNU LESSER GENERAL PUBLIC LICENSE
+                       Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL.  It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+  This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it.  You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+  When we speak of free software, we are referring to freedom of use,
+not price.  Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+  To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights.  These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+  For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you.  You must make sure that they, too, receive or can get the source
+code.  If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it.  And you must show them these terms so they know their rights.
+
+  We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+  To protect each distributor, we want to make it very clear that
+there is no warranty for the free library.  Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+\f
+  Finally, software patents pose a constant threat to the existence of
+any free program.  We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder.  Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+  Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License.  This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License.  We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+  When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library.  The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom.  The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+  We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License.  It also provides other free software developers Less
+of an advantage over competing non-free programs.  These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries.  However, the Lesser license provides advantages in certain
+special circumstances.
+
+  For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard.  To achieve this, non-free programs must be
+allowed to use the library.  A more frequent case is that a free
+library does the same job as widely used non-free libraries.  In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+  In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software.  For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+  Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.  Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library".  The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+\f
+                  GNU LESSER GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+  A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+  The "Library", below, refers to any such software library or work
+which has been distributed under these terms.  A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language.  (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+  "Source code" for a work means the preferred form of the work for
+making modifications to it.  For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+  Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it).  Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+  1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+  You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+\f
+  2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) The modified work must itself be a software library.
+
+    b) You must cause the files modified to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    c) You must cause the whole of the work to be licensed at no
+    charge to all third parties under the terms of this License.
+
+    d) If a facility in the modified Library refers to a function or a
+    table of data to be supplied by an application program that uses
+    the facility, other than as an argument passed when the facility
+    is invoked, then you must make a good faith effort to ensure that,
+    in the event an application does not supply such function or
+    table, the facility still operates, and performs whatever part of
+    its purpose remains meaningful.
+
+    (For example, a function in a library to compute square roots has
+    a purpose that is entirely well-defined independent of the
+    application.  Therefore, Subsection 2d requires that any
+    application-supplied function or table used by this function must
+    be optional: if the application does not supply it, the square
+    root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library.  To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License.  (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.)  Do not make any other change in
+these notices.
+\f
+  Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+  This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+  4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+  If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library".  Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+  However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library".  The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+  When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library.  The
+threshold for this to be true is not precisely defined by law.
+
+  If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work.  (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+  Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+\f
+  6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+  You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License.  You must supply a copy of this License.  If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License.  Also, you must do one
+of these things:
+
+    a) Accompany the work with the complete corresponding
+    machine-readable source code for the Library including whatever
+    changes were used in the work (which must be distributed under
+    Sections 1 and 2 above); and, if the work is an executable linked
+    with the Library, with the complete machine-readable "work that
+    uses the Library", as object code and/or source code, so that the
+    user can modify the Library and then relink to produce a modified
+    executable containing the modified Library.  (It is understood
+    that the user who changes the contents of definitions files in the
+    Library will not necessarily be able to recompile the application
+    to use the modified definitions.)
+
+    b) Use a suitable shared library mechanism for linking with the
+    Library.  A suitable mechanism is one that (1) uses at run time a
+    copy of the library already present on the user's computer system,
+    rather than copying library functions into the executable, and (2)
+    will operate properly with a modified version of the library, if
+    the user installs one, as long as the modified version is
+    interface-compatible with the version that the work was made with.
+
+    c) Accompany the work with a written offer, valid for at
+    least three years, to give the same user the materials
+    specified in Subsection 6a, above, for a charge no more
+    than the cost of performing this distribution.
+
+    d) If distribution of the work is made by offering access to copy
+    from a designated place, offer equivalent access to copy the above
+    specified materials from the same place.
+
+    e) Verify that the user has already received a copy of these
+    materials or that you have already sent this user a copy.
+
+  For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it.  However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+  It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system.  Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+\f
+  7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+    a) Accompany the combined library with a copy of the same work
+    based on the Library, uncombined with any other library
+    facilities.  This must be distributed under the terms of the
+    Sections above.
+
+    b) Give prominent notice with the combined library of the fact
+    that part of it is a work based on the Library, and explaining
+    where to find the accompanying uncombined form of the same work.
+
+  8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License.  Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License.  However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+  9. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Library or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+  10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+\f
+  11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded.  In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+  13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation.  If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+\f
+  14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission.  For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this.  Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+                            NO WARRANTY
+
+  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+\f
+           How to Apply These Terms to Your New Libraries
+
+  If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change.  You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+  To apply these terms, attach the following notices to the library.  It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the library's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the
+  library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+  <signature of Ty Coon>, 1 April 1990
+  Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/subprojects/gstreamer-vaapi/NEWS b/subprojects/gstreamer-vaapi/NEWS
new file mode 100644 (file)
index 0000000..d561a39
--- /dev/null
@@ -0,0 +1,2758 @@
+GStreamer 1.22 Release Notes
+
+GStreamer 1.22.0 was originally released on 23 January 2023.
+
+The latest bug-fix release in the stable 1.22 series is 1.22.8 and was
+released on 18 December 2023.
+
+See https://gstreamer.freedesktop.org/releases/1.22/ for the latest
+version of this document.
+
+Last updated: Monday 18 December 2023, 11:00 UTC (log)
+
+Introduction
+
+The GStreamer team is proud to announce a new major feature release in
+the stable 1.x API series of your favourite cross-platform multimedia
+framework!
+
+As always, this release is again packed with many new features, bug
+fixes and other improvements.
+
+Highlights
+
+-   AV1 video codec support improvements
+-   New HLS, DASH and Microsoft Smooth Streaming adaptive streaming
+    clients
+-   Qt6 support for rendering video inside a QML scene
+-   Minimal builds optimised for binary size, including only the
+    individual elements needed
+-   Playbin3, Decodebin3, UriDecodebin3, Parsebin enhancements and
+    stabilisation
+-   WebRTC simulcast support and support for Google Congestion Control
+-   WebRTC-based media server ingestion/egress (WHIP/WHEP) support
+-   New easy to use batteries-included WebRTC sender plugin
+-   Easy RTP sender timestamp reconstruction for RTP and RTSP
+-   ONVIF timed metadata support
+-   New fragmented MP4 muxer and non-fragmented MP4 muxer
+-   New plugins for Amazon AWS storage and audio transcription services
+-   New gtk4paintablesink and gtkwaylandsink renderers
+-   New videocolorscale element that can convert and scale in one go for
+    better performance
+-   High bit-depth video improvements
+-   Touchscreen event support in navigation API
+-   Rust plugins now shipped in macOS and Windows/MSVC binary packages
+-   H.264/H.265 timestamp correction elements for PTS/DTS reconstruction
+    before muxers
+-   Improved design for DMA buffer sharing and modifier handling for
+    hardware-accelerated video decoders/encoders/filters and
+    capturing/rendering on Linux
+-   Video4Linux2 hardware accelerated decoder improvements
+-   CUDA integration and Direct3D11 integration and plugin improvements
+-   New H.264 / AVC, H.265 / HEVC and AV1 hardware-accelerated video
+    encoders for AMD GPUs using the Advanced Media Framework (AMF) SDK
+-   applemedia: H.265 / HEVC video encoding + decoding support
+-   androidmedia: H.265 / HEVC video encoding support
+-   New “force-live” property for audiomixer, compositor, glvideomixer,
+    d3d11compositor etc.
+-   Lots of new plugins, features, performance improvements and bug
+    fixes
+
+Major new features and changes
+
+AV1 video codec support improvements
+
+AV1 is a royalty free next-generation video codec by AOMedia and a free
+alternative to H.265/HEVC.
+
+While supported in earlier versions of GStreamer already, this release
+saw a lot of improvements across the board:
+
+-   Support for hardware encoding and decoding via VAAPI/VA, AMF, D3D11,
+    NVCODEC, QSV and Intel MediaSDK. Hardware codecs for AV1 are slowly
+    becoming available in embedded systems and desktop GPUs (AMD, Intel,
+    NVIDIA), and these can now be used via GStreamer.
+
+-   New AV1 RTP payloader and depayloader elements.
+
+-   New encoder settings in the AOM reference encoder-based av1enc
+    element.
+
+-   Various improvements in the AV1 parser and in the MP4/Matroska/WebM
+    muxers/demuxers.
+
+-   dav1d and rav1e based software decoder/encoder elements shipped as
+    part of the binaries.
+
+-   AV1 parser improvements and various bugfixes all over the place.
+
+Touchscreen event support in Navigation API
+
+The Navigation API supports the sending of key press events and mouse
+events through a GStreamer pipeline. Typically these will be picked up
+by a video sink on which these events happen and then the event is
+transmitted into the pipeline so it can be handled by elements inside
+the pipeline if it wasn’t handled by the application.
+
+This has traditionally been used for DVD menu support, but can also be
+used to forward such inputs to source elements that render a web page
+using a browser engine such as WebKit or Chromium.
+
+This API has now gained support for touchscreen events, and this has
+been implemented in various plugins such as the GTK, Qt, XV, and x11
+video sinks as well as the wpevideosrc element.
+
+GStreamer CUDA integration
+
+-   New gst-cuda library
+-   integration with D3D11 and NVIDIA dGPU NVMM elements
+-   new cudaconvertscale element
+
+GStreamer Direct3D11 integration
+
+-   New gst-d3d11 public library
+    -   gst-d3d11 library is not integrated with GStreamer documentation
+        system yet. Please refer to the examples
+-   d3d11screencapture: Add Windows Graphics Capture API based capture
+    mode, including Win32 application window capturing
+-   d3d11videosink and d3d11convert can support flip/rotation and crop
+    meta
+-   d3d11videosink: New emit-present property and present signal so that
+    applications can overlay an image on Direct3D11 swapchain’s
+    backbuffer via Direct3D/Direct2D APIs. See also C++ and Rust
+    examples
+-   d3d11compositor supports YUV blending/composing without intermediate
+    RGB(A) conversion to improve performance
+-   Direct3D11 video decoders are promoted to GST_RANK_PRIMARY or
+    higher, except for the MPEG2 decoder
+
+H.264/H.265 timestamp correction elements
+
+-   Muxers are often picky and need proper PTS/DTS timestamps set on the
+    input buffers, but that can be a problem if the encoded input media
+    stream comes from a source that doesn’t provide proper signalling of
+    DTS, such as is often the case for RTP, RTSP and WebRTC streams or
+    Matroska container files. Theoretically parsers should be able to
+    fix this up, but it would probably require fairly invasive changes
+    in the parsers, so two new elements h264timestamper and
+    h265timestamper bridge the gap in the meantime and can reconstruct
+    missing PTS/DTS.
+
+Easy sender timestamp reconstruction for RTP and RTSP
+
+-   it was always possible to reconstruct and retrieve the original RTP
+    sender timestamps in GStreamer, but required a fair bit of
+    understanding of the internal mechanisms and the right property
+    configuration and clock setup.
+
+-   rtspsrc and rtpjitterbuffer gained a new
+    “add-reference-timestamp-meta” property that if set puts the
+    original absolute reconstructed sender timestamps on the output
+    buffers via a meta. This is particularly useful if the sender is
+    synced to an NTP clock or PTP clock. The original sender timestamps
+    are either based on the RTCP NTP times, NTP RTP header extensions
+    (RFC6051) or RFC7273-style clock signalling.
+
+Qt6 support
+
+-   new qml6glsink element for Qt6 similar to the existing Qt5 element.
+    Matching source and overlay elements will hopefully follow in the
+    near future.
+
+OpenGL + Video library enhancements
+
+-   Support for new video formats (NV12_4L4, NV12_16L32S, NV12_8L128,
+    NV12_10BE_8L128) and dmabuf import in more formats (Y410, Y212_LE,
+    Y212_BE, Y210, NV21, NV61)
+
+-   Improved support for tiled formats with arbitrary tile dimensions,
+    as needed by certain hardware decoders/encoders
+
+-   glvideomixer: New “crop-left,”crop-right, “crop-top” and
+    “crop-bottom” pad properties for cropping inputs
+
+-   OpenGL support for gst_video_sample_convert():
+
+    -   Used for video snapshotting and thumbnailing, to convert buffers
+        retrieved from appsinks or sink “last-sample” properties in
+        JPG/PNG thumbnails.
+    -   This function can now take samples and buffers backed by GL
+        textures as input and will automatically plug a gldownload
+        element in that case.
+
+High bit-depth support (10, 12, 16 bits per component value) improvements
+
+-   compositor can now handle any supported input format and also mix
+    high-bitdepth (10-16 bit) formats (naively)
+
+-   videoflip has gained support for higher bit depth formats.
+
+-   vp9enc, vp9dec now support 12-bit formats and also 10-bit 4:4:4
+
+WebRTC
+
+-   Allow insertion of bandwidth estimation elements e.g. for Google
+    Congestion Control (GCC) support
+
+-   Initial support for sending or receiving simulcast streams
+
+-   Support for asynchronous host resolution for STUN/TURN servers
+
+-   GstWebRTCICE was split into base classes and implementation to make
+    it possible to plug custom ICE implementations
+
+-   webrtcsink: batteries-included WebRTC sender (Rust)
+
+-   whipsink: WebRTC HTTP ingest (WHIP) to a MediaServer (Rust)
+
+-   whepsrc: WebRTC HTTP egress (WHEP) from a MediaServer (Rust)
+
+-   Many other improvements and bug fixes
+
+New HLS, DASH and MSS adaptive streaming clients
+
+A new set of “adaptive demuxers” to support HLS, DASH and MSS adaptive
+streaming protocols has been added. They provide improved performance,
+new features and better stream compatibility compared to the previous
+elements. These new elements require a “streams-aware” pipeline such as
+playbin3, uridecodebin3 or urisourcebin.
+
+The previous elements’ design prevented implementing several use-cases
+and fixing long-standing issues. The new elements were re-designed from
+scratch to tackle those:
+
+-   Scheduling Only 3 threads are present, regardless of the number of
+    streams selected. One in charge of downloading fragments and
+    manifests, one in charge of outputting parsed data downstream, and
+    one in charge of scheduling. This improves performance, resource
+    usage and latency.
+
+-   Better download control The elements now directly control the
+    scheduling and download of manifests and fragments using libsoup
+    directly instead of depending on external elements for downloading.
+
+-   Stream selection, only the selected streams are downloaded. This
+    improves bandwith usage. Switching stream is done in such a way to
+    ensure there are no gaps, meaning the new stream will be switched to
+    only once enough data for it has been downloaded.
+
+-   Internal parsing, the downloaded streams are parsed internally. This
+    allows the element to fully respect the various specifications and
+    offer accurate buffering, seeking and playback. This is especially
+    important for HLS streams which require parsing for proper
+    positioning of streams.
+
+-   Buffering and adaptive rate switching, the new elements handle
+    buffering internally which allows them to have a more accurate
+    visibility of which bandwith variant to switch to.
+
+Playbin3, Decodebin3, UriDecodebin3, Parsebin improvements
+
+The “new” playback elements introduced in 1.18 (playbin3 and its various
+components) have been refactored to allow more use-cases and improve
+performance. They are no longer considered experimental, so applications
+using the legacy playback elements (playbin and (uri)decodebin) can
+migrate to the new components to benefit from these improvements.
+
+-   Gapless The “gapless” feature allows files and streams to be
+    fetched, buffered and decoded in order to provide a “gapless”
+    output. This feature has been refactored extensively in the new
+    components:
+    -   A single (uri)decodebin3 (and therefore a single set of
+        decoders) is used. This improves memory and cpu usage, since on
+        identical codecs a single decoder will be used.
+    -   The “next” stream to play will be pre-rolled “just-in-time”
+        thanks to the buffering improvements in urisourcebin (see below)
+    -   This feature is now handled at the uridecodebin3 level.
+        Applications that wish to have a “gapless” stream and process it
+        (instead of just outputting it, for example for transcoding,
+        retransmission, …) can now use uridecodebin3 directly. Note that
+        a streamsynchronizer element is required in that case.
+-   Buffering improvements The urisourcebin element is in charge of
+    fetching and (optionally) buffering/downloading the stream. It has
+    been extended and improved:
+    -   When the parse-streams property is used (by default in
+        uridecodebin3 and playbin3), compatible streams will be demuxed
+        and parsed (via parsebin) and buffering will be done on the
+        elementary streams. This provides a more accurate handling of
+        buffering. Previously buffering was done on a best-effort basis
+        and was mostly wrong (i.e. downloading more than needed).
+    -   Applications can use urisourcebin with this property as a
+        convenient way of getting elementary streams from a given URI.
+    -   Elements can handle buffering themselves (such as the new
+        adaptive demuxers) by answering the GST_QUERY_BUFFERING query.
+        In that case urisourcebin will not handle it.
+-   Stream Selection Efficient stream selection was previously only
+    possible within decodebin3. The downside is that this meant that
+    upstream elements had to provide all the streams from which to chose
+    from, which is inefficient. With the addition of the
+    GST_QUERY_SELECTABLE query, this can now be handled by elements
+    upstream (i.e. sources)
+    -   Elements that can handle stream selection internally (such as
+        the new adaptive demuxer elements) answer that query, and handle
+        the stream selection events themselves.
+    -   In this case, decodebin3 will always process all streams that
+        are provided to it.
+-   Instant URI switching This new feature allows switching URIs
+    “instantly” in playbin3 (and uridecodebin3) without having to change
+    states. This mimics switching channels on a television.
+    -   If compatible, decoders will be re-used, providing lower
+        latency/cpu/memory than by switching states.
+    -   This is enabled by setting the instant-uri property to true,
+        setting the URI to switch to immediately, and then disabling the
+        instant-uri property again afterwards.
+-   playbin3, decodebin3, uridecodebin3, parsebin, and urisourcebin are
+    no longer experimental
+    -   They were originally marked as ‘technology preview’ but have
+        since seen extensive usage in production settings, so are
+        considered ready for general use now.
+
+Fraunhofer AAC audio encoder HE-AAC and AAC-LD profile support
+
+-   fdkaacenc:
+    -   Support for encoding to HE-AACv1 and HE-AACv2 profile
+    -   Support for encoding to AAC Low Delay (LD) profile
+    -   Advanced bitrate control options via new “rate-control”,
+        “vbr-preset”, “peak-bitrate”, and “afterburner” properties
+
+RTP rapid synchronization support in the RTP stack (RFC6051)
+
+RTP provides several mechanisms how streams can be synchronized relative
+to each other, and how absolute sender times for RTP packets can be
+obtained. One of these mechanisms is via RTCP, which has the
+disadvantage that the synchronization information is only distributed
+out-of-band and usually some time after the start.
+
+GStreamer’s RTP stack, specifically the rtpbin, rtpsession and
+rtpjitterbuffer elements, now also have support for retrieving and
+sending the same synchronization information in-band via RTP header
+extensions according to RFC6051 (Rapid Synchronisation of RTP Flows).
+Only 64-bit timestamps are supported currently.
+
+This provides per packet synchronization information from the very
+beginning of a stream and allows accurate inter-stream, and (depending
+on setup) inter-device, synchronization at the receiver side.
+
+ONVIF XML Timed Metadata support
+
+The ONVIF standard implemented by various security cameras also
+specifies a format for timed metadata that is transmitted together with
+the audio/video streams, usually over RTSP.
+
+Support for this timed metadata is implemented in the MP4 demuxer now as
+well as the new fragmented MP4 muxer and the new non-fragmented MP4
+muxer from the GStreamer Rust plugins. Additionally, the new onvif
+plugin ‒ which is part of the GStreamer Rust plugins ‒ provides general
+elements for handling the metadata and e.g. overlaying certain parts of
+it over a video stream.
+
+As part of this support for absolute UTC times was also implemented
+according to the requirements of the ONVIF standards in the
+corresponding elements.
+
+MP3 gapless playback support
+
+While MP3 can probably considered a legacy format at this point, a new
+feature was added with this release.
+
+When playing back plain MP3 files, i.e. outside a container format,
+switches between files can now be completely gapless if the required
+metadata is provided inside the file. There is no standardized metadata
+for this, but the LAME MP3 encoder writes metadata that can be parsed by
+the mpegaudioparse element now and forwarded to decoders for ensuring
+removal of padding samples at the front and end of MP3 files.
+
+“force-live” property for audio + video aggregators
+
+This is a quality of life fix for playout and streaming applications
+where it is common to have audio and video mixer elements that should
+operate in live mode from the start and produce output continuously.
+
+Often one would start a pipeline without any inputs hooked up to these
+mixers in the beginning, and up until now there was no way to easily
+force these elements into live mode from the start. One would have to
+add an initial live video or audio test source as dummy input to achieve
+this.
+
+The new “force-live” property makes these audio and video aggregators
+start in live mode without the need for any dummy inputs, which is
+useful for scenarios where inputs are only added after starting the
+pipeline.
+
+This new property should usually be used in connection with the
+“min-upstream-latency” property, i.e. you should always set a non-0
+minimum upstream latency then.
+
+This is now supported in all GstAudioAggregator and GstVideoAggregator
+subclasses such as audiomixer, audiointerleave, compositor,
+glvideomixer, d3d11compositor, etc.
+
+New elements and plugins
+
+-   new cudaconvertscale element that can convert and scale in one pass
+
+-   new gtkwaylandsink element based on gtksink, but similar to
+    waylandsink and uses Wayland APIs directly instead of rendering with
+    Gtk/Cairo primitives. This approach is only compatible with Gtk3,
+    and like gtksink this element only supports Gtk3.
+
+-   new h264timestamper and h265timestamper elements to reconstruct
+    missing pts/dts from inputs that might not provide them such as
+    e.g. RTP/RTSP/WebRTC inputs (see above)
+
+-   mfaacdec, mfmp3dec: Windows MediaFoundation AAC and MP3 decoders
+
+-   new msdkav1enc AV1 video encoder element
+
+-   new nvcudah264enc, nvcudah265enc, nvd3d11h264enc, and nvd3d11h265enc
+    NVIDIA GPU encoder elements to support zero-copy encoding, via CUDA
+    and Direct3D11 APIs, respectively
+
+-   new nvautogpuh264enc and nvautogpuh265enc NVIDIA GPU encoder
+    elements: The auto GPU elements will automatically select a target
+    GPU instance in case multiple NVIDIA desktop GPUs are present, also
+    taking into account the input memory. On Windows CUDA or Direct3D11
+    mode will be determined by the elements automatically as well. Those
+    new elements are useful if target GPU and/or API mode (either CUDA
+    or Direct3D11 in case of Windows) is undeterminable from the encoder
+    point of view at the time when pipeline is configured, and therefore
+    lazy target GPU and/or API selection are required in order to avoid
+    unnecessary memory copy operations.
+
+-   new nvav1dec AV1 NVIDIA desktop GPU decoder element
+
+-   new qml6glsink element to render video with Qt6
+
+-   qsv: New Intel OneVPL/MediaSDK (a.k.a Intel Quick Sync) based
+    decoder and encoder elements, with gst-d3d11 (on Windows) and gst-va
+    (on Linux) integration
+
+    -   Support multi-GPU environment, for example, concurrent video
+        encoding using Intel iGPU and dGPU in a single pipeline
+    -   H.264 / H.265 / VP9 and JPEG decoders
+    -   H.264 / H.265 / VP9 / AV1 / JPEG encoders with dynamic encoding
+        bitrate update
+    -   New plugin does not require external SDK for building on Windows
+
+-   vulkanoverlaycompositor: new vulkan overlay compositor element to
+    overlay upstream GstVideoOverlayCompositonMeta onto the video
+    stream.
+
+-   vulkanshaderspv: performs operations with SPIRV shaders in Vulkan
+
+-   win32ipcvideosink, win32ipcvideosrc: new shared memory videosrc/sink
+    elements for Windows
+
+-   wicjpegdec, wicpngdec: Windows Imaging Component (WIC) based JPEG
+    and PNG decoder elements.
+
+-   Many exciting new Rust elements, see Rust section below
+
+New element features and additions
+
+-   audioconvert: Dithering now uses a slightly slower, less biased PRNG
+    which results in better quality output. Also dithering can now be
+    enabled via the new “dithering-threshold” property for target bit
+    depths of more than 20 bits.
+
+-   av1enc: Add “keyframe-max-dist” property for controlling max
+    distance between keyframes, as well as “enc-pass”, “keyframe-mode”,
+    “lag-in-frames” and “usage-profile” properties.
+
+-   cccombiner: new “output-padding” property
+
+-   decklink: Add support for 4k DCI, 8k/UHD2 and 8k DCI modes
+
+-   dvbsubenc: Support for >SD resolutions is working correctly now.
+
+-   fdkaacenc: Add HE-AAC / HE-AACv2 profile support
+
+-   glvideomixer: New “crop-left,”crop-right, “crop-top” and
+    “crop-bottom” pad properties for cropping inputs
+
+-   gssink: new ‘content-type’ property. Useful when one wants to upload
+    a video as video/mp4 instead of ’video/quicktime` for example.
+
+-   jpegparse: Rewritten using the common parser library
+
+-   msdk:
+
+    -   new msdkav1enc AV1 video encoder element
+    -   msdk decoders: Add support for Scaler Format Converter (SFC) on
+        supported Intel platforms for hardware accelerated conversion
+        and scaling
+    -   msdk encoders: support import of dmabuf, va memory and D3D11
+        memory
+    -   msdk encoders: add properties for low delay bitrate control and
+        max frame sizes for I/P frames
+    -   msdkh264enc, msdkh265enc: more properties to control intra
+        refresh
+    -   note that on systems with multi GPUs the Windows D3D11
+        integration might only work reliably if the Intel GPU is the
+        primary GPU
+
+-   mxfdemux: Add support for Canon XF-HEVC
+
+-   openaptx: Support the freeaptx library
+
+-   qroverlay:
+
+    -   new “qrcode-case-sensitive” property allows encoding case
+        sensitive strings like wifi SSIDs or passwords.
+    -   added the ability to pick up data to render from an
+        upstream-provided custom GstQROverlay meta
+
+-   qtdemux: Add support for ONVIF XML Timed MetaData and AVC-Intra
+    video
+
+-   rfbsrc now supports the uri handler interface, so applications can
+    use RFB/VNC sources in uridecodebin(3) and playbin, with
+    e.g. rfb://:password@10.1.2.3:5903?shared=1
+
+-   rtponviftimestamp: Add support for using reference timestamps
+
+-   rtpvp9depay now has the same keyframe-related properties as
+    rtpvp8depay and rtph264depay: “request-keyframe” and
+    “wait-for-keyframe”
+
+-   rtspsrc: Various RTSP servers are using invalid URL operations for
+    constructing the control URL. Until GStreamer 1.16 these worked
+    correctly because GStreamer was just appending strings itself to
+    construct the control URL, but starting version 1.18 the correct URL
+    operations were used. With GStreamer 1.22, rtspsrc now first tries
+    with the correct control URL and if that fails it will retry with
+    the wrongly constructed control URL to restore support for such
+    servers.
+
+-   rtspsrc and rtpjitterbuffer gained a new
+    “add-reference-timestamp-meta” property that makes them put the
+    unmodified original sender timestamp on output buffers for NTP or
+    PTP clock synced senders
+
+-   srtsrc, srtsink: new “auto-reconnect” property to make it possible
+    to disable automatic reconnects (in caller mode) and make the
+    elements post an error immediately instead; also stats improvements
+
+-   srtsrc: new “keep-listening” property to avoid EOS on disconnect and
+    keep the source running while it waits for a new connection.
+
+-   videocodectestsink: added YUV 4:2:2 support
+
+-   wasapi2src: Add support for process loopback capture
+
+-   wpesrc: Add support for modifiers in key/touch/pointer events
+
+Plugin and library moves
+
+-   The xingmux plugin has been moved from gst-plugins-ugly into
+    gst-plugins-good.
+
+-   The various Windows directshow plugins in gst-plugins-bad have been
+    unified into a single directshow plugin.
+
+Plugin removals
+
+-   The dxgiscreencapsrc element has been removed, use
+    d3d11screencapturesrc instead
+
+Miscellaneous API additions
+
+-   GST_AUDIO_FORMAT_INFO_IS_VALID_RAW() and
+    GST_VIDEO_FORMAT_INFO_IS_VALID_RAW() can be used to check if a
+    GstAudioFormatInfo or GstVideoFormatInfo has been initialised to a
+    valid raw format.
+
+-   Video SEI meta: new GstVideoSEIUserDataUnregisteredMeta to carry
+    H.264 and H.265 metadata from SEI User Data Unregistered messages.
+
+-   vulkan: Expose gst_vulkan_result_to_string()
+
+Miscellaneous performance, latency and memory optimisations
+
+-   liborc 0.4.33 adds support for aarch64 (64-bit ARM) architecture
+    (not enabled by default on Windows yet though) and improvements for
+    32-bit ARM and should greatly enhance performance for certain
+    operations that use ORC.
+
+-   as always there have been plenty of performance, latency and memory
+    optimisations all over the place.
+
+Miscellaneous other changes and enhancements
+
+-   the audio/video decoder base classes will not consider decoding
+    errors a hard error by default anymore but will continue trying to
+    decode. Previously more than 10 consecutive errors were considered a
+    hard error but this caused various partially broken streams to fail.
+    The threshold is configurable via the “max-errors” property.
+
+-   compatibility of the GStreamer PTP clock implementation with
+    different PTP server implementations was improved, and
+    synchronization is achieved successfully in various scenarios that
+    failed before.
+
+Tracing framework and debugging improvements
+
+New tracers
+
+-   buffer-lateness: Records lateness of buffers and the reported
+    latency for each pad in a CSV file. Comes with a script for
+    visualisation.
+
+-   pipeline-snapshot: Creates a .dot file of all pipelines in the
+    application whenever requested via SIGUSR1 (on UNIX systems)
+
+-   queue-levels: Records queue levels for each queue in a CSV file.
+    Comes with a script for visualisation.
+
+Debug logging system improvements
+
+-   new log macros GST_LOG_ID, GST_DEBUG_ID, GST_INFO_ID,
+    GST_WARNING_ID, GST_ERROR_ID, and GST_TRACE_ID allow passing a
+    string identifier instead of a GObject. This makes it easier to log
+    non-gobject-based items and also has performance benefits.
+
+Tools
+
+-   gst-play-1.0 gained a --no-position command line option to suppress
+    position/duration queries, which can be useful to reduce debug log
+    noise.
+
+GStreamer FFMPEG wrapper
+
+-   Fixed bitrate management and timestamp inaccuracies for video
+    encoders
+
+-   Fix synchronization issues and errors created by the (wrong)
+    forwarding of upstream segment events by ffmpeg demuxers.
+
+-   Clipping meta support for gapless mp3 playback
+
+GStreamer RTSP server
+
+-   Add RFC5576 Source-specific media attribute to the SDP media for
+    signalling the CNAME
+
+-   Add support for adjusting request response on pipeline errors
+
+    -   Give the application the possibility to adjust the error code
+        when responding to a request. For that purpose the pipeline’s
+        bus messages are emitted to subscribers through a
+        “handle-message” signal. The subscribers can then check those
+        messages for errors and adjust the response error code by
+        overriding the virtual method
+        GstRTSPClientClass::adjust_error_code().
+
+-   Add gst_rtsp_context_set_token() method to make it possible to set
+    the RTSPToken on some RTSPContext from bindings such as the Python
+    bindings.
+
+-   rtspclientsink gained a “publish-clock-mode” property to configure
+    whether the pipeline clock should be published according to RFC7273
+    (RTP Clock Source Signalling), similar to the same API on
+    GstRTSPMedia.
+
+GStreamer VA-API support
+
+-   Development activity has shifted towards the new va plugin, with
+    gstreamer-vaapi now basically in maintenance-only mode. Most of the
+    below refers to the va plugin (not gstreamer-vaapi).
+
+-   new gst-va library for GStreamer VA-API integration
+
+-   vajpegdec: new JPEG decoder
+
+-   vah264enc, vah265enc: new H.264/H.265 encoders
+
+-   vah264lpenc, vah265lpenc: new low power mode encoders
+
+-   vah265enc: Add extended formats support such as 10/12 bits, 4:2:2
+    and 4:4:4
+
+-   Support encoder reconfiguration
+
+-   vacompositor: Add new compositor element using the VA-API VPP
+    interface
+
+-   vapostproc:
+
+    -   new “scale-method” property
+    -   Process HDR caps if supported
+    -   parse video orientation from tags
+
+-   vaapipostproc: Enable the use of DMA-Buf import and export
+    (gstreamer-vaapi)
+
+GStreamer Video4Linux2 support
+
+-   Added support for Mediatek Stateless CODEC (VP8, H.264, VP9)
+
+-   Stateless H.264 interlaced decoder support
+
+-   Stateless H.265 decoder support
+
+-   Stateful decoder support for driver resolution change events
+
+-   Stateful decoding support fixes for NXP/Amphion driver
+
+-   Support for hardware crop in v4l2src
+
+-   Conformance test improvement for stateful decoders
+
+-   Fixes for Raspberry Pi CODEC
+
+GStreamer OMX
+
+-   There were no changes in this module
+
+GStreamer Editing Services and NLE
+
+-   Handle compositors that are bins around the actual compositor
+    implementation (like glvideomixers which wraps several elements)
+
+-   Add a mode to disable timeline editing API so the user can be in
+    full control of its layout (meaning that the user is responsible for
+    ensuring its validity/coherency)
+
+-   Add a new fade-in transition type
+
+-   Add support for non-1/1 PAR source videos
+
+-   Fix frame accuracy when working with very low framerate streams
+
+GStreamer validate
+
+-   Clean up and stabilize API so we can now generate rust bindings
+
+-   Enhance the appsrc-push action type allowing to find tune the
+    buffers more in details
+
+-   Add an action type to verify currently configured pad caps
+
+-   Add a way to run checks from any thread after executing a ‘wait’
+    action. This is useful when waiting on a signal and want to check
+    the value of a property right when it is emited for example.
+
+GStreamer Python Bindings
+
+-   Add a Gst.init_python() function to be called from plugins which
+    will initialise everything needed for the GStreamer Python bindings
+    but not call Gst.init() again since this will have been called
+    already.
+
+-   Add support for the GstURIHandlerInterface that allows elements to
+    advertise what URI protocols they support.
+
+GStreamer C# Bindings
+
+-   Fix AppSrc and AppSink constructors
+
+-   The C# bindings have yet to be updated to include new 1.22 API,
+    which requires improvements in various places in the bindings /
+    binding generator stack. See issue #1718 in GitLab for more
+    information and to track progress.
+
+GStreamer Rust Bindings and Rust Plugins
+
+The GStreamer Rust bindings are released separately with a different
+release cadence that’s tied to gtk-rs, but the latest release has
+already been updated for the new GStreamer 1.22 API. Check the bindings
+release notes for details of the changes since 0.18, which was released
+around GStreamer 1.20.
+
+gst-plugins-rs, the module containing GStreamer plugins written in Rust,
+has also seen lots of activity with many new elements and plugins. A
+list of all Rust plugins and elements provided with the 0.9 release can
+be found in the repository.
+
+-   33% of GStreamer commits are now in Rust (bindings + plugins), and
+    the Rust plugins module is also where most of the new plugins are
+    added these days.
+
+-   The Rust plugins are now shipped as part of the Windows MSVC + macOS
+    binary packages. See below for the list of shipped plugins and the
+    status of Rust support in cerbero.
+
+-   The Rust plugins are also part of the documentation on the GStreamer
+    website now.
+
+-   Rust plugins can be used from any programming language. To the
+    outside they look just like a plugin written in C or C++.
+
+New Rust plugins and elements
+
+-   rtpav1pay / rtpav1depay: RTP (de)payloader for the AV1 video codec
+-   gtk4paintablesink: a GTK4 video sink that provides a GdkPaintable
+    for rendering a video in any place inside a GTK UI. Supports
+    zero-copy rendering via OpenGL on Linux and macOS.
+-   ndi: source, sink and device provider for NewTek NDI protocol
+-   onvif: Various elements for parsing, RTP (de)payloading, overlaying
+    of ONVIF timed metadata.
+-   livesync: Element for converting a live stream into a continuous
+    stream without gaps and timestamp jumps while preserving live
+    latency requirements.
+-   raptorq: Encoder/decoder elements for the RaptorQ FEC mechanism that
+    can be used for RTP streams (RFC6330).
+
+WebRTC elements
+
+-   webrtcsink: a WebRTC sink (batteries included WebRTC sender with
+    specific signalling)
+-   whipsink: WebRTC HTTP ingest (WHIP) to MediaServer
+-   whepsrc: WebRTC HTTP egress (WHEP) from MediaServer
+-   rtpgccbwe: RTP bandwidth estimator based on the Google Congestion
+    Control algorithm (GCC), used by webrtcsink
+
+Amazon AWS services
+
+-   awss3src / awss3sink: A source and sink element to talk to the
+    Amazon S3 object storage system.
+-   awss3hlssink: A sink element to store HLS streams on Amazon S3.
+-   awstranscriber: an element wrapping the AWS Transcriber service.
+-   awstranscribeparse: an element parsing the packets of the AWS
+    Transcriber service.
+
+Video Effects (videofx)
+
+-   roundedcorners: Element to make the corners of a video rounded via
+    the alpha channel.
+-   colordetect: A pass-through filter able to detect the dominant
+    color(s) on incoming frames, using color-thief.
+-   videocompare: Compare similarity of video frames. The element can
+    use different hashing algorithms like Blockhash, DSSIM, and others.
+
+New MP4 muxer + Fragmented MP4 muxer
+
+-   isofmp4mux, cmafmux, dashmp4mux, onviffmp4mux: New fragmented
+    MP4/ISOBMFF/CMAF muxer for generating e.g. DASH/HLS media fragments.
+-   isomp4mux, onvifmp4mux: New non-fragmented, normal MP4 muxer.
+
+Both plugins provides elements that replace the existing qtmux/mp4mux
+element from gst-plugins-good. While not feature-equivalent yet, the new
+codebase and using separate elements for the fragment and non-fragmented
+case allows for easier extensability in the future.
+
+Cerbero Rust support
+
+-   Starting this release, cerbero has support for building and shipping
+    Rust code on Linux, Windows (MSVC) and macOS. The Windows (MSVC) and
+    macOS binaries also ship the GStreamer Rust plugins in this release.
+    Only dynamic plugins are built and shipped currently.
+
+-   Preliminary support for Android, iOS and Windows (MinGW) exists but
+    more work is needed. Check the tracker issue for more details about
+    future work.
+
+-   The following plugins are included currently: audiofx, aws, cdg,
+    claxon, closedcaption, dav1d, fallbackswitch, ffv1, fmp4, gif,
+    hlssink3, hsv, json, livesync, lewton, mp4, ndi, onvif, rav1e,
+    regex, reqwest, raptorq, png, rtp, textahead, textwrap, threadshare,
+    togglerecord, tracers, uriplaylistbin, videofx, webrtc, webrtchttp.
+
+Build and Dependencies
+
+-   meson 0.62 or newer is required
+
+-   GLib >= 2.62 is now required (but GLib >= 2.64 is strongly
+    recommended)
+
+-   libnice >= 0.1.21 is now required and contains important fixes for
+    GStreamer’s WebRTC stack.
+
+-   liborc >= 0.4.33 is recommended for 64-bit ARM support and 32-bit
+    ARM improvements
+
+-   onnx: OnnxRT >= 1.13.1 is now required
+
+-   openaptx: can now be built against libfreeaptx
+
+-   opencv: allow building against any 4.x version
+
+-   shout: libshout >= 2.4.3 is now required
+
+-   gstreamer-vaapi’s Meson build options have been switched from a
+    custom combo type (yes/no/auto) to the built-in Meson feature type
+    (enabled/disabled/auto)
+
+-   The GStreamer Rust plugins module gst-plugins-rs is now considered
+    an essential part of the GStreamer plugin offering and packagers and
+    distributors are strongly encouraged to package and ship those
+    plugins alongside the existing plugin modules.
+
+-   we now make use of Meson’s install tags feature which allows
+    selective installation of installl components and might be useful
+    for packagers.
+
+Monorepo build (gst-build)
+
+-   new “orc-source” build option to allow build against a
+    system-installed liborc instead of forcing the use of orc as a
+    subproject.
+
+-   GStreamer command line tools can now be linked to the gstreamer-full
+    library if it’s built
+
+Cerbero
+
+Cerbero is a meta build system used to build GStreamer plus dependencies
+on platforms where dependencies are not readily available, such as
+Windows, Android, iOS, and macOS.
+
+General improvements
+
+-   Rust support was added for all support configurations, controlled by
+    the rust variant; see above for more details
+-   All pkgconfig files are now reliably relocatable without requiring
+    pkg-config --define-prefix. This also fixes statically linking with
+    GStreamer plugins using the corresponding pkgconfig files.
+-   New documentation on how to build a custom GStreamer repository
+    using Cerbero, please see the README
+-   HTTPS certificate checking is enabled for downloads on all platforms
+    now
+-   Fetching now automatically retries on error for robustness against
+    transient errors
+-   Support for building the new Qt6 plugin was added
+-   pkgconfig files for various recipes were fixed
+-   Several recipes were updated to newer versions
+-   New plugins: adaptivedemux2 aes codectimestamper dav1d
+-   New libraries: cuda webrtcnice
+
+macOS / iOS
+
+-   Added support for running Cerbero on ARM64 macOS
+-   GStreamer.framework and all libraries in it are now relocatable,
+    which means they use LC_RPATH entries to find dependencies instead
+    of using an absolute path. If you link to GStreamer using the
+    pkgconfig files, no action is necessary. However, if you use the
+    framework directly or link to the libraries inside the framework by
+    hand, then you need to pass -Wl,-rpath,<path_to_libdir> to the
+    linker.
+-   Apple bitcode support was dropped, since Apple has deprecated it
+-   macOS installer now correctly advertises support for both x86_64 and
+    arm64
+-   macOS framework now ships the gst-rtsp-server-1.0 library
+-   Various fixes were made to make static linking to gstreamer
+    libraries and plugins work correctly on macOS
+-   When statically linking to the applemedia plugin using Xcode 13, you
+    will need to pass -fno-objc-msgsend-selector-stubs which works
+    around a backwards-incompatible change in Xcode 14. This is not
+    required for the rest of GStreamer at present, but will be in the
+    future.
+-   macOS installer now shows the GStreamer logo correctly
+
+Windows
+
+-   MSVC is now required by default on Windows, and the Visual Studio
+    variant is enabled by default
+    -   To build with MinGW, use the mingw variant
+-   Visual Studio props files were updated for newer Visual Studio
+    versions
+-   Visual Studio 2015 support was dropped
+-   MSYS2 is now supported as the base instead of MSYS. Please see the
+    README for more details. Some advantages include:
+    -   Faster build times, since parallel make works
+    -   Faster bootstrap, since some tools are provided by MSYS2
+    -   Other speed-ups due to using MSYS2 tools instead of MSYS
+-   Faster download by using powershell instead of hand-rolled Python
+    code
+-   Many recipes were ported from Autotools to Meson, speeding up the
+    build
+-   Universal Windows Platform is no longer supported, and binaries are
+    no longer shipped for it
+-   New documentation on how to force a specific Visual Studio
+    installation in Cerbero, please see the README
+-   New plugins: qsv wavpack directshow amfcodec wic win32ipc
+-   New libraries: d3d11
+
+Windows MSI installer
+
+-   Universal Windows Platform prebuilt binaries are no longer available
+
+Linux
+
+-   Various fixes for RHEL/CentOS 7 support
+-   Added support for running on Linux ARM64
+
+Android
+
+-   Android support now requires Android API version 21 (Lollipop)
+-   Support for Android Gradle plugin 7.2
+
+Platform-specific changes and improvements
+
+Android
+
+-   Android SDK 21 is required now as minimum SDK version
+
+-   androidmedia: Add H.265 / HEVC video encoder mapping
+
+-   Implement JNI_OnLoad() to register static plugins etc. automatically
+    in case GStreamer is loaded from Java using System.loadLibrary(),
+    which is also useful for the gst-full deployment scenario.
+
+Apple macOS and iOS
+
+-   The GLib version shipped with the GStreamer binaries does not
+    initialize an NSApp and does not run a NSRunLoop on the main thread
+    anymore. This was a custom GLib patch and caused it to behave
+    different from the GLib shipped by Homebrew or anybody else.
+
+    The change was originally introduced because various macOS APIs
+    require a NSRunLoop to run on the main thread to function correctly
+    but as this change will never get merged into GLib and it was
+    reverted for 1.22. Applications that relied on this behaviour should
+    move to the new gst_macos_main() function, which also does not
+    require the usage of a GMainLoop.
+
+    See e.g. gst-play.c for an example for the usage of
+    gst_macos_main().
+
+-   GStreamer.framework and all libraries in it are now relocatable,
+    which means they use LC_RPATH entries to find dependencies instead
+    of using an absolute path. If you link to GStreamer using the
+    pkgconfig files, no action is necessary. However, if you use the
+    framework directly or link to the libraries inside the framework by
+    hand, then you need to pass -Wl,-rpath,<path_to_libdir> to the
+    linker.
+
+-   avfvideosrc: Allow specifying crop coordinates during screen capture
+
+-   vtenc, vtdec: H.265 / HEVC video encoding + decoding support
+
+-   osxaudiosrc: Support a device as both input and output
+
+    -   osxaudiodeviceprovider now probes devices more than once to
+        determine if the device can function as both an input AND and
+        output device. Previously, if the device provider detected that
+        a device had any output capabilities, it was treated solely as
+        an Audio/Sink. This caused issues for devices that have both
+        input and output capabilities (for example, USB interfaces for
+        professional audio have both input and output channels). Such
+        devicesare now listed as both an Audio/Sink as well as an
+        Audio/Source.
+
+-   osxaudio: support hidden devices on macOS
+
+    -   These are devices that will not be shown in the macOS UIs and
+        that cannot be retrieved without having the specific UID of the
+        hidden device. There are cases when you might want to have a
+        hidden device, for example when having a virtual speaker that
+        forwards the data to a virtual hidden input device from which
+        you can then grab the audio. The blackhole project supports
+        these hidden devices and this change provides a way that if the
+        device id is a hidden device it will use it instead of checkinf
+        the hardware list of devices to understand if the device is
+        valid.
+
+Windows
+
+-   win32ipcvideosink, win32ipcvideosrc: new shared memory videosrc/sink
+    elements
+
+-   wasapi2: Add support for process loopback capture for a specified
+    PID (requires Windows 11/Windows Server 2022)
+
+-   The Windows universal UWP build is currently non-functional and will
+    need updating after the recent GLib upgrade. It is unclear if anyone
+    is using these binaries, so if you are please make yourself known.
+
+-   wicjpegdec, wicpngdec: Windows Imaging Component (WIC) based JPEG
+    and PNG decoder elements.
+
+-   mfaacdec, mfmp3dec: Windows MediaFoundation AAC and MP3 decoders
+
+-   The uninstalled development environment supports PowerShell 7 now
+
+Linux
+
+-   Improved design for DMA buffer sharing and modifier handling for
+    hardware-accelerated video decoders/encoders/filters and
+    capture/rendering on Linux and Linux-like system.
+
+-   kmssink
+
+    -   new “fd” property which allows an application to provide their
+        own opened DRM device fd handle to kmssink. That way an
+        application can lease multiple fd’s from a DRM master to display
+        on different CRTC outputs at the same time with multiple kmssink
+        instances, for example.
+    -   new “skip-vsync” property to achieve full framerate with legacy
+        emulation in drivers.
+    -   HDR10 infoframe support
+
+-   va plugin and gstreamer-vaapi improvements (see above)
+
+-   waylandsink: Add “rotate-method” property and “render-rectangle”
+    property
+
+-   new gtkwaylandsink element based on gtksink, but similar to
+    waylandsink and uses Wayland APIs directly instead of rendering with
+    Gtk/Cairo primitives. This approach is only compatible with Gtk3,
+    and like gtksink this element only supports Gtk3.
+
+Documentation improvements
+
+-   The GStreamer Rust plugins are now included and documented in the
+    plugin documentation.
+
+Possibly Breaking Changes
+
+-   the Opus audio RTP payloader and depayloader no longer accept the
+    lower case encoding-format=multiopus but instead produce and accept
+    only the upper case variant encoding-format=MULTIOPUS, since those
+    should always be upper case in GStreamer (caps fields are always
+    case sensitive). This should hopefully only affect applications
+    where RTP caps are set manually and multi-channel audio (>= 3
+    channels) is used.
+
+-   wpesrc: the URI handler protocols changed from wpe:// and web:// to
+    web+http://, web+https://, and web+file:// which means URIs are RFC
+    3986 compliant and the source can simply strip the prefix from the
+    protocol.
+
+-   The Windows screen capture element dxgiscreencapsrc has been
+    removed, please use d3d11screencapturesrc instead.
+
+-   On Android the minimum supported Android API version is now version
+    21 and has been increased from 16.
+
+-   On macOS, the GLib version shipped with the GStreamer binaries will
+    no longer initialize an NSApp or run an NSRunLoop on the main
+    thread. See macOS/iOS section above for details.
+
+-   decklink: The decklink plugin is now using the 12.2.2 version of the
+    SDK and will not work with drivers older than version 12.
+
+-   On iOS Apple Bitcode support was removed from the binaries. This
+    feature is deprecated since XCode 14 and not used on the App Store
+    anymore.
+
+-   The MP4/Matroska/WebM muxers now require the “stream-format” to be
+    provided as part of the AV1 caps as only the original “obu-stream”
+    format is supported in these containers and not the “annexb” format.
+
+Known Issues
+
+-   The Windows UWP build in Cerbero needs fixing after the recent GLib
+    upgrade (see above)
+
+-   The C# bindings have not been updated to include new 1.22 API yet
+    (see above)
+
+Statistics
+
+-   4072 commits
+
+-   2224 Merge Requests
+
+-   716 Issues
+
+-   200+ Contributors
+
+-   ~33% of all commits and Merge Requests were in Rust modules
+
+-   4747 files changed
+
+-   469633 lines added
+
+-   209842 lines deleted
+
+-   259791 lines added (net)
+
+Contributors
+
+Ádám Balázs, Adam Doupe, Adrian Fiergolski, Adrian Perez de Castro, Alba
+Mendez, Aleix Conchillo Flaqué, Aleksandr Slobodeniuk, Alicia Boya
+García, Alireza Miryazdi, Andoni Morales Alastruey, Andrew Pritchard,
+Arun Raghavan, A. Wilcox, Bastian Krause, Bastien Nocera, Benjamin
+Gaignard, Bill Hofmann, Bo Elmgreen, Boyuan Zhang, Brad Hards, Branko
+Subasic, Bruce Liang, Bunio FH, byran77, Camilo Celis Guzman, Carlos
+Falgueras García, Carlos Rafael Giani, Célestin Marot, Christian Wick,
+Christopher Obbard, Christoph Reiter, Chris Wiggins, Chun-wei Fan, Colin
+Kinloch, Corentin Damman, Corentin Noël, Damian Hobson-Garcia, Daniel
+Almeida, Daniel Morin, Daniel Stone, Daniels Umanovskis, Danny Smith,
+David Svensson Fors, Devin Anderson, Diogo Goncalves, Dmitry Osipenko,
+Dongil Park, Doug Nazar, Edward Hervey, ekwange, Eli Schwartz, Elliot
+Chen, Enrique Ocaña González, Eric Knapp, Erwann Gouesbet, Evgeny
+Pavlov, Fabian Orccon, Fabrice Fontaine, Fan F He, F. Duncanh, Filip
+Hanes, Florian Zwoch, François Laignel, Fuga Kato, George Kiagiadakis,
+Guillaume Desmottes, Gu Yanjie, Haihao Xiang, Haihua Hu, Havard Graff,
+Heiko Becker, He Junyan, Henry Hoegelow, Hiero32, Hoonhee Lee, Hosang
+Lee, Hou Qi, Hugo Svirak, Ignacio Casal Quinteiro, Ignazio Pillai, Igor
+V. Kovalenko, Jacek Skiba, Jakub Adam, James Cowgill, James Hilliard,
+Jan Alexander Steffens (heftig), Jan Lorenz, Jan Schmidt, Jianhui Dai,
+jinsl00000, Johan Sternerup, Jonas Bonn, Jonas Danielsson, Jordan
+Petridis, Joseph Donofry, Jose Quaresma, Julian Bouzas, Junsoo Park,
+Justin Chadwell, Khem Raj, Krystian Wojtas, László Károlyi, Linus
+Svensson, Loïc Le Page, Ludvig Rappe, Marc Leeman, Marek Olejnik, Marek
+Vasut, Marijn Suijten, Mark Nauwelaerts, Martin Dørum, Martin Reboredo,
+Mart Raudsepp, Mathieu Duponchelle, Matt Crane, Matthew Waters, Matthias
+Clasen, Matthias Fuchs, Mengkejiergeli Ba, MGlolenstine, Michael Gruner,
+Michiel Konstapel, Mikhail Fludkov, Ming Qian, Mingyang Ma, Myles
+Inglis, Nicolas Dufresne, Nirbheek Chauhan, Olivier Crête, Pablo Marcos
+Oltra, Patricia Muscalu, Patrick Griffis, Paweł Stawicki, Peter
+Stensson, Philippe Normand, Philipp Zabel, Pierre Bourré, Piotr
+Brzeziński, Rabindra Harlalka, Rafael Caricio, Rafael Sobral, Rafał
+Dzięgiel, Raul Tambre, Robert Mader, Robert Rosengren, Rodrigo
+Bernardes, Rouven Czerwinski, Ruben Gonzalez, Sam Van Den Berge,
+Sanchayan Maity, Sangchul Lee, Sebastian Dröge, Sebastian Fricke,
+Sebastian Groß, Sebastian Mueller, Sebastian Wick, Sergei Kovalev,
+Seungha Yang, Seungmin Kim, sezanzeb, Sherrill Lin, Shingo Kitagawa,
+Stéphane Cerveau, Talha Khan, Taruntej Kanakamalla, Thibault Saunier,
+Tim Mooney, Tim-Philipp Müller, Tomasz Andrzejak, Tom Schuring, Tong Wu,
+toor, Tristan Matthews, Tulio Beloqui, U. Artie Eoff, Víctor Manuel
+Jáquez Leal, Vincent Cheah Beng Keat, Vivia Nikolaidou, Vivienne
+Watermeier, WANG Xuerui, Wojciech Kapsa, Wonchul Lee, Wu Tong, Xabier
+Rodriguez Calvar, Xavier Claessens, Yatin Mann, Yeongjin Jeong, Zebediah
+Figura, Zhao Zhili, Zhiyuaniu, مهدي شينون (Mehdi Chinoune),
+
+… and many others who have contributed bug reports, translations, sent
+suggestions or helped testing.
+
+Stable 1.22 branch
+
+After the 1.22.0 release there will be several 1.22.x bug-fix releases
+which will contain bug fixes which have been deemed suitable for a
+stable branch, but no new features or intrusive changes will be added to
+a bug-fix release usually. The 1.22.x bug-fix releases will be made from
+the git 1.22 branch, which will be a stable branch.
+
+1.22.0
+
+1.22.0 was originally released on 23 January 2023.
+
+1.22.1
+
+The first 1.22 bug-fix release (1.22.1) was released on 04 March 2023.
+
+This release only contains bugfixes and it should be safe to update from
+1.22.0.
+
+Highlighted bugfixes in 1.22.1
+
+-   audio channel-mix: allow up to 64 channels (instead of up to 63
+    channels)
+-   avfvideosrc: Don’t wait on main thread for permissions request
+-   avvidenc: avoid generating inaccurate output timestamps, especially
+    with variable framerate streams
+-   AV1 video codec caps signalling improvements in various elements
+-   codectimestamper: Fix timestamping on sequence update
+-   d3d11overlaycompositor: fix texture width and height
+-   d3d11videosink: Fix rendering on external handle
+-   dashdemux2: fix seek operation taking a log time to finish for some
+    streams
+-   nvencoder: Fix B-frame encoding on Linux and min buffers in auto GPU
+    mode
+-   playbin3: fixing buffering for live pipelines
+-   playbin: fix potential deadlock when stopping stream with subtitles
+    visible
+-   redenc: fix setting of extension ID for twcc
+-   rtspsrc: improved compatibility with more broken RTSP servers
+-   v4l2h264dec: Fix Raspberry Pi4 will not play video in application
+-   vtdec: fix jittery playback of H.264 Level 4.1 movies in macOS
+-   vtdec: Fix non-deterministic frame output after flushing seeks
+-   vtenc: fix handling of interlaced ProRes on Apple M1 hardware
+-   vtenc: don’t advertise ARGB/RGBA64 input caps on M1 Pro/Max with
+    macOS <13
+-   wasapi2src: Fix loopback capture on Windows 10 Anniversary Update
+-   tools: better handling of non-ASCII command line arguments on
+    Windows
+-   gst-libav: fix build against newer ffmpeg versions
+-   gst-python: Use arch-specific install dir for gi overrides
+-   cerbero: Fix setuptools site.py breakage in Python 3.11
+-   macOS packages: Fix broken binaries on macos < 11.0
+-   various bug fixes, memory leak fixes, and other stability and
+    reliability improvements
+
+gstreamer
+
+-   buffer: fix copy meta reference debug log formatting
+-   bin: Don’t unlock unlocked mutex in gst_bin_remove_func()
+-   pad: Don’t leak user_data in gst_pad_start_task()
+-   aggregator: Always lock aggpad around update_time_level
+-   inputselector: Avoid potential deadlock when shutting down,
+    e.g. playbin with subtitles
+-   multiqueue: Handle use-interleave latency live pipelines, fixing
+    buffering for live pipelines in playbin3
+-   GstBaseSrc: fix transfer annotation for fixate() virtual method
+-   GstBaseSrc, GstPushSrc: add nullable annotations to virtual methods
+-   tools: Make sure UTF-8 encoded command line arguments on Windows
+
+gst-plugins-base
+
+-   alsasink: Fix stall when going from PLAYING to NULL (stucked at
+    PAUSED) with uac1 gadget
+-   appsrc: Don’t chain up BaseSrc::negotiate()
+-   audio: channel-mix: Fix channel count limit to be able to equal 64
+-   gldisplay: Mark gst_gl_display_create_context() other_context
+    parameter as nullable
+-   gldisplay: Remove unused code
+-   gstglwindow_x11.c: Fix colormap leak
+-   gl/cocoa: Return a strong ref to the parent GstGLContext
+-   rtspconnection: Annotate RTSP message and RTSP events parameters
+    correctly
+-   sdp, typefind: Fix some annotations
+-   sdp: gstmikey: gst_mikey_message_to_caps: extract ROC from first
+    crypto session
+-   subparse: Properly forward segment seqnum
+-   uridecodebin: Set source element to READY before querying it
+-   uritranscodebin: Fix unref of NULL
+-   gst-play-1.0: Don’t force accurate seeking
+
+gst-plugins-good
+
+-   adaptivedemux2: Fix buffering threshold initialization
+-   dashdemux2: the seek operation takes a log time to finish for some
+    streams
+-   glvideomixer: Keep a reference to the underlying pad
+-   qtdemux: Don’t emit GstSegment correcting start time when in MSE
+    mode
+-   qtdemux: Handle moov atom length=0 case by reading until the end
+-   qtdemux, qtmux: Drop av1C version 0 parsing and implement version 1
+    parsing/writing
+-   qtmux: Fix assertion on caps update
+-   redenc: fix setting of extension ID for twcc
+-   rtspsrc: Use the correct vfunc for the push-backchannel-sample
+    action signal
+-   rtpssrcdemux: set different stream-id on each src pad
+-   udpsrc: GstSocketTimestampMessage only for SCM_TIMESTAMPNS
+-   v4l2h264dec: Fix Raspberry Pi4 will not play video in application
+
+gst-plugins-bad
+
+-   aom: Include stream-format and alignment in the AV1 caps
+-   av1parser, h265parser: Fix some code defects
+-   av1parser: Don’t consider unknown metadata OBUs a bitstream error
+-   avfvideosrc: Don’t wait on main thread for permissions request
+-   ccconverter: don’t debug a potentially freed filter caps
+-   codectimestamper: Fix timestamping on sequence update
+-   codecparsers: {h264, h265}bitwriter: Remove redundant condition
+    checks
+-   codecs: decoders: fail early if no input caps have been provided for
+    all new decoder base classes
+-   closedcaption: Don’t leak caps event
+-   curlhttpsrc: Add curl anyauth option
+-   d3d11overlaycompositor: fix texture width and height
+-   d3d11videosink: Fix rendering on external handle
+-   h265parse: Always set profile on src caps
+-   msdkav1enc: fix the category for msdkav1enc debug
+-   nvcodec: improve error reporting on plugin init
+-   nvencoder: Fix b-frame encoding on Linux
+-   nvencoder: Fix min buffers parameter of allocation query in auto GPU
+    mode
+-   nvvp9dec: Fix return value
+-   qsvav1enc, amfav1enc: Set stream-format on caps
+-   vtdec: Jittery playback of H.264 Level 4.1 movies in macOS (both
+    x86_64 and arm64)
+-   vtdec: Fix DPB size calculations not taking values from SPS into
+    account
+-   vtdec: Fix not waiting for async frames when flushing
+-   vtenc: Disable ARGB/RGBA64 caps on M1 Pro/Max with macOS <13
+-   vtenc: Fix checking for certain CPU variants when running in VMs
+-   vtenc: Disable HW acceleration for interlaced ProRes
+-   va: Avoid the array index overflow when filling 8x8 scaling list.
+-   va: Fix some code defects
+-   vah265enc: Use helper to update properties.
+-   vulkan: memory: Flush non coherent memory after write.
+-   wasapi2src: Fix loopback capture on Windows 10 Anniversary Update
+-   webrtcbin: small stats improvements
+-   win32ipcutils: Add missing include
+-   wpe: Logging fixes for the WebExtension
+
+gst-plugins-ugly
+
+-   mpegpsdemux: Ignore DTS if PTS < DTS
+
+gst-libav
+
+-   avauddec, avviddec: Free packet side data after usage
+-   avviddec: change
+    AV_CODEC_CAP_AUTO_THREADS->AV_CODEC_CAP_OTHER_THREADS to fix build
+    against newer ffmpeg versions
+-   Memory leak in ’ av_packet_add_side_data’ in
+    /lib/x86_64-linux-gnu/libavcodec.so reading the file
+    clock_odd_size_RLE_g1597902.avi
+-   avvidenc: Don’t take ffmpeg timestamps verbatim but only use them to
+    calculate DTS
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   vaapi: Skip plugin pc file for shared plugins
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   gst-python: Use arch-specific install dir for gi overrides
+
+gst-editing-services
+
+-   No changes
+
+gst-validate + gst-integration-testsuites
+
+-   validate:scenario: sink refs when building
+-   tests: Fix known issue definition location for unit tests and how we
+    handle them in validate launcher
+-   tests: mark elements_srtp.test_play test as flaky
+-   Fix gstreamer-validate-1.0 dependency name
+-   validate-scenario: fix g-i warning in annotation
+-   validate: Fix gst_validate_execute_action annotation
+
+gst-examples
+
+-   webrtc examples: Use webrtc.gstreamer.net
+-   webrtc_sendrecv.py: Various fixes
+
+Development build environment
+
+-   gst-env: Handle installing python modules to dist-packages
+-   meson: Allow sysdeps to be forced as fallback subprojects
+-   meson: Switch dav1d wrap to a tarball and update to dav1d 1.1.0
+
+Cerbero build tool and packaging changes in 1.22.1
+
+-   macos: Fix broken binaries on macos < 11.0
+-   orc: Update pthread_jit_write_protect fix for macOS/iOS
+-   dav1d: Update to 1.1.0
+-   libsrtp: update to v2.5.0
+-   rustup: Update to 1.25.2
+-   rust: Update to 1.67; cargo-c to 0.9.16
+-   cerbero: Don’t error out if bindir already exists
+-   Fix setuptools site.py breakage in Python 3.11, bump
+    gobject-introspection, bump windows image
+-   cerbero: Retry if cargo update fails on macOS
+-   gst-plugins-rs: Build glib/gio bindings with 2.74 API support
+
+Contributors to 1.22.1
+
+Alessandro Bono, Arun Raghavan, Bart Van Severen, Carlos Falgueras
+García, Célestin Marot, David Svensson Fors, Edward Hervey, Enrique
+Ocaña González, Frank Dana, Guillaume Desmottes, He Junyan, James
+Hilliard, Jan Alexander Steffens (heftig), Jan Schmidt, Jordan Petridis,
+Mathieu Duponchelle, Matthew Waters, medithe, Mengkejiergeli Ba, Nicolas
+Beland, Nirbheek Chauhan, Patricia Muscalu, Pawel Stawicki, Philippe
+Normand, Piotr Brzeziński, Rajneesh Soni, Robert Rosengren, Sanchayan
+Maity, Sebastian Dröge, Seungha Yang, Simon Himmelbauer, Thibault
+Saunier, Tim-Philipp Müller, Tristan van Berkom, U. Artie Eoff, Víctor
+Manuel Jáquez Leal, Vivia Nikolaidou, Xuchen Yang, Yinhang Liu,
+
+… and many others who have contributed bug reports, translations, sent
+suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.22.1
+
+-   List of Merge Requests applied in 1.22.1
+-   List of Issues fixed in 1.22.1
+
+1.22.2
+
+The second 1.22 bug-fix release (1.22.2) was released on 11 April 2023.
+
+This release only contains bugfixes and it should be safe to update from
+1.22.x.
+
+Highlighted bugfixes in 1.22.2
+
+-   avdec_h264: fix decoder deadlocks with FFmpeg 6.0
+-   rtspsrc: fix regression with URI protocols in OPTIONS requests for
+    RTSP over TLS
+-   rtspsrc: improved control url handling compatibility for broken
+    servers
+-   decklink: fix 10 bit RGB (r210) format auto detection for capture
+    and fix playout if video caps are configured before audio caps
+-   d3d11videosink: Fix tearing in case of fullscreen mode
+-   playbin: fix deadlock when stopping stream with subtitles visible
+    (even more)
+-   typefinding: fix regression not detecting application/dash+xml in
+    some corner cases
+-   osxvideosink: fix broken aspect ratio and frame drawing region
+-   decodebin3, parsebin: Improve elementary stream handling when
+    decoders are not present and fix hang when removing a failing stream
+-   urisourcebin: Propagate sticky events from parsebin, so that the
+    STREAM_START event with the GstStream info is always available when
+    pads get exposed
+-   v4l2: Add support for YVU420M format; mark JPEG content as parsed
+-   h264decoder, h265decoder: DPB bumping process and latency reporting
+    fixes
+-   Opus: Fix reading of extended channel config in MPEG-TS and fix
+    missing sample rate when remuxing from RTP to Matroska
+-   zxing: add support for building against zxing-c++ 2.0
+-   cerbero: Fix packaging of Rust plugins on Android; fix modern Gentoo
+    distro detection
+-   various bug fixes, memory leak fixes, and other stability and
+    reliability improvements
+
+gstreamer
+
+-   datetime: Return G_MAXFLOAT instead of G_MAXDOUBLE for no timezone
+    offset
+-   inputselector: Wake up streaming thread before PLAYING_TO_PAUSED
+    transition
+-   tools: fix potential crash when passing command-line options on
+    Windows
+
+gst-plugins-base
+
+-   alsasink: Fix for being stuck in stop_streaming_threads state
+-   decodebin3: fix hang when removing a failing stream
+-   gl: wayland: cleanup on close
+-   parsebin: Improve elementary stream handling
+-   playbin: fix deadlock when stopping stream with subtitles visible
+    even more
+-   sdp: Skip source-specific caps fields when creating an SDP media
+    from caps
+-   urisourcebin: Propagate sticky events from parsebin
+-   urisourcebin: Activate pad before transferring sticky events
+-   typefinding: fix failure to recognize application/dash+xml in some
+    cases
+
+gst-plugins-good
+
+-   osxvideosink: fix broken aspect ratio and frame drawing region
+-   qtdemux: Fix seek adjustment with SNAP_AFTER flag
+-   rtpopusdepay, matroskamux: Fix invalid rate while muxing Opus in
+    Matroska
+-   rtpmanager: twcc: Fix duplicate packet handling
+-   rtsp: url: fix incorrect request URI scheme for TLS transport
+    methods (regression)
+-   rtspsrc: Consider “451: Parameter Not Understood” when handling
+    broken control urls
+-   rtspsrc: fix behavior change with URI protocols in OPTIONS requests
+-   rtspsrc: Skip PTs with caps incompatible to the global caps
+-   rtpjpegdepay: fix logic error when checking if an end of image (EOI)
+    tag is present
+-   v4l2: Add support for YVU420M format
+-   v4l2: mark JPEG as parsed
+
+gst-plugins-bad
+
+-   cea708overlay: fix HCR interpretation
+-   d3d11bufferpool: Fix invalid access in debug print loop
+-   d3d11compositor: Fix composition error on release_pad()
+-   d3d11converter: Fix conversion backend selection
+-   d3d11videosink: Fix tearing in case of fullscreen mode -
+    d3d11bufferpool: Fix invalid access in debug print loop
+-   d3d11window: fix memory leak
+-   decklink: fix 10 bit RGB (r210) format auto detection
+-   decklinkaudiosink: Fix playback when video caps is configured before
+    audio
+-   decklinkvideosrc: RGB 4:4:4 doesn’t work after GStreamer upgrade
+    (regression)
+-   decklinkvideosrc: unable to show HDMI stream that Blackmagic’s Media
+    Express is able to see
+-   debugqroverlay: fix string leak
+-   gtkwaylandsink: Destroy GstWlWindow when parent GtkWindow is
+    destroyed
+-   gtkwaylandsink: Fix crash when rendering after the window is closed
+-   ksvideo, directshow: Fix reference leaks in device providers
+-   h264decoder: Fix DPB bumping process
+-   h264decoder, h265decoder: Latency reporting related fixes
+-   h264parse: Validate VUI framerate
+-   jpegparse: reset parse state when the SOI is not the first marker
+-   nvencoder: Fix CQP option setting
+-   nvh264encoder: Fix template caps to include progressive mode as well
+-   openjpegdec: allow multithread decoding only in subframe mode
+-   tsdemux: Fix reading of extended Opus channel configuration
+-   vulkan: fix validation layer issues
+-   vulkanoverlaycompositor: fix potential use after free
+-   vulkanswapper: correctly handle force-aspect-ratio=false
+-   wasapi2: Fix potential crash on device activation failure
+-   webrtc: Fix segfault traversing ice transports
+-   webrtc: patch leak caused by early return
+-   zxing: add support for zxing-c++ 2.0
+
+gst-plugins-ugly
+
+-   No changes
+
+gst-libav
+
+-   avdec_h264 pipeline freeze with FFmpeg6
+-   avdeinterlace, avmux: fix element reference leak
+-   avviddec: Drop decoder stream lock when calling send_packet
+
+gst-rtsp-server
+
+-   rtsp-server: fix deadlock on shutdown with non-live pipeline if
+    media isn’t playing/prerolled yet and eos-shutdown is enabled for
+    the media
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   No changes
+
+gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   git: prevent CRLF line ending conversion for patches to fix pango
+    subproject patching issues on Windows
+
+Cerbero build tool and packaging changes in 1.22.2
+
+-   build: retry rust build on SIGBUS errors too
+-   Fix packaging of rust plugins on Android
+-   Modern Gentoo distro adaptation
+-   sbc: update to 2.0
+-   speex: update to 1.2.1
+
+Contributors to 1.22.2
+
+Adrien De Coninck, Albert Sjölund, Alexande B, Antonio Rojas, Arun
+Raghavan, Bart Van Severen, Carlo Cabrera, Colin Kinloch, Edward Hervey,
+Guillaume Desmottes, Haihua Hu, He Junyan, Ilie Halip, Jordan Petridis,
+Josef Kolář, Lily Foster, Mathieu Duponchelle, Matt Feury, Matthew
+Waters, Maxim P. Dementyev, Michael Tretter, Nicolas Dufresne, Nirbheek
+Chauhan, Piotr Brzeziński, Robert Rosengren, Rouven Czerwinski,
+Sebastian Dröge, Seungha Yang, Shengqi Yu, Stéphane Cerveau, Talha Khan,
+Thibault Saunier, Tim-Philipp Müller, Víctor Manuel Jáquez Leal, Vivia
+Nikolaidou, Wang Chuan, Wojciech Kapsa,
+
+… and many others who have contributed bug reports, translations, sent
+suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.22.2
+
+-   List of Merge Requests applied in 1.22.2
+-   List of Issues fixed in 1.22.2
+
+1.22.3
+
+The third 1.22 bug-fix release (1.22.3) was released on 19 May 2023.
+
+This release only contains bugfixes and it should be safe to update from
+1.22.x.
+
+Highlighted bugfixes in 1.22.3
+
+-   avdec: fix occasional video decoder deadlock on seeking with FFmpeg
+    6.0
+-   decodebin3: fix regression handling input streams without CAPS or
+    TIME segment such as e.g. udpsrc or `pushfilesrc
+-   bluez: a2dpsink: fix Bluetooth SIG Certification test failures
+-   osxvideosink: fix deadlock upon closing output window
+-   qtdemux: fix edit list handling regression and AV1 codec box parsing
+-   qtmux: fix extraction of CEA608 closed caption data from S334-1A
+    packets
+-   rtspsrc: Fix handling of * control path
+-   splitmux: timestamp handling improvements
+-   v4l2videodec: Rework dynamic resolution change handling (needed for
+    IMX6 mainline codec)
+-   videoflip: fix regression with automatically rotating video based on
+    tags
+-   d3d11: many d3d11videosink and d3d11compositor fixes
+-   webrtc, rtp: numerous data race fixes and stability fixes
+-   various bug fixes, memory leak fixes, and other stability and
+    reliability improvements
+
+gstreamer
+
+-   tracing: Initialize tracing infrastructure even if the debug system
+    is not compiled in
+-   parse-launch: fix missing unref of looked-up child element
+-   gstutils: Add category and object to most logging messages
+
+gst-plugins-base
+
+-   allocators: Fix fdmem unit test with recent GLib versions
+-   audiotestsrc: Initialize all samples in wave=ticks mode
+-   decodebin3: Handle input streams without CAPS or TIME segment such
+    as e.g. udpsrc or pushfilesrc
+-   decodebin3: fix regression handling streams without caps
+-   decodebin3: fix random hang when remove failing stream
+-   uridecodebin3: Ensure atomic urisourcebin state change
+-   glvideoflip: fix leaked caps
+-   glcontext_wgl: fix missing unref
+-   playsink: Fix volume leak
+
+gst-plugins-good
+
+-   adaptivedemux2: fix critical when using an unsupported URI
+-   dashdemux2: mpdclient: fix divide by 0 if segment has no duration
+-   imagesequencesrc: Properly set default location
+-   multifile: error out if no filename was set
+-   osxvideosink: fix deadlock upon closing output window
+-   rtpmanager: rtpsession: data race leading to critical warnings
+-   rtpmanager: rtpsession: race conditions leading to critical warnings
+-   rtspsrc: Fix handling of * control path
+-   splitmuxsink: Catch invalid DTS to avoid running into problems later
+-   splitmuxsrc: Make PTS contiguous by preference
+-   qtdemux: emit no-more-pads after pruning old pads
+-   Revert “qtdemux: fix conditions for end of segment in reverse
+    playback” to fix edit list regression
+-   qtdemux: Fix av1C parsing
+-   qtmux: Fix extraction of CEA608 data from S334-1A packets
+-   qtwindow: unref caps in destructor
+-   v4l2: device provider: Fix GMainLoop leak
+-   v4l2: videodec: Rework dynamic resolution change handling
+-   v4l2: videodec: Prefer acquired caps over anything downstream
+-   videoflip: fix setting of method property at construction time
+-   videoflip 1.22.2 not rotating video when extracting frames
+
+gst-plugins-bad
+
+-   a2dpsink: Fails many tests in Bluetooth SIG Certification
+-   avdtputil: Use int instead of int range for fixed bitpool values
+-   ccconverter: reintroduce frame count reset on cycle completion
+-   ccconverter: integer overflow & crashing
+-   codectimestamper: remove PC file generation from plugin’s own
+    meson.build
+-   cudamemory: Fix for semi planar YUV memory size decision
+-   d3d11compositor: Reconfigure resource only when output caps is
+    changed
+-   d3d11compositor: Skip zero alpha input
+-   d3d11convert: Fix for runtime property update
+-   d3d11memory: Don’t clear wrapped texture memory
+-   d3d11videosink: Fix for ignored initial render rectangle
+-   d3d11videosink: fix race condition in window unprepare
+-   d3d11videosink: Enhancement for initial window size decision
+-   d3d11videosink: Don’t clear prepared buffer on unlock_stop()
+-   dashdemux: mpdclient: fix divide by 0 if segment has no duration
+-   dtlstransport: Keep strong ref of dtls encoder/decoder
+-   GstPlay: avoid getting property of playbin2 if subtitle_sid is null
+-   GstPlay: fix critical log when using playbin3
+-   h264decoder: Drop nonexisting picture silently without error
+-   dtmf: element classification improvements
+-   mfvideoenc: Allow only even resolution numbers
+-   sctpenc: Fix potential shutdown deadlock
+-   srtpdec: fix “srtp-key” check
+-   tests: disable dtls test if openssl is not present
+-   tsdemux: Set number of channels to 2 for dual mono Opus
+-   va: Various fixes for defects found with MSVC
+-   wasapi2: Allows process loopback capture on Windows 10
+-   webrtcdatachannel: Bind to parent webrtcbin using a weak reference
+-   webrtcbin: Fix potential deadlock when closing before any data was
+    sent
+-   webrtc: Plug leaks of resolved ICE addresses
+-   webrtc: do not tear down data channel before data is flushed
+
+gst-plugins-ugly
+
+-   mpegpsdemux: Rework gap sending
+
+gst-libav
+
+-   avviddec: Temporarily unlock stream lock while flushing buffers
+-   Random freeze and deadlock in ffmpegviddec flush and get_buffer
+    while seeking
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   ges: base-xml-formatter: Don’t pass non-GObject pointers to
+    GST_DEBUG_OBJECT
+
+gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.22.3
+
+-   glib: Ship Windows process spawning helpers
+-   recipes: add recipe for libltc for timecodestamper element
+-   Add support for RHEL9 and Rocky Linux
+
+Contributors to 1.22.3
+
+Aleksandr Slobodeniuk, Antonio Kevo, Arun Raghavan, Carlos Rafael Giani,
+Daniel Moberg, Edward Hervey, Elliot Chen, François Laignel, Guillaume
+Desmottes, Haihua Hu, Jan Alexander Steffens (heftig), Jan Beich, Jan
+Schmidt, Johan Sternerup, John King, Jordan Petridis, Juan Navarro, Lily
+Foster, Martin Nordholts, Mathieu Duponchelle, Matthew Waters, Matthias
+Fuchs, Michael Olbrich, Mihail Ivanchev, Nick Steel, Nicolas Dufresne,
+Nirbheek Chauhan, Patricia Muscalu, Philippe Normand, Piotr Brzeziński,
+Sanchayan Maity, Sebastian Dröge, Seungha Yang, Stéphane Cerveau,
+Thibault Saunier, Tim-Philipp Müller, Xabier Rodriguez Calvar,
+
+… and many others who have contributed bug reports, translations, sent
+suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.22.3
+
+-   List of Merge Requests applied in 1.22.3
+-   List of Issues fixed in 1.22.3
+
+1.22.4
+
+The fourth 1.22 bug-fix release (1.22.4) was released on 20 June 2023.
+
+This release only contains bugfixes and security fixes and it should be
+safe to update from 1.22.x.
+
+Highlighted bugfixes in 1.22.4
+
+-   Security fixes for flacparse, dvdspu, and subparse
+-   d3d11videosink: Fix error on pause and play
+-   decklink: Correctly handle SDK strings on macOS and free strings
+    after usage on Linux
+-   filesink: Fix buffered mode writing of buffer lists and buffers with
+    multiple memories
+-   gldownload: handle passthrough without a critical
+-   h265parse: Fix framerate handling regression
+-   oggdemux: vp8 fixes
+-   mp4mux, qtmux, qtdemux: Opus audio mapping fixes
+-   pngdec: Fix wrong colours output from 16bit RGB images
+-   ptp clock: Work around ptpd bug in default configuration
+-   srtpdec: fix critical warnings on shutdown
+-   v4l2src: fix support for bayer format
+-   v4l2videoenc: support force-keyframe event in v4l2 encoder
+-   vtenc: apply DTS offset to ensure DTS <= PTS
+-   gst-python: allow more functions to be called before gst_init()
+-   cerbero: fix vaapi variant; add qt6 build on windows; ensure errors
+    on unguarded use of new APIs, require macOS 10.13
+-   packages: ship codecalpha, rtponvif, dvbsubenc, switchbin,
+    videosignal plugins; fix pango crash on 32-bit windows
+-   various bug fixes, memory leak fixes, and other stability and
+    reliability improvements
+
+gstreamer
+
+-   filesink: Fix buffered mode writing of buffer lists and buffers with
+    multiple memories
+-   basesink: Clear EOS flag on STREAM-START event
+-   typefindhelper: downgrade bogus error level debug log message
+-   ptp: Correctly parse clock ID from the commandline parameters in the
+    helper
+-   ptp: Work around bug in ptpd in default configuration
+
+gst-plugins-base
+
+-   alsasink: Fix stall for transition from PAUSED to READY with USB
+    speakerphone.
+-   appsink: unref buffer in prev sample early so buffers from v4l2 can
+    be released properly
+-   basetextoverlay: Fix typo in “text-y” property description
+-   gldownload: handle passthrough without a critical
+-   glfilter: add parent meta to output buffer for input buffer
+-   oggdemux: vp8: Push headers downstream and detect keyframe packets
+-   opus: Fix potential crash when getting unexpected channel position
+-   streamsynchronizer: reset eos on STREAM_START
+-   subparse: Look for the closing > of a tag after the opening <
+-   video: convertframe: Add D3D11 specific conversion path
+-   videometa: Only validate the alignment only when it contains some
+    info
+-   video-blend: Fix linking error with C++
+
+gst-plugins-good
+
+-   flacparse: Avoid integer overflow in available data check for image
+    tags
+-   flvmux: use the correct timestamp to calculate wait times
+-   isomp4: Fix (E)AC-3 channel count handling
+-   jpegdec: fixes related to interlaced jpeg
+-   pngdec: Fix wrong colours output from 16bit RGB images
+-   qtmux, qtdemux: fix byte order for opus extension
+-   rtspsrc: Do not try send dropped get/set parameter
+-   qt5, qt6: Add more meson options and eliminate all automagic
+-   qt: glrenderer: don’t attempt to use QWindow from non-Qt main thread
+-   qml6glsink: Support building on win32
+-   v4l2src: fix support for bayer format
+-   v4l2: Change to query only up to
+    V4L2_CID_PRIVATE_BASE+V4L2_CID_MAX_CTRLS
+-   v4l2videodec: treat MPEG-1 format as MPEG-2
+-   v4l2videoenc: support force keyframe event in v4l2 encoder
+-   tests: rtpbin_buffer_list: fix possible unaligned write/read on
+    32-bit ARM
+
+gst-plugins-bad
+
+-   asfmux: fix possible unaligned write on 32-bit ARM
+-   d3d11videosink: Fix error on pause and play
+-   d3dvideosink: Fix navigation event leak
+-   decklink: Correctly handle SDK strings on macOS and free strings
+    after usage on Linux
+-   dvdspu: Make sure enough data is allocated for the available data
+-   fdkaacdec: Support up to 5 rear channels
+-   h265parse: Fix framerate handling
+-   kmssink: Add STM32 LTDC and NXP i.MX8M Plus LCDIFv3 auto-detection
+-   sdpdemux: ensure that only one srcpad is created per stream
+-   srtpdec: fix critical warnings on shutdown
+-   testsrcbin: Remove spurious caps unref
+-   va: map the mbbrc to correct enum value in get_property()
+-   vtenc: apply DTS offset to ensure DTS <= PTS
+-   vtdec: time glitches on h264 playback
+-   waylandsink: Emit “map” signal boarder surface is ready
+
+gst-plugins-ugly
+
+-   No changes
+
+gst-libav
+
+-   No changes
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   vaapidecodebin: don’t load vaapipostproc if not available
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   python: More functions can be called before gst_init()
+
+gst-editing-services
+
+-   ges: launcher: Never put sinks in a GstPipeline
+
+gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.22.4
+
+-   Ship codecalpha, rtponvif, dvbsubenc, switchbin, videosignal plugins
+-   pango: Fix crash on Windows 32bit build
+-   qml6: Add support for building the qml6 plugin on Windows and bump
+    meson to 1.1.1
+-   vaapi: update vaapi variant/recipe for meson option changes
+-   packages: Put libass in the same category as assrender
+-   cerbero: Don’t extract if already extracted in fetch
+-   darwin: Ensure errors on unguarded use of new APIs, require macOS
+    10.13
+
+Contributors to 1.22.4
+
+Andoni Morales Alastruey, Arun Raghavan, Colin Kinloch, Daniel Morin,
+Edward Hervey, ekwange, Elliot Chen, François Laignel, Guillaume
+Desmottes, Haihua Hu, He Junyan, Hou Qi, Jan Alexander Steffens
+(heftig), Jochen Henneberg, Jordan Petridis, Kevin Song, Maksym
+Khomenko, Marek Vasut, Mathieu Duponchelle, Matthew Waters,
+Mengkejiergeli Ba, Michael Olbrich, Nicolas Beland, Nicolas Dufresne,
+Nirbheek Chauhan, Philippe Normand, Piotr Brzeziński, Sebastian Dröge,
+Seungha Yang, Thibault Saunier, Tim-Philipp Müller, Víctor Manuel Jáquez
+Leal, William Manley, Xavier Claessens, Yuri Fedoseev,
+
+… and many others who have contributed bug reports, translations, sent
+suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.22.4
+
+-   List of Merge Requests applied in 1.22.4
+-   List of Issues fixed in 1.22.4
+
+1.22.5
+
+The fifth 1.22 bug-fix release (1.22.5) was released on 20 July 2023.
+
+This release only contains bugfixes and security fixes and it should be
+safe to update from 1.22.x.
+
+Highlighted bugfixes in 1.22.5
+
+-   Security fixes for the RealMedia demuxer
+-   vaapi decoders, postproc: Disable DMAbuf from caps negotiation to
+    fix garbled video in some cases
+-   decodebin3, playbin3, parsebin fixes, especially for stream
+    reconfiguration
+-   hlsdemux2: fix early seeking; don’t pass referer when updating
+    playlists; webvtt fixes
+-   gtk: Fix critical caused by pointer movement when stream is getting
+    ready
+-   qt6: Set sampler filtering method, fixes bad quality with qml6glsink
+    and gstqt6d3d11
+-   v4l2src: handle resolution change when buffers are copied
+-   videoflip: update orientation tag in auto mode
+-   video timecode: Add support for framerates lower than 1fps and
+    accept 119.88 (120/1.001) fps
+-   webrtcsink: fixes for x264enc and NVIDIA encoders
+-   cerbero: Pull ninja from system if possible, avoid spurious
+    bootstrap of cmake
+-   packages: Recipe updates for ffmpeg, libsoup, orc
+-   various bug fixes, memory leak fixes, and other stability and
+    reliability improvements
+
+gstreamer
+
+-   taglist, plugins: fix compiler warnings with GLib >= 2.76
+-   tracerutils: allow casting parameter types
+-   inputselector: fix playing variable is never set
+
+gst-plugins-base
+
+-   appsink: add missing make_writable call
+-   audioaggregator: Do not post message before being constructed
+-   decodebin3: Prevent a critical warning when reassigning output slots
+-   decodebin3: Fix slot input linking when the associated stream has
+    changed
+-   decodebin3: Remove spurious input locking during parsebin
+    reconfiguration
+-   urisourcebin: Set source element to READY before querying it
+-   gl/viv-fb: meson build updates
+-   plugins: fix compiler warnings with GLib >= 2.76
+-   subtitleoverlay: fix mutex error if sink caps is not video
+-   video: timecode: Add support for framerates lower than 1fps
+-   video: accept timecode of 119.88 (120/1.001) FPS
+-   video: cannot attach time code meta when frame rate is 119.88
+    (120000/1001)
+-   videodecoder: fix copying buffer metas
+
+gst-plugins-good
+
+-   adaptivedemux2: Fix early seeking
+-   hlsdemux2: Ensure processed webvtt ends with empty new line
+-   hlsdemux2: Don’t set a referer when updating playlists
+-   matroska: demux: Strip signal byte when encrypted
+-   rtspsrc: Fix crash when is-live=false
+-   gtk: Fix critical caused by pointer movement when stream is getting
+    ready
+-   qt6: Set sampler filtering method, fixes bad quality with qml6glsink
+    and gstqt6d3d11
+-   qtdemux: opus: set entry as sampled
+-   v4l2src: handle resolution change when buffers are copied
+-   v4l2videodec: Fix handling of initial gaps
+-   v4l2videodec: correctly register v4l2mpeg2dec
+-   v4l2videoenc: replace custom QUERY_CAPS handling with getcaps
+    callback
+-   videoflip: update orientation tag in auto mode
+-   videoflip: fix critical when tag list is not writable
+
+gst-plugins-bad
+
+-   d3d11bufferpool: Fix heavy CPU usage in case of fixed-size pool
+-   jpegparser: jpegdecoder: Don’t pollute bus and comply with spec
+-   plugins: fix compiler warnings with GLib >= 2.76
+-   webrtcbin: Prevent critical warning when creating an additional data
+    channel
+-   webrtcstats: Properly report IceCandidate type
+
+gst-plugins-ugly
+
+-   rmdemux: add some integer overflow checks
+
+gst-plugins-rs
+
+-   fallbackswitch: Change the threshold for trailing buffers
+-   fallbackswitch: Fix pad health calculation and notifies
+-   fmp4mux: Fix draining in chunk mode if keyframes are too late
+-   livesync: Wait for the end timestamp of the previous buffer before
+    looking at queue
+-   livesync: Improve EOS handling
+-   togglerecord: Clip segment before calculating timestamp/duration
+-   togglerecord: Error out if main stream buffer has no valid running
+    time
+-   webrtcsink: fix pipeline when input caps contain max-framerate
+-   webrtcsink: Configure only 4 threads for x264enc
+-   webrtcsink: Translate force-keyunit events to force-IDR action
+    signal for NVIDIA encoders
+-   webrtcsink: Set config-interval=-1 and aggregate-mode=zero-latency
+    on rtph264pay and rtph265pay
+-   webrtcsink: Set VP8/VP9 payloader based on payloader element factory
+    name
+-   webrtcink: Use correct property types for nvvideoconvert
+-   webrtc/signalling: fix race condition in message ordering
+-   videofx: Minimize dependencies of the image crate
+
+gst-libav
+
+-   No changes
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   vaapidecode,vaapipostproc: Disable DMAbuf from caps negotiation.
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   ges: some fixes for 32-bit systems
+-   ges, nle: Avoid setting state or sending query when constructing
+    objects
+
+gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.22.5
+
+-   Pull ninja from system if possible, avoid spurious bootstrap of
+    cmake
+-   ffmpeg: update to 5.0.3
+-   libsoup: update to 2.74.3
+-   orc: update to 0.4.34
+
+Contributors to 1.22.5
+
+Andoni Morales Alastruey, Bastien Nocera, Carlos Rafael Giani, David
+Craven, Doug Nazar, Edward Hervey, François Laignel, Guillaume
+Desmottes, He Junyan, Hou Qi, Jan Alexander Steffens (heftig), Jan
+Schmidt, Maksym Khomenko, Mathieu Duponchelle, Matthew Waters, Michael
+Olbrich, Michael Tretter, Nicolas Dufresne, Nirbheek Chauhan, Philippe
+Normand, Ruslan Khamidullin, Sebastian Dröge, Seungha Yang, Théo
+Maillart, Thibault Saunier, Tim-Philipp Müller, Víctor Manuel Jáquez
+Leal, Vivia Nikolaidou, Yatin Maan,
+
+… and many others who have contributed bug reports, translations, sent
+suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.22.5
+
+-   List of Merge Requests applied in 1.22.5
+-   List of Issues fixed in 1.22.5
+
+1.22.6
+
+The sixth 1.22 bug-fix release (1.22.6) was released on 20 September
+2023.
+
+This release only contains bugfixes and security fixes and it should be
+safe to update from 1.22.x.
+
+Highlighted bugfixes in 1.22.6
+
+-   Security fixes for the MXF demuxer and H.265 video parser
+-   Fix latency regression in H.264 hardware decoder base class
+-   androidmedia: fix HEVC codec profile registration and fix coded_data
+    handling
+-   decodebin3: fix switching from a raw stream to an encoded stream
+-   gst-inspect: prettier and more correct signal and action signals
+    printing
+-   rtmp2: Allow NULL flash version, omitting the field, for better RTMP
+    server compatibility
+-   rtspsrc: better compatibility with buggy RTSP servers that don’t set
+    a clock-rate
+-   rtpjitterbuffer: fix integer overflow that led to more packets being
+    declared lost than have been lost
+-   v4l2: fix video encoding regression on RPi and fix support for left
+    and top padding
+-   waylandsink: Crop surfaces to their display width height
+-   cerbero: recognise Manjaro; add Rust support for MSVC ARM64; cmake
+    detection fixes
+-   various bug fixes, build fixes, memory leak fixes, and other
+    stability and reliability improvements
+
+gstreamer
+
+-   gst-inspect: prettier and more correct signal printing, and print
+    action signals in g_signal_emit_by_name() format
+-   gst-launch: Disable fault signal handlers on macOS
+
+gst-plugins-base
+
+-   audio: Make sure to stop ringbuffer on error
+-   decodebin3: avoid identity, sinkpad, parsebin leakage when reset
+    input
+-   decodebin3: Ensure the slot is unlinked before linking to decoder
+-   sdp: fix wrong debug log error message for missing clock-rate in
+    caps
+-   sdp: Parse zero clock-rate as default
+
+gst-plugins-good
+
+-   adaptivedemux2: fix memory leak
+-   pulsedeviceprovider: fix incorrect usage of GST_ELEMENT_ERROR
+-   qt: Unbreak build with qt-egl enabled but viv_fb missing
+-   qt: Fix searching of qt5/qt6 tools with qmake in Meson
+-   qtdemux: Fix premature EOS when some files are played in push mode
+-   qtdemux: attach cbcs crypt info at the right moment
+-   rtpjitterbuffer: Avoid integer overflow in max saveable packets
+    calculation with negative offset
+-   videoflip: fix concurrent access when modifying the tag list
+-   v4l2: allocator: Don’t close foreign dmabuf
+-   v4l2: bufferpool: Fix large encoded stream regression
+-   v4l2: bufferpool: Problems when checking for truncated buffer
+-   v4l2: Fix support for left and top padding
+-   v4l2object: clear format lists if source change event is received
+
+gst-plugins-bad
+
+-   androidmedia/enc: handle codec-data before popping
+    GstVideoCodecFrames
+-   androidmedia: fix hevc codec profile registration
+-   androidmedia: Small fixes
+-   androidmedia: Add more null checks (of env) to JNI utilities
+-   applemedia: Fix pixel format for I420 and NV12
+-   audiolatency: Forward latency query and event upstream
+-   av1parser: Fix segmentation params update
+-   codecparsers: Fix MPEG-1 aspect ratio table
+-   d3d11convert: Passthrough allocation query on same caps
+-   h264decoder: Update latency dynamically
+-   h265parser: Allow partially broken hvcC data
+-   h265parser: Fix possible overflow using max_sub_layers_minus1
+-   hlssink2: Always use forward slash separator
+-   mdns: Fix a crash on context error
+-   mxfdemux: Fix integer overflow causing out of bounds writes when
+    handling invalid uncompressed video and check channels for AES3
+-   nvencoder: Fix negotiation error when interlace-mode is unspecified
+-   rtmp2: Allow NULL flash version, omitting the field
+-   rtmp2sink: fix crash if message conversion failed
+-   transcodebin: Fixes for upstream selectable support
+-   va: Fix in error logs functions mismatches
+-   waylandsink: Crop surfaces to their display width height
+-   waylandsink: Fix cropping for video with non-square aspect ratio
+-   webrtc: Fix docs for create-data-channel action signal
+-   win32ipc: Fix pipe handle leak
+
+gst-plugins-ugly
+
+-   No changes
+
+gst-plugins-rs
+
+-   fallbackswitch: locking/deadlock fixes
+-   onvifmetadataparse: Skip metadata frames with unrepresentable UTC
+    time
+-   transcriberbin: Configure audioresample in front of transcriber
+-   webrtcsink: Propagate GstContext messages
+-   webrtcsink: Add support for d3d11 memory and qsvh264enc
+-   webrtcsink: fix TWCC extension adding
+-   webrtcsink: don’t forget to setup encoders for discoveries
+-   webrtcsink: NVIDIA V4L2 encoders always require NVMM memory
+-   meson: Fix handling of optional deps, and don’t require Python 3.8
+
+gst-libav
+
+-   No changes
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   No changes
+
+gst-validate + gst-integration-testsuites
+
+-   gst-validate: Disable fault signal handlers on macOS
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   macos-bison: Update to 3.8.2 and add an ARM64 build
+-   wrap: update libpsl to 0.21.2
+
+Cerbero build tool and packaging changes in 1.22.6
+
+-   Add Rust support for MSVC ARM64
+-   Recognise PERL5LIB as a joinable Unix variable
+-   Recognise Manjaro as an Arch derivative
+-   Fix picking up cmake from build-tools
+
+Contributors to 1.22.6
+
+Akihiro Sagawa, Alicia Boya García, Guillaume Desmottes, Haihua Hu,
+Hugues Fruchet, Ivan Molodetskikh, Jan Alexander Steffens (heftig), Jan
+Schmidt, L. E. Segovia, Mathieu Duponchelle, Matthew Waters, Ming Qian,
+Nicolas Dufresne, Nirbheek Chauhan, Olivier Blin, Olivier Crête,
+Philippe Normand, Piotr Brzeziński, Robert Ayrapetyan, Ryan Pavlik,
+Sebastian Dröge, Seungha Yang, Stéphane Cerveau, Stephan Seitz, Thomas
+Schneider, Tim-Philipp Müller, Víctor Manuel Jáquez Leal, Wang Chuan,
+Xabier Rodriguez Calvar,
+
+… and many others who have contributed bug reports, translations, sent
+suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.22.6
+
+-   List of Merge Requests applied in 1.22.6
+-   List of Issues fixed in 1.22.6
+
+1.22.7
+
+The seventh 1.22 bug-fix release (1.22.7) was released on 13 November
+2023.
+
+This release only contains bugfixes and security fixes and it should be
+safe to update from 1.22.x.
+
+Highlighted bugfixes in 1.22.7
+
+-   Security fixes for the MXF demuxer and AV1 codec parser
+-   glfilter: Memory leak fix for OpenGL filter elements
+-   d3d11videosink: Fix toggling between fullscreen and maximized, and
+    window switching in fullscreen mode
+-   DASH / HLS adaptive streaming fixes
+-   Decklink card device provider device name string handling fixes
+-   interaudiosrc: handle non-interleaved audio properly
+-   openh264: Fail gracefully if openh264 encoder/decoder creation fails
+-   rtspsrc: improved whitespace handling in response headers by certain
+    cameras
+-   v4l2codecs: avoid wrap-around after 1000000 frames; tiled formats
+    handling fixes
+-   video-scaler, audio-resampler: downgraded “Can’t find exact taps”
+    debug log messages
+-   wasapi2: Don’t use global volume control object
+-   Rust plugins: various improvements in aws, fmp4mux, hlssink3,
+    livesync, ndisrc, rtpav1depay, rsfilesink, s3sink, sccparse
+-   WebRTC: various webrtchttp, webrtcsrc, and webrtcsink improvements
+    and fixes
+-   Cerbero build tools: recognise Windows 11; restrict parallelism of
+    gst-plugins-rs build on small systems
+-   Packages: ca-certificates update; fix gio module loading and TLS
+    support on macOS
+
+gstreamer
+
+-   debugutils: provide gst_debug_bin_to_dot_data() implementation even
+    if debug system is disabled
+
+gst-plugins-base
+
+-   audioaggregator, audiomixer: Make access to the pad list thread-safe
+    while mixing
+-   basetextoverlay: Fix overlay never rendering again if width reaches
+    1px
+-   glfiter: Protect GstGLContext access
+-   glfilter: Only add parent meta if inbuf != outbuf
+-   macOS: fix huge memory leak with glfilter-based elements
+-   rtspconnection: Ignore trailing whitespace in rtsp headers
+-   video-scaler, audio-resampler: downgrade ‘can’t find exact taps’ to
+    debug
+
+gst-plugins-good
+
+-   adaptivedemux2: Do not submit_transfer when cancelled
+-   adaptivedemux2: Call GTasks’s return functions for blocking tasks
+-   flacenc: Correctly handle up to 255 cue entries
+-   flvmux: set the src segment position as running time
+-   imagesequencesrc: fix deadlock when feeding the same image in a loop
+-   pngenc: output one frame only in snapshot mode and mark output
+    frames as I-frames
+-   qmlglsrc: sync on the streaming thread
+-   souphttpsrc: Chain up to finalize to fix memory leak
+-   wavparse: fix buffer leak with adtl tag
+-   v4l2codecs: Avoid QBUF/DQBUF struct timeval .tv_usec wrap-around at
+    frame 1000000
+-   v4l2codecs: Fix tiled formats stride conversion
+
+gst-plugins-bad
+
+-   audiobuffersplit: disable max-silence-time if set to 0
+-   libde265: Do not decode the non 4:2:0 8 bits format
+-   codecparsers: av1: Clip max tile rows and cols values
+-   codecs: h265: Do not free slice header before using it
+-   d3d11converter: Fix 10/12bits planar output
+-   d3d11decoder: Fix crash on negotiate() when decoder is not
+    configured
+-   d3d11videosink: Fix toggling between fullscreen and maximized
+-   d3d11videosink: Fix window switching in case of fullscreen mode
+-   d3d11screencapturesrc: Fix mouse cursor blending
+-   decklink: Fix broken COM string conversion
+-   decklink: Decklink Device Provider wrongly parses SDK strings
+-   gstwayland: Don’t depend on wayland-protocols
+-   interaudiosrc: Add audio meta to buffers containing non-interleaved
+    samples
+-   kmssink: Add TIDSS auto-detection
+-   mfvideoencoder: Fix typo in template caps
+-   mxfdemux: Store GstMXFDemuxEssenceTrack in their own fixed
+    allocation
+-   nvcodec: fix bounds for auto-select GPU enumeration
+-   openh264: Fail gracefully if openh264 encoder/decoder creation fails
+-   tsmux: More cleanups
+-   tsmux: Fill padding packets with stuffing bytes
+-   v4l2codecs: Fix tiled formats stride conversion
+-   v4l2videodec: Correctly free caps to avoid memory leak
+-   wasapi2: Don’t use global volume control object
+-   wasapi2device: Ignore activation failed device
+
+gst-plugins-ugly
+
+-   No changes
+
+gst-plugins-rs
+
+-   aws: s3sink: Fix handling of special characters in key
+-   aws: s3: Properly percent-decode GstS3Url
+-   fmp4mux: Don’t overflow negative composition offset calculation
+-   fmp4mux: specify the fragment duration unit
+-   hlssink3: Use Path API for getting file name
+-   hlssink3: Use sprintf for segment name formatting
+-   hlssink3: Remove unused deps
+-   hlssink3: Don’t remove old files if max-files is zero
+-   hlssink3: Don’t remove uri from playlist if playlist-length is zero
+-   hlssink3: Various cleanup
+-   livesync: log new pending segments
+-   livesync: display jitter when waiting on clock
+-   livesync: Rename activatemode methods to *_activatemode
+-   livesync: Simplify start_src_task and src_loop
+-   livesync: Improve audio duration fixups
+-   livesync: Log a category error when we are missing the segment
+-   livesync: Clean up state handling
+-   livesync: Replace an if-let with match
+-   livesync: Move a notify closer to the interesting state change
+-   livesync: Move num_in counting to the src task
+-   livesync: Simplify num_duplicate counting
+-   livesync: Handle flags and late buffer patching after queueing
+-   livesync: Separate out_buffer duplicate status from GAP flag
+-   livesync: Use fallback_duration for audio repeat buffers as well
+-   livesync: example: Add identities single-segment=1
+-   livesync: Split fallback_duration into in_ and out_duration
+-   livesync: Keep existing buffer duration in some cases
+-   livesync: Remove the stop from outgoing segments
+-   ndisrc: Assume input with more than 8 raw audio channels is
+    unpositioned
+-   rtpav1depay: Skip unexpected leading fragments
+-   rtpav1depay: Don’t push stale temporal delimiters downstream
+-   rsfilesink: set sync=false
+-   s3sink: set sync=false
+-   sccparse: Fix leading spaces between the tab and caption data
+-   webrtchttp: Respect HTTP redirects
+-   webrtcsrc: use @watch instead of @to-owned
+-   webrtcsrc: add turn-servers property
+-   webrtc: Fix paths in README
+-   webrtcsink: don’t miss ice candidates
+
+gst-libav
+
+-   No changes
+
+gst-rtsp-server
+
+-   rtspclientsink: Don’t leak previous server_ip
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   No changes
+
+gst-validate + gst-integration-testsuites
+
+-   gst-validate: Fix compatibility with Python 3.12
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.22.7
+
+-   Add Windows 11 to the supported versions list
+-   ca-certificates: Update to version from 2023-08-22
+-   cargo: Restrict parallelism if a small system is detected (for
+    gst-plugins-rs build)
+-   Fix venv setup on Python 3.11+
+-   Fix unlinking of Android NDK directories if install fails midway
+-   glib: Work around AppleClang + -Werror test build failure
+-   glib: Re-add gio module loading patch for macOS, remove unused patch
+    files
+
+Contributors to 1.22.7
+
+Albert Sjölund, Arun Raghavan, Balló György, Benjamin Gaignard, Detlev
+Casanova, Doug Nazar, Eric, Florian Zwoch, François Laignel, Guillaume
+Desmottes, He Junyan, Hou Qi, James Oliver, Jan Alexander Steffens
+(heftig), Jan Schmidt, Johan Adam Nilsson, Jordan Yelloz, Kalev Lember,
+L. E. Segovia, Lieven Paulissen, Maksym Khomenko, Marek Vasut, Matthias
+Fuchs, Michiel Westerbeek, Nicolas Dufresne, Philippe Normand, Piotr
+Brzeziński, Rahul T R, Sean DuBois, Sebastian Dröge, Seungha Yang,
+Stéphane Cerveau, Thibault Saunier, Tim-Philipp Müller,
+
+… and many others who have contributed bug reports, translations, sent
+suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.22.7
+
+-   List of Merge Requests applied in 1.22.7
+-   List of Issues fixed in 1.22.7
+
+1.22.8
+
+The eight 1.22 bug-fix release (1.22.8) was released on 18 December
+2023.
+
+This release only contains bugfixes and security fixes and it should be
+safe to update from 1.22.x.
+
+Highlighted bugfixes in 1.22.8
+
+-   Security fixes for the AV1 video codec parser
+-   avdec video decoder: fix another possible deadlock with FFmpeg 6.1
+-   qtdemux: reverse playback and seeking fixes for files with raw audio
+    streams
+-   v4l2: fix “newly allocated buffer … is not free” warning log flood
+-   GstPlay + GstPlayer library fixes
+-   dtls: Fix build failure on Windows when compiling against OpenSSL
+    3.2.0
+-   d3d11screencapturesrc: Fix wrong color with HDR enabled
+-   Cerbero build tool: More python 3.12 string escape warning fixes;
+    make sure to bundle build tools as well
+-   various bug fixes, build fixes, memory leak fixes, and other
+    stability and reliability improvements
+
+gstreamer
+
+-   buffer: Unref memories before metas
+-   pad: Recheck pads when linking after temporary unlock
+-   baseparse: Fixes to buffers extracted from adapter
+
+gst-plugins-base
+
+-   appsrc: Fix flow return when buffer is dropped
+-   audioringbuffer: Don’t try to map MONO channel
+-   encoding-target: Properly free when missing type field in
+    parse_encoding_profile
+-   pbutils: Don’t include default vp9 parameters in resulting codec
+    mime string
+-   videorate: Don’t forget last_ts on caps changes
+
+gst-plugins-good
+
+-   dcaparse: keep upstream buffer meta
+-   rtpklvdepay: Recover after invalid fragmented KLV unit
+-   matroska-demux: fix accumulated base offset in segment seeks
+-   qtdemux: fix bug report URL
+-   qtdemux: Don’t overflow sample index
+-   qtdemux: Fix reverse playback for pcm audio stream
+-   qtdemux: Ignore raw audio streams when adjusting seek
+-   qtdemux: Under-seeking to a key unit in certain (encoded by Adobe
+    products) ProRes movies (macOS x86_64 & arm64, Windows x86_64, …)
+-   rtpac3depay: should output audio/x-ac3 not audio/ac3
+-   rtp: Fix incorrect RTP channel order lookup by name
+-   v4l2bufferpool: add lock as atomic operation for seek
+
+gst-plugins-bad
+
+-   aesenc: Fix IV length addition to output buffer length
+-   av1parser: Fix array sizes in scalability structure
+-   camerabin: Fix source updates with user filters
+-   codecparsers: av1: Clip max tile rows and cols values
+-   dtlscertificate: Define WINSOCKAPI before including windows.h
+-   d3d11: fix building with address sanitizer
+-   d3d11screencapturesrc: Fix wrong color with HDR enabled
+-   h264decoder: Fix GstVideoCodecFrame leak
+-   ladspa: Make RDF parsing truly optional
+-   rtponviftimestamp: Fix drop-out-of-segment=false mode
+-   qsvdecoder: Fix stream format detection
+-   webrtcsdp: Remove fingerprint validation that doesn’t make sense
+-   GstPlay: Automatically flush the bus when disposing the signal
+    adapter
+-   GstPlayer: Without dispatcher emit signals directly instead of via
+    the default main context
+
+gst-plugins-ugly
+
+-   No changes
+
+gst-plugins-rs
+
+-   threadshare: Fix a deadlock in used-socket notification
+-   threadshare: Fix a typo while logging
+-   webrtcsink: don’t panic on failure to request pad from webrtcbin
+-   ndi: Remove wrong Clone impl on RecvInstance
+-   ndi: Don’t mark private type as public
+-   fallbacksrc: Fix timeout scheduling
+
+gst-libav
+
+-   avviddec: Unlock stream lock while waiting for decoded frame. Fixes
+    potential deadlock
+-   avviddec: Calculate latency only for fixed framerate
+
+gst-rtsp-server
+
+-   No changes
+
+gstreamer-vaapi
+
+-   No changes
+
+gstreamer-sharp
+
+-   No changes
+
+gst-omx
+
+-   No changes
+
+gst-python
+
+-   No changes
+
+gst-editing-services
+
+-   No changes
+
+gst-validate + gst-integration-testsuites
+
+-   No changes
+
+gst-examples
+
+-   No changes
+
+Development build environment
+
+-   No changes
+
+Cerbero build tool and packaging changes in 1.22.8
+
+-   cerbero: Fix some more python 3.12 string escape warnings
+-   cerbero: Fix bundle-source not including build-tools recipes, fix
+    CalledProcessError handling
+-   pango: Add Perl interpreter consistency check
+
+Contributors to 1.22.8
+
+Alessandro Bono, Alexander Slobodeniuk, Arun Raghavan, Benjamin
+Gaignard, Daniel Moberg, Dongyun Seo, Doug Nazar, Guillaume Desmottes,
+Hosang Lee, Jan Alexander Steffens (heftig), jeri.li, Jimmy Ohn, L. E.
+Segovia, Mathieu Duponchelle, Nicolas Dufresne, Nirbheek Chauhan,
+Olivier Crête, Philippe Normand, Piotr Brzeziński, Rabindra Harlalka,
+Robert Mader, Robin Gustavsson, Sebastian Dröge, Seungha Yang, Stefan
+Brüns, Tim-Philipp Müller, Xavier Claessens,
+
+… and many others who have contributed bug reports, translations, sent
+suggestions or helped testing. Thank you all!
+
+List of merge requests and issues fixed in 1.22.8
+
+-   List of Merge Requests applied in 1.22.8
+-   List of Issues fixed in 1.22.8
+
+Schedule for 1.24
+
+Our next major feature release will be 1.24, and 1.23 will be the
+unstable development version leading up to the stable 1.24 release. The
+development of 1.23/1.24 will happen in the git main branch of the
+GStreamer mono repository.
+
+The plan for the 1.24 development cycle is yet to be confirmed.
+
+1.24 will be backwards-compatible to the stable 1.22, 1.20, 1.18, 1.16,
+1.14, 1.12, 1.10, 1.8, 1.6, 1.4, 1.2 and 1.0 release series.
+
+------------------------------------------------------------------------
+
+These release notes have been prepared by Tim-Philipp Müller with
+contributions from Edward Hervey, Matthew Waters, Nicolas Dufresne,
+Nirbheek Chauhan, Olivier Crête, Sebastian Dröge, Seungha Yang, and
+Thibault Saunier.
+
+License: CC BY-SA 4.0
diff --git a/subprojects/gstreamer-vaapi/README b/subprojects/gstreamer-vaapi/README
new file mode 100644 (file)
index 0000000..5cc959c
--- /dev/null
@@ -0,0 +1,133 @@
+
+  gstreamer-vaapi
+  VA-API support to GStreamer
+
+  Copyright (C) 2010-2011 Splitted-Desktop Systems
+  Copyright (C) 2011-2020 Intel Corporation
+  Copyright (C) 2011 Collabora Ltd.
+  Copyright (C) 2015-2020 Igalia, S.L.
+
+
+License
+-------
+
+gstreamer-vaapi helper libraries and plugin elements are available
+under the terms of the GNU Lesser General Public License v2.1+
+
+
+Overview
+--------
+
+gstreamer-vaapi consists in a collection of VA-API based plugins for
+GStreamer and helper libraries.
+
+  * `vaapi<CODEC>dec' is used to decode JPEG, MPEG-2, MPEG-4:2, H.264
+    AVC, H.264 MVC, VP8, VP9, VC-1, WMV3, HEVC videos to VA surfaces,
+    depending on the actual value of <CODEC> and the underlying
+    hardware capabilities.  This plugin is also able to implicitly
+    download the decoded surface to raw YUV buffers.
+
+  * `vaapi<CODEC>enc' is used to encode into MPEG-2, H.264 AVC, H.264
+    MVC, JPEG, VP8, VP9, HEVC videos, depending on the actual value of
+    <CODEC> (mpeg2, h264, etc.) and the hardware capabilities. By
+    default, raw format bitstreams are generated, so the result may be
+    piped to a muxer, e.g. qtmux for MP4 containers.
+
+  * `vaapipostproc' is used to filter VA surfaces, for e.g. scaling,
+    deinterlacing (bob, motion-adaptive, motion-compensated), noise
+    reduction or sharpening. This plugin is also used to upload raw
+    YUV pixels into VA surfaces.
+
+  * `vaapisink' is used to render VA surfaces to an X11 or Wayland
+    display. This plugin also features a "headless" mode (DRM) more
+    suited to remote transcode scenarios, with faster throughput.
+
+  * `vaapioverlay` is a accelerated compositor that blends or
+    composite different video streams.
+
+
+Features
+--------
+
+  * VA-API support from 0.39
+  * JPEG, MPEG-2, MPEG-4, H.264 AVC, H.264 MVC, VP8, VC-1, HEVC and
+    VP9 ad-hoc decoders
+  * MPEG-2, H.264 AVC,H.264 MVC, JPEG, VP8, VP9 and HEVC ad-hoc
+    encoders
+  * OpenGL rendering through VA/GLX or GLX texture-from-pixmap + FBO
+  * Support for EGL backend
+  * Support for the Wayland display server
+  * Support for headless decode pipelines with VA/DRM
+  * Support for major HW video decoding solutions on Linux (AMD,
+    Intel, NVIDIA)
+  * Support for HW video encoding on Intel HD Graphics hardware
+  * Support for VA Video Processing APIs (VA/VPP)
+    - Scaling and color conversion
+    - Image enhancement filters: Sharpening, Noise Reductio, Color
+      Balance, Skin-Tone-Enhancement
+    - Advanced deinterlacing: Motion-Adaptive, Motion-Compensated
+
+
+Requirements
+------------
+
+Hardware requirements
+
+  * Hardware supported by i965 driver or iHD, such as
+    - Intel Ironlake, Sandybridge, Ivybridge, Haswell, Broadwell,
+      Skylake, etc. (HD Graphics)
+    - Intel BayTrail, Braswell
+    - Intel Poulsbo (US15W)
+    - Intel Medfield or Cedar Trail
+  * Hardware supported by AMD Radeonsi driver, such as the list below
+    - AMD Carrizo, Bristol Ridge, Raven Ridge, Picasso, Renoir
+    - AMD Tonga, Fiji, Polaris XX, Vega XX, Navi 1X
+  * Other hardware supported by Mesa VA gallium state-tracker
+
+
+Usage
+-----
+
+  VA elements are automatically plugged into GStreamer pipelines. So,
+  using playbin should work as is.
+  However, here are a few alternate pipelines that could be manually
+  constructed.
+
+  * Play an H.264 video with an MP4 container in fullscreen mode
+  $ gst-launch-1.0 -v filesrc location=/path/to/video.mp4 ! \
+      qtdemux ! vaapidecodebin ! vaapisink fullscreen=true
+
+  * Play a raw MPEG-2 interlaced stream
+  $ gst-launch-1.0 -v filesrc location=/path/to/mpeg2.bits ! \
+      mpegvideoparse ! vaapimpeg2dec ! vaapipostproc ! vaapisink
+
+  * Convert from one pixel format to another, while also downscaling
+  $ gst-launch-1.0 -v filesrc location=/path/to/raw_video.yuv ! \
+      videoparse format=yuy2 width=1280 height=720 ! \
+      vaapipostproc format=nv12 height=480 ! vaapisink
+
+  * Encode a 1080p stream in raw I420 format into H.264
+  $ gst-launch-1.0 -v filesrc location=/path/to/raw_video.yuv ! \
+      videoparse format=i420 width=1920 height=1080 framerate=30/1 ! \
+      vaapih264enc rate-control=cbr tune=high-compression ! \
+      qtmux ! filesink location=/path/to/encoded_video.mp4
+
+
+Sources
+-------
+
+  gstreamer-vaapi is Open Source software, so updates to this
+  framework are really easy to get.
+
+  Stable source code releases can be found at:
+  <https://gstreamer.freedesktop.org/src/gstreamer-vaapi/>
+
+  GitLab repository for work-in-progress changes is available at:
+  <https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi>
+
+
+Reporting Bugs
+--------------
+
+  Bugs can be reported in the GStreamer's GitLab system at:
+  <https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues>
diff --git a/subprojects/gstreamer-vaapi/RELEASE b/subprojects/gstreamer-vaapi/RELEASE
new file mode 100644 (file)
index 0000000..57fee0a
--- /dev/null
@@ -0,0 +1,104 @@
+This is GStreamer gstreamer-vaapi 1.22.8.
+
+The GStreamer team is thrilled to announce a new major feature release
+of your favourite cross-platform multimedia framework!
+
+As always, this release is again packed with new features, bug fixes and
+other improvements.
+
+The 1.22 release series adds new features on top of the 1.20 series and is
+part of the API and ABI-stable 1.x release series.
+
+Full release notes can be found at:
+
+  https://gstreamer.freedesktop.org/releases/1.22/
+
+Binaries for Android, iOS, Mac OS X and Windows will usually be provided
+shortly after the release.
+
+This module will not be very useful by itself and should be used in conjunction
+with other GStreamer modules for a complete multimedia experience.
+
+ - gstreamer: provides the core GStreamer libraries and some generic plugins
+
+ - gst-plugins-base: a basic set of well-supported plugins and additional
+                     media-specific GStreamer helper libraries for audio,
+                     video, rtsp, rtp, tags, OpenGL, etc.
+
+ - gst-plugins-good: a set of well-supported plugins under our preferred
+                     license
+
+ - gst-plugins-ugly: a set of well-supported plugins which might pose
+                     problems for distributors
+
+ - gst-plugins-bad: a set of plugins of varying quality that have not made
+                    their way into one of core/base/good/ugly yet, for one
+                    reason or another. Many of these are are production quality
+                    elements, but may still be missing documentation or unit
+                    tests; others haven't passed the rigorous quality testing
+                    we expect yet.
+
+ - gst-libav: a set of codecs plugins based on the ffmpeg library. This is
+                    where you can find audio and video decoders and encoders
+                    for a wide variety of formats including H.264, AAC, etc.
+
+ - gstreamer-vaapi: hardware-accelerated video decoding and encoding using
+                    VA-API on Linux. Primarily for Intel graphics hardware.
+
+ - gst-omx: hardware-accelerated video decoding and encoding, primarily for
+                    embedded Linux systems that provide an OpenMax
+                    implementation layer such as the Raspberry Pi.
+
+ - gst-rtsp-server: library to serve files or streaming pipelines via RTSP
+
+ - gst-editing-services: library an plugins for non-linear editing
+
+ - gst-plugins-rs: an exciting collection of well-maintained plugins written
+                   in the Rust programming language (usable from any language)
+
+==== Download ====
+
+You can find source releases of gstreamer in the download
+directory: https://gstreamer.freedesktop.org/src/gstreamer/
+
+The git repository and details how to clone it can be found at
+https://gitlab.freedesktop.org/gstreamer/gstreamer/
+
+==== Homepage ====
+
+The project's website is https://gstreamer.freedesktop.org/
+
+==== Support and Bugs ====
+
+We track bugs and feature requests in GitLab:
+
+  https://gitlab.freedesktop.org/gstreamer/gstreamer/
+
+Please submit patches via GitLab as well, in form of Merge Requests. See
+
+  https://gstreamer.freedesktop.org/documentation/contribute/
+
+for more details.
+
+For help and support, please subscribe to and send questions to the
+gstreamer-devel mailing list (see below for details).
+
+There is also a #gstreamer IRC channel on the OFTC IRC network, which is
+also bridged into the Matrix network.
+
+Please do not submit support requests in GitLab, we only use it
+for bug tracking and merge requests review.
+
+==== Developers ====
+
+The GStreamer source code repository can be found on GitLab on freedesktop.org:
+
+  https://gitlab.freedesktop.org/gstreamer/gstreamer/
+
+and can also be cloned from there and this is also where you can submit
+Merge Requests or file issues for bugs or feature requests.
+
+Interested developers of the core library, plugins, and applications should
+subscribe to the gstreamer-devel list:
+
+  https://lists.freedesktop.org/mailman/listinfo/gstreamer-devel
diff --git a/subprojects/gstreamer-vaapi/docs/gst_plugins_cache.json b/subprojects/gstreamer-vaapi/docs/gst_plugins_cache.json
new file mode 100644 (file)
index 0000000..8868c20
--- /dev/null
@@ -0,0 +1,2018 @@
+{
+    "vaapi": {
+        "description": "VA-API based elements",
+        "elements": {
+            "vaapidecodebin": {
+                "author": "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, Victor Jaquez <victorx.jaquez@intel.com>",
+                "description": "A VA-API based bin with a decoder and a postprocessor",
+                "hierarchy": [
+                    "GstVaapiDecodeBin",
+                    "GstBin",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "interfaces": [
+                    "GstChildProxy"
+                ],
+                "klass": "Codec/Decoder/Video/Hardware",
+                "long-name": "VA-API Decode Bin",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/mpeg:\n    mpegversion: 2\n   systemstream: false\nvideo/mpeg:\n    mpegversion: 4\nvideo/x-divx:\nvideo/x-xvid:\nvideo/x-h263:\nvideo/x-h264:\nvideo/x-h265:\nvideo/x-wmv:\nvideo/x-vp8:\nvideo/x-vp9:\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-raw(memory:VASurface):\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n         format: { RGBA, BGRA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\nvideo/x-raw:\n         format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {
+                    "deinterlace-method": {
+                        "blurb": "Deinterlace method to use",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "none (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiDeinterlaceMethod",
+                        "writable": true
+                    },
+                    "disable-vpp": {
+                        "blurb": "Disable Video Post Processing (No support for run time disabling)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "max-size-buffers": {
+                        "blurb": "Max. number of buffers in the queue (0=disable)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "-1",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "max-size-bytes": {
+                        "blurb": "Max. amount of data in the queue (bytes, 0=disable)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "-1",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "max-size-time": {
+                        "blurb": "Max. amount of data in the queue (in ns, 0=disable)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "18446744073709551615",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint64",
+                        "writable": true
+                    }
+                },
+                "rank": "primary + 2"
+            },
+            "vaapih264dec": {
+                "author": "Gwenole Beauchesne <gwenole.beauchesne@intel.com>, Halley Zhao <halley.zhao@intel.com>, Sreerenj Balachandran <sreerenj.balachandran@intel.com>, Wind Yuan <feng.yuan@intel.com>",
+                "description": "A VA-API based H264 video decoder",
+                "hierarchy": [
+                    "GstVaapiDecode_h264",
+                    "GstVideoDecoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "klass": "Codec/Decoder/Video/Hardware",
+                "long-name": "VA-API H264 decoder",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/x-h264:\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-raw(memory:VASurface):\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n         format: { RGBA, BGRA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n         format: { I420, YV12, RGBA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {
+                    "base-only": {
+                        "blurb": "Drop any NAL unit not defined in Annex.A",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "low-latency": {
+                        "blurb": "When enabled, frames will be pushed as soon as they are available. It might violate the H.264 spec.",
+                        "conditionally-available": false,
+                        "construct": true,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    }
+                },
+                "rank": "primary"
+            },
+            "vaapih264enc": {
+                "author": "Wind Yuan <feng.yuan@intel.com>",
+                "description": "A VA-API based H264 video encoder",
+                "hierarchy": [
+                    "GstVaapiEncodeH264",
+                    "GstVaapiEncode",
+                    "GstVideoEncoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "interfaces": [
+                    "GstPreset"
+                ],
+                "klass": "Codec/Encoder/Video/Hardware",
+                "long-name": "VA-API H264 encoder",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/x-raw:\n         format: { NV12, YV12, I420 }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(memory:VASurface):\n         format: { NV12, YV12, I420 }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-h264:\n  stream-format: { (string)avc, (string)byte-stream }\n      alignment: au\n        profile: { (string)constrained-baseline, (string)baseline, (string)main, (string)high, (string)multiview-high, (string)stereo-high }\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {
+                    "bitrate": {
+                        "blurb": "The desired bitrate expressed in kbps (0: auto-calculate)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "2048000",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "cabac": {
+                        "blurb": "Enable CABAC entropy coding mode",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "compliance-mode": {
+                        "blurb": "Tune Encode quality/performance by relaxing specification compliance restrictions",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "strict (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiEncoderH264ComplianceMode",
+                        "writable": true
+                    },
+                    "cpb-length": {
+                        "blurb": "Length of the CPB buffer in milliseconds",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1500",
+                        "max": "10000",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "dct8x8": {
+                        "blurb": "Enable adaptive use of 8x8 transforms in I-frames",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "default-roi-delta-qp": {
+                        "blurb": "The default delta-qp to apply to each Region of Interest(lower value means higher-quality, higher value means lower-quality)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "-10",
+                        "max": "10",
+                        "min": "-10",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gint",
+                        "writable": true
+                    },
+                    "init-qp": {
+                        "blurb": "Initial quantizer value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "26",
+                        "max": "51",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "keyframe-period": {
+                        "blurb": "Maximal distance between two keyframes (0: auto-calculate)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "30",
+                        "max": "-1",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "max-bframes": {
+                        "blurb": "Number of B-frames between I and P",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "10",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "max-qp": {
+                        "blurb": "Maximum quantizer value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "51",
+                        "max": "51",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "mbbrc": {
+                        "blurb": "Macroblock level Bitrate Control",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "auto (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiEncoderMbbrc",
+                        "writable": true
+                    },
+                    "min-qp": {
+                        "blurb": "Minimum quantizer value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "51",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "num-slices": {
+                        "blurb": "Number of slices per frame",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "200",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "num-views": {
+                        "blurb": "Number of Views for MVC encoding",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "10",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "prediction-type": {
+                        "blurb": "Reference Picture Selection Modes",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "default (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiEncoderH264PredictionType",
+                        "writable": true
+                    },
+                    "qp-ib": {
+                        "blurb": "Difference of QP between I and B frame (available only on CQP)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "51",
+                        "min": "-51",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gint",
+                        "writable": true
+                    },
+                    "qp-ip": {
+                        "blurb": "Difference of QP between I and P frame (available only on CQP)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "51",
+                        "min": "-51",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gint",
+                        "writable": true
+                    },
+                    "quality-factor": {
+                        "blurb": "quality factor for ICQ/QVBR bitrate control mode(low value means higher-quality, higher value means lower-quality)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "26",
+                        "max": "51",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "quality-level": {
+                        "blurb": "Encoding Quality Level (lower value means higher-quality/slow-encode,  higher value means lower-quality/fast-encode)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "4",
+                        "max": "7",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "rate-control": {
+                        "blurb": "Rate control mode",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "cqp (1)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiRateControlH264",
+                        "writable": true
+                    },
+                    "refs": {
+                        "blurb": "Number of reference frames",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "8",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "target-percentage": {
+                        "blurb": "The desired target percentage of bitrate for variable rate controls.",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "70",
+                        "max": "100",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "temporal-levels": {
+                        "blurb": "Number of temporal levels in the encoded stream ",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "4",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "trellis": {
+                        "blurb": "The Trellis Quantization Method of Encoder",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "tune": {
+                        "blurb": "Encoder tuning option",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "none (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiEncoderTuneH264",
+                        "writable": true
+                    },
+                    "view-ids": {
+                        "blurb": "Set of View Ids used for MVC encoding",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstValueArray",
+                        "writable": true
+                    }
+                },
+                "rank": "primary"
+            },
+            "vaapih265dec": {
+                "author": "Gwenole Beauchesne <gwenole.beauchesne@intel.com>, Halley Zhao <halley.zhao@intel.com>, Sreerenj Balachandran <sreerenj.balachandran@intel.com>, Wind Yuan <feng.yuan@intel.com>",
+                "description": "A VA-API based H265 video decoder",
+                "hierarchy": [
+                    "GstVaapiDecode_h265",
+                    "GstVideoDecoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "klass": "Codec/Decoder/Video/Hardware",
+                "long-name": "VA-API H265 decoder",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/x-h265:\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-raw(memory:VASurface):\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n         format: { RGBA, BGRA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n         format: { I420, YV12, RGBA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {},
+                "rank": "primary"
+            },
+            "vaapih265enc": {
+                "author": "Sreerenj Balachandran <sreerenj.balachandran@intel.com>",
+                "description": "A VA-API based H265 video encoder",
+                "hierarchy": [
+                    "GstVaapiEncodeH265",
+                    "GstVaapiEncode",
+                    "GstVideoEncoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "interfaces": [
+                    "GstPreset"
+                ],
+                "klass": "Codec/Encoder/Video/Hardware",
+                "long-name": "VA-API H265 encoder",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/x-raw:\n         format: { NV12, YV12, I420 }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(memory:VASurface):\n         format: { NV12, YV12, I420 }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-h265:\n  stream-format: { (string)hvc1, (string)byte-stream }\n      alignment: au\n        profile: { (string)main, (string)main-10, (string)main-444, (string)main-444-10 }\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {
+                    "bitrate": {
+                        "blurb": "The desired bitrate expressed in kbps (0: auto-calculate)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "2048000",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "cpb-length": {
+                        "blurb": "Length of the CPB buffer in milliseconds",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1500",
+                        "max": "10000",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "default-roi-delta-qp": {
+                        "blurb": "The default delta-qp to apply to each Region of Interest(lower value means higher-quality, higher value means lower-quality)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "-10",
+                        "max": "10",
+                        "min": "-10",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gint",
+                        "writable": true
+                    },
+                    "init-qp": {
+                        "blurb": "Initial quantizer value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "26",
+                        "max": "51",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "keyframe-period": {
+                        "blurb": "Maximal distance between two keyframes (0: auto-calculate)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "30",
+                        "max": "-1",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "low-delay-b": {
+                        "blurb": "Transforms P frames into predictive B frames. Enable it when P frames are not supported.",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "max-bframes": {
+                        "blurb": "Number of B-frames between I and P",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "10",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "max-qp": {
+                        "blurb": "Maximum quantizer value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "51",
+                        "max": "51",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "mbbrc": {
+                        "blurb": "Macroblock level Bitrate Control",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "auto (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiEncoderMbbrc",
+                        "writable": true
+                    },
+                    "min-qp": {
+                        "blurb": "Minimum quantizer value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "51",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "num-slices": {
+                        "blurb": "Number of slices per frame",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "200",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "num-tile-cols": {
+                        "blurb": "the number of columns for tile encoding",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "20",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "num-tile-rows": {
+                        "blurb": "the number of rows for tile encoding",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "22",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "qp-ib": {
+                        "blurb": "Difference of QP between I and B frame (available only on CQP)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "51",
+                        "min": "-51",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gint",
+                        "writable": true
+                    },
+                    "qp-ip": {
+                        "blurb": "Difference of QP between I and P frame (available only on CQP)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "51",
+                        "min": "-51",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gint",
+                        "writable": true
+                    },
+                    "quality-factor": {
+                        "blurb": "quality factor for ICQ/QBVR bitrate control mode (lower value means higher quality, higher value means lower quality)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "26",
+                        "max": "51",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "quality-level": {
+                        "blurb": "Encoding Quality Level (lower value means higher-quality/slow-encode,  higher value means lower-quality/fast-encode)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "4",
+                        "max": "7",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "rate-control": {
+                        "blurb": "Rate control mode",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "cqp (1)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiRateControlH265",
+                        "writable": true
+                    },
+                    "refs": {
+                        "blurb": "Number of reference frames",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "3",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "target-percentage": {
+                        "blurb": "The desired target percentage of bitrate for variable rate controls.",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "70",
+                        "max": "100",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "trellis": {
+                        "blurb": "The Trellis Quantization Method of Encoder",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "tune": {
+                        "blurb": "Encoder tuning option",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "none (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiEncoderTuneH265",
+                        "writable": true
+                    }
+                },
+                "rank": "primary"
+            },
+            "vaapijpegdec": {
+                "author": "Gwenole Beauchesne <gwenole.beauchesne@intel.com>, Halley Zhao <halley.zhao@intel.com>, Sreerenj Balachandran <sreerenj.balachandran@intel.com>, Wind Yuan <feng.yuan@intel.com>",
+                "description": "A VA-API based JPEG video decoder",
+                "hierarchy": [
+                    "GstVaapiDecode_jpeg",
+                    "GstVideoDecoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "klass": "Codec/Decoder/Video/Hardware",
+                "long-name": "VA-API JPEG decoder",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "image/jpeg:\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-raw(memory:VASurface):\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n         format: { RGBA, BGRA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n         format: { I420, YV12, RGBA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {},
+                "rank": "marginal"
+            },
+            "vaapimpeg2dec": {
+                "author": "Gwenole Beauchesne <gwenole.beauchesne@intel.com>, Halley Zhao <halley.zhao@intel.com>, Sreerenj Balachandran <sreerenj.balachandran@intel.com>, Wind Yuan <feng.yuan@intel.com>",
+                "description": "A VA-API based MPEG2 video decoder",
+                "hierarchy": [
+                    "GstVaapiDecode_mpeg2",
+                    "GstVideoDecoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "klass": "Codec/Decoder/Video/Hardware",
+                "long-name": "VA-API MPEG2 decoder",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/mpeg:\n    mpegversion: 2\n   systemstream: false\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-raw(memory:VASurface):\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n         format: { RGBA, BGRA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n         format: { I420, YV12, RGBA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {},
+                "rank": "primary"
+            },
+            "vaapimpeg2enc": {
+                "author": "Guangxin Xu <guangxin.xu@intel.com>",
+                "description": "A VA-API based MPEG-2 video encoder",
+                "hierarchy": [
+                    "GstVaapiEncodeMpeg2",
+                    "GstVaapiEncode",
+                    "GstVideoEncoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "interfaces": [
+                    "GstPreset"
+                ],
+                "klass": "Codec/Encoder/Video/Hardware",
+                "long-name": "VA-API MPEG-2 encoder",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/x-raw:\n         format: { NV12, YV12, I420 }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(memory:VASurface):\n         format: { NV12, YV12, I420 }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/mpeg:\n    mpegversion: 2\n   systemstream: false\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {
+                    "bitrate": {
+                        "blurb": "The desired bitrate expressed in kbps (0: auto-calculate)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "2048000",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "default-roi-delta-qp": {
+                        "blurb": "The default delta-qp to apply to each Region of Interest(lower value means higher-quality, higher value means lower-quality)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "-10",
+                        "max": "10",
+                        "min": "-10",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gint",
+                        "writable": true
+                    },
+                    "keyframe-period": {
+                        "blurb": "Maximal distance between two keyframes (0: auto-calculate)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "30",
+                        "max": "-1",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "max-bframes": {
+                        "blurb": "Number of B-frames between I and P",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "16",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "min-force-key-unit-interval": {
+                        "blurb": "Minimum interval between force-keyunit requests in nanoseconds",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "18446744073709551615",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint64",
+                        "writable": true
+                    },
+                    "qos": {
+                        "blurb": "Handle Quality-of-Service events from downstream",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "quality-level": {
+                        "blurb": "Encoding Quality Level (lower value means higher-quality/slow-encode,  higher value means lower-quality/fast-encode)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "4",
+                        "max": "7",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "quantizer": {
+                        "blurb": "Constant quantizer (if rate-control mode is CQP)",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "8",
+                        "max": "62",
+                        "min": "2",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "rate-control": {
+                        "blurb": "Rate control mode",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "cqp (1)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiRateControlMPEG2",
+                        "writable": true
+                    },
+                    "target-percentage": {
+                        "blurb": "The desired target percentage of bitrate for variable rate controls.",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "70",
+                        "max": "100",
+                        "min": "1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "trellis": {
+                        "blurb": "The Trellis Quantization Method of Encoder",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "tune": {
+                        "blurb": "Encoder tuning option",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "none (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiEncoderTuneMPEG2",
+                        "writable": true
+                    }
+                },
+                "rank": "primary"
+            },
+            "vaapipostproc": {
+                "author": "Gwenole Beauchesne <gwenole.beauchesne@intel.com>",
+                "description": "A VA-API video postprocessing filter",
+                "hierarchy": [
+                    "GstVaapiPostproc",
+                    "GstBaseTransform",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "interfaces": [
+                    "GstColorBalance"
+                ],
+                "klass": "Filter/Converter/Effect/Video/Scaler/Deinterlace/Hardware",
+                "long-name": "VA-API video postprocessing",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/x-raw(memory:VASurface):\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: { (string)progressive, (string)interleaved, (string)mixed }\nvideo/x-raw:\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: { (string)progressive, (string)interleaved, (string)mixed }\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-raw(memory:VASurface):\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: progressive\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n         format: { RGBA, BGRA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n interlace-mode: { (string)progressive, (string)interleaved, (string)mixed }\n\nvideo/x-raw(memory:DMABuf):\n         format: { I420, YV12, RGBA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {
+                    "brightness": {
+                        "blurb": "The color brightness value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "1",
+                        "min": "-1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "contrast": {
+                        "blurb": "The color contrast value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "2",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "crop-bottom": {
+                        "blurb": "Pixels to crop at bottom",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "2147483647",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "crop-left": {
+                        "blurb": "Pixels to crop at left",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "2147483647",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "crop-right": {
+                        "blurb": "Pixels to crop at right",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "2147483647",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "crop-top": {
+                        "blurb": "Pixels to crop at top",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "2147483647",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "deinterlace-method": {
+                        "blurb": "Deinterlace method to use",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "bob (1)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiDeinterlaceMethod",
+                        "writable": true
+                    },
+                    "deinterlace-mode": {
+                        "blurb": "Deinterlace mode to use",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "auto (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiDeinterlaceMode",
+                        "writable": true
+                    },
+                    "denoise": {
+                        "blurb": "The level of denoising to apply",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "1",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "force-aspect-ratio": {
+                        "blurb": "When enabled, scaling will respect original aspect ratio",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "true",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "format": {
+                        "blurb": "The forced output pixel format",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "encoded (1)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVideoFormat",
+                        "writable": true
+                    },
+                    "hdr-tone-map": {
+                        "blurb": "Apply HDR tone mapping algorithm",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "auto (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiHDRToneMap",
+                        "writable": true
+                    },
+                    "height": {
+                        "blurb": "Forced output height",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "2147483647",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "hue": {
+                        "blurb": "The color hue value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "180",
+                        "min": "-180",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "saturation": {
+                        "blurb": "The color saturation value",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "2",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "scale-method": {
+                        "blurb": "Scaling method to use",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "default (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiScaleMethod",
+                        "writable": true
+                    },
+                    "sharpen": {
+                        "blurb": "The level of sharpening/blurring to apply",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "1",
+                        "min": "-1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "skin-tone-enhancement": {
+                        "blurb": "Apply the skin tone enhancement algorithm",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "skin-tone-enhancement-level": {
+                        "blurb": "Apply the skin tone enhancement algorithm with specified level",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "3",
+                        "max": "9",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
+                    "video-direction": {
+                        "blurb": "Video direction: rotation and flipping",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "identity (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVideoOrientationMethod",
+                        "writable": true
+                    },
+                    "width": {
+                        "blurb": "Forced output width",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "2147483647",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    }
+                },
+                "rank": "primary"
+            },
+            "vaapisink": {
+                "author": "Gwenole Beauchesne <gwenole.beauchesne@intel.com>",
+                "description": "A VA-API based videosink",
+                "hierarchy": [
+                    "GstVaapiSink",
+                    "GstVideoSink",
+                    "GstBaseSink",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "interfaces": [
+                    "GstVideoOverlay",
+                    "GstColorBalance",
+                    "GstNavigation"
+                ],
+                "klass": "Sink/Video",
+                "long-name": "VA-API sink",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/x-raw(memory:VASurface):\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:VASurface, meta:GstVideoOverlayComposition):\n         format: { ENCODED, NV12, I420, YV12, P010_10LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoOverlayComposition):\n         format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n         format: { AYUV64, ARGB64, GBRA_12LE, GBRA_12BE, Y412_LE, Y412_BE, A444_10LE, GBRA_10LE, A444_10BE, GBRA_10BE, A422_10LE, A422_10BE, A420_10LE, A420_10BE, RGB10A2_LE, BGR10A2_LE, Y410, GBRA, ABGR, VUYA, BGRA, AYUV, ARGB, RGBA, A420, Y444_16LE, Y444_16BE, v216, P016_LE, P016_BE, Y444_12LE, GBR_12LE, Y444_12BE, GBR_12BE, I422_12LE, I422_12BE, Y212_LE, Y212_BE, I420_12LE, I420_12BE, P012_LE, P012_BE, Y444_10LE, GBR_10LE, Y444_10BE, GBR_10BE, r210, I422_10LE, I422_10BE, NV16_10LE32, Y210, v210, UYVP, I420_10LE, I420_10BE, P010_10LE, NV12_10LE32, NV12_10LE40, P010_10BE, Y444, GBR, NV24, xBGR, BGRx, xRGB, RGBx, BGR, IYU2, v308, RGB, Y42B, NV61, NV16, VYUY, UYVY, YVYU, YUY2, I420, YV12, NV21, NV12, NV12_64Z32, Y41B, IYU1, YVU9, YUV9, RGB16, BGR16, RGB15, BGR15, RGB8P, GRAY16_LE, GRAY16_BE, GRAY10_LE32, GRAY8 }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    }
+                },
+                "properties": {
+                    "brightness": {
+                        "blurb": "The display brightness value",
+                        "conditionally-available": false,
+                        "construct": true,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "1",
+                        "min": "-1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "contrast": {
+                        "blurb": "The display contrast value",
+                        "conditionally-available": false,
+                        "construct": true,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "2",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "display": {
+                        "blurb": "display type to use",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "any (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiDisplayType",
+                        "writable": true
+                    },
+                    "display-name": {
+                        "blurb": "display name to use",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "NULL",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gchararray",
+                        "writable": true
+                    },
+                    "force-aspect-ratio": {
+                        "blurb": "When enabled, scaling will respect original aspect ratio",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "true",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "fullscreen": {
+                        "blurb": "Requests window in fullscreen state",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "hue": {
+                        "blurb": "The display hue value",
+                        "conditionally-available": false,
+                        "construct": true,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0",
+                        "max": "180",
+                        "min": "-180",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "rotation": {
+                        "blurb": "The display rotation mode",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "0 (0)",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "GstVaapiRotation",
+                        "writable": true
+                    },
+                    "saturation": {
+                        "blurb": "The display saturation value",
+                        "conditionally-available": false,
+                        "construct": true,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "1",
+                        "max": "2",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gfloat",
+                        "writable": true
+                    },
+                    "signal-handoffs": {
+                        "blurb": "Send a signal after rendering the buffer",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "false",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gboolean",
+                        "writable": true
+                    },
+                    "view-id": {
+                        "blurb": "ID of the view component of interest to display",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "-1",
+                        "max": "2147483647",
+                        "min": "-1",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "gint",
+                        "writable": true
+                    }
+                },
+                "rank": "marginal",
+                "signals": {
+                    "handoff": {
+                        "args": [
+                            {
+                                "name": "arg0",
+                                "type": "GstBuffer"
+                            }
+                        ],
+                        "return-type": "void",
+                        "when": "last"
+                    }
+                }
+            },
+            "vaapivc1dec": {
+                "author": "Gwenole Beauchesne <gwenole.beauchesne@intel.com>, Halley Zhao <halley.zhao@intel.com>, Sreerenj Balachandran <sreerenj.balachandran@intel.com>, Wind Yuan <feng.yuan@intel.com>",
+                "description": "A VA-API based VC1 video decoder",
+                "hierarchy": [
+                    "GstVaapiDecode_vc1",
+                    "GstVideoDecoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "klass": "Codec/Decoder/Video/Hardware",
+                "long-name": "VA-API VC1 decoder",
+                "pad-templates": {
+                    "sink": {
+                        "caps": "video/x-wmv:\n     wmvversion: 3\n         format: { WMV3, WVC1 }\n",
+                        "direction": "sink",
+                        "presence": "always"
+                    },
+                    "src": {
+                        "caps": "video/x-raw(memory:VASurface):\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(meta:GstVideoGLTextureUploadMeta):\n         format: { RGBA, BGRA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\nvideo/x-raw:\n         format: { ENCODED, NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, VUYA, Y210, Y410, ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n\nvideo/x-raw(memory:DMABuf):\n         format: { I420, YV12, RGBA }\n          width: [ 1, 2147483647 ]\n         height: [ 1, 2147483647 ]\n      framerate: [ 0/1, 2147483647/1 ]\n",
+                        "direction": "src",
+                        "presence": "always"
+                    }
+                },
+                "properties": {},
+                "rank": "primary"
+            }
+        },
+        "filename": "gstvaapi",
+        "license": "LGPL",
+        "other-types": {
+            "GstVaapiDeinterlaceMethod": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Disable deinterlacing",
+                        "name": "none",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "Bob deinterlacing",
+                        "name": "bob",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Weave deinterlacing",
+                        "name": "weave",
+                        "value": "2"
+                    },
+                    {
+                        "desc": "Motion adaptive deinterlacing",
+                        "name": "motion-adaptive",
+                        "value": "3"
+                    },
+                    {
+                        "desc": "Motion compensated deinterlacing",
+                        "name": "motion-compensated",
+                        "value": "4"
+                    }
+                ]
+            },
+            "GstVaapiDeinterlaceMode": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Auto detection",
+                        "name": "auto",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "Force deinterlacing",
+                        "name": "interlaced",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Never deinterlace",
+                        "name": "disabled",
+                        "value": "2"
+                    }
+                ]
+            },
+            "GstVaapiDisplayType": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Auto detection",
+                        "name": "any",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "VA/X11 display",
+                        "name": "x11",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "VA/GLX display",
+                        "name": "glx",
+                        "value": "2"
+                    },
+                    {
+                        "desc": "VA/EGL display",
+                        "name": "egl",
+                        "value": "5"
+                    },
+                    {
+                        "desc": "VA/Wayland display",
+                        "name": "wayland",
+                        "value": "3"
+                    },
+                    {
+                        "desc": "VA/DRM display",
+                        "name": "drm",
+                        "value": "4"
+                    }
+                ]
+            },
+            "GstVaapiEncode": {
+                "hierarchy": [
+                    "GstVaapiEncode",
+                    "GstVideoEncoder",
+                    "GstElement",
+                    "GstObject",
+                    "GInitiallyUnowned",
+                    "GObject"
+                ],
+                "interfaces": [
+                    "GstPreset"
+                ],
+                "kind": "object"
+            },
+            "GstVaapiEncoderH264ComplianceMode": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Strict compliance to the H264 Specification ",
+                        "name": "strict",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "Restrict the allocation size of coded-buffer",
+                        "name": "restrict-buf-alloc",
+                        "value": "1"
+                    }
+                ]
+            },
+            "GstVaapiEncoderH264PredictionType": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Default encode, prev/next frame as ref ",
+                        "name": "default",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "Hierarchical P frame encode",
+                        "name": "hierarchical-p",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Hierarchical B frame encode",
+                        "name": "hierarchical-b",
+                        "value": "2"
+                    }
+                ]
+            },
+            "GstVaapiEncoderMbbrc": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Auto",
+                        "name": "auto",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "On",
+                        "name": "on",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Off",
+                        "name": "off",
+                        "value": "2"
+                    }
+                ]
+            },
+            "GstVaapiEncoderTuneH264": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "None",
+                        "name": "none",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "High compression",
+                        "name": "high-compression",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Low power mode",
+                        "name": "low-power",
+                        "value": "3"
+                    }
+                ]
+            },
+            "GstVaapiEncoderTuneH265": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "None",
+                        "name": "none",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "Low power mode",
+                        "name": "low-power",
+                        "value": "3"
+                    }
+                ]
+            },
+            "GstVaapiEncoderTuneMPEG2": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "None",
+                        "name": "none",
+                        "value": "0"
+                    }
+                ]
+            },
+            "GstVaapiHDRToneMap": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Auto detection",
+                        "name": "auto",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "Disable HDR tone mapping",
+                        "name": "disabled",
+                        "value": "1"
+                    }
+                ]
+            },
+            "GstVaapiRateControlH264": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Constant QP",
+                        "name": "cqp",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Constant bitrate",
+                        "name": "cbr",
+                        "value": "2"
+                    },
+                    {
+                        "desc": "Variable bitrate",
+                        "name": "vbr",
+                        "value": "4"
+                    },
+                    {
+                        "desc": "Variable bitrate - Constrained",
+                        "name": "vbr_constrained",
+                        "value": "5"
+                    },
+                    {
+                        "desc": "Constant QP - Intelligent",
+                        "name": "icq",
+                        "value": "7"
+                    },
+                    {
+                        "desc": "Variable bitrate - Quality defined",
+                        "name": "qvbr",
+                        "value": "8"
+                    }
+                ]
+            },
+            "GstVaapiRateControlH265": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Constant QP",
+                        "name": "cqp",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Constant bitrate",
+                        "name": "cbr",
+                        "value": "2"
+                    },
+                    {
+                        "desc": "Variable bitrate",
+                        "name": "vbr",
+                        "value": "4"
+                    },
+                    {
+                        "desc": "Constant QP - Intelligent",
+                        "name": "icq",
+                        "value": "7"
+                    },
+                    {
+                        "desc": "Variable bitrate - Quality defined",
+                        "name": "qvbr",
+                        "value": "8"
+                    }
+                ]
+            },
+            "GstVaapiRateControlMPEG2": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Constant QP",
+                        "name": "cqp",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "Constant bitrate",
+                        "name": "cbr",
+                        "value": "2"
+                    }
+                ]
+            },
+            "GstVaapiRotation": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Unrotated mode",
+                        "name": "0",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "Rotated by 90°, clockwise",
+                        "name": "90",
+                        "value": "90"
+                    },
+                    {
+                        "desc": "Rotated by 180°, clockwise",
+                        "name": "180",
+                        "value": "180"
+                    },
+                    {
+                        "desc": "Rotated by 270°, clockwise",
+                        "name": "270",
+                        "value": "270"
+                    },
+                    {
+                        "desc": "Rotated by image-orientating tag°",
+                        "name": "Automatic",
+                        "value": "360"
+                    }
+                ]
+            },
+            "GstVaapiScaleMethod": {
+                "kind": "enum",
+                "values": [
+                    {
+                        "desc": "Default scaling mode",
+                        "name": "default",
+                        "value": "0"
+                    },
+                    {
+                        "desc": "Fast scaling mode",
+                        "name": "fast",
+                        "value": "1"
+                    },
+                    {
+                        "desc": "High quality scaling mode",
+                        "name": "hq",
+                        "value": "2"
+                    }
+                ]
+            }
+        },
+        "package": "gstreamer-vaapi",
+        "source": "gstreamer-vaapi",
+        "tracers": {},
+        "url": "Unknown package origin"
+    }
+}
\ No newline at end of file
diff --git a/subprojects/gstreamer-vaapi/docs/index.md b/subprojects/gstreamer-vaapi/docs/index.md
new file mode 100644 (file)
index 0000000..c143b28
--- /dev/null
@@ -0,0 +1,34 @@
+---
+short-description: GStreamer plugins from gstreamer-vaapi
+...
+
+# VAAPI Plugin
+
+## Environment variables
+
+GStreamer-VAAPI inspects a few of environment variables to define it
+usage.
+
+**GST_VAAPI_ALL_DRIVERS.**
+
+This environment variable can be set, independently of its value, to
+disable the drivers white list. By default only intel and mesa va
+drivers are loaded if they are available. The rest are ignored. With
+this environment variable defined, all the available va drivers are
+loaded, even if they are deprecated.
+
+**LIBVA_DRIVER_NAME.**
+
+This environment variable can be set with the drivers name to load. For
+example, intel's driver is `i965`, meanwhile mesa is `gallium`.
+
+**LIBVA_DRIVERS_PATH.**
+
+This environment variable can be set to a colon-separated list of paths
+(or a semicolon-separated list on Windows). libva will scan these paths
+for va drivers.
+
+**GST_VAAPI_DRM_DEVICE.**
+This environment variable can be set to a specified DRM device when DRM
+display is used, it is ignored when other types of displays are used.
+By default /dev/dri/renderD128 is used for DRM display.
diff --git a/subprojects/gstreamer-vaapi/docs/meson.build b/subprojects/gstreamer-vaapi/docs/meson.build
new file mode 100644 (file)
index 0000000..2ddb741
--- /dev/null
@@ -0,0 +1,83 @@
+build_hotdoc = false
+
+if meson.is_cross_build()
+    if get_option('doc').enabled()
+        error('Documentation enabled but building the doc while cross building is not supported yet.')
+    endif
+
+    message('Documentation not built as building it while cross building is not supported yet.')
+    subdir_done()
+endif
+
+if static_build
+    if get_option('doc').enabled()
+        error('Documentation enabled but not supported when building statically.')
+    endif
+
+    message('Building statically, can\'t build the documentation')
+    subdir_done()
+endif
+
+required_hotdoc_extensions = ['gi-extension', 'gst-extension']
+if gst_dep.type_name() == 'internal'
+    gst_proj = subproject('gstreamer')
+    plugins_cache_generator = gst_proj.get_variable('plugins_cache_generator')
+else
+    plugins_cache_generator = find_program(join_paths(gst_dep.get_variable('libexecdir'), 'gstreamer-' + api_version, 'gst-plugins-doc-cache-generator'),
+        required: false)
+endif
+
+plugins_cache = join_paths(meson.current_source_dir(), 'gst_plugins_cache.json')
+if plugins_cache_generator.found()
+    gst_plugins_doc_dep = custom_target('vaapi-plugins-doc-cache',
+        command: [plugins_cache_generator, plugins_cache, '@OUTPUT@', '@INPUT@'],
+        input: plugins,
+        output: 'gst_plugins_cache.json',
+        build_always_stale: true,
+    )
+else
+    warning('GStreamer plugin inspector for documentation not found, can\'t update the cache')
+endif
+
+hotdoc_p = find_program('hotdoc', required: get_option('doc'))
+if not hotdoc_p.found()
+    message('Hotdoc not found, not building the documentation')
+    subdir_done()
+endif
+
+hotdoc_req = '>= 0.11.0'
+hotdoc_version = run_command(hotdoc_p, '--version', check: false).stdout()
+if not hotdoc_version.version_compare(hotdoc_req)
+    if get_option('doc').enabled()
+        error('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version))
+    else
+        message('Hotdoc version @0@ not found, got @1@'.format(hotdoc_req, hotdoc_version))
+        subdir_done()
+    endif
+endif
+
+build_hotdoc = true
+hotdoc = import('hotdoc')
+if not hotdoc.has_extensions(required_hotdoc_extensions)
+    if get_option('doc').enabled()
+        error('Documentation enabled but gi-extension missing')
+    endif
+
+    message('@0@ extensions not found, not building documentation'.format(required_hotdoc_extensions))
+    subdir_done()
+endif
+
+message('Plugins: @0@'.format(plugins))
+libs_doc = []
+plugins_doc = [hotdoc.generate_doc('vaapi',
+    project_version: api_version,
+    sitemap: 'sitemap.txt',
+    index: 'index.md',
+    gst_index: 'index.md',
+    gst_smart_index: true,
+    gst_c_sources: ['../gst/*/*.[ch]',],
+    gst_cache_file: plugins_cache,
+    gst_plugin_name: 'vaapi',
+    dependencies: [gstbase_dep, gstvideo_dep, gstallocators_dep, gstpbutils_dep,
+    libva_dep, gstlibvaapi_dep, gstgl_dep, libm] + plugins,
+)]
diff --git a/subprojects/gstreamer-vaapi/docs/sitemap.txt b/subprojects/gstreamer-vaapi/docs/sitemap.txt
new file mode 100644 (file)
index 0000000..058a271
--- /dev/null
@@ -0,0 +1 @@
+gst-index
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/meson.build b/subprojects/gstreamer-vaapi/gst-libs/gst/meson.build
new file mode 100644 (file)
index 0000000..a8719a1
--- /dev/null
@@ -0,0 +1 @@
+subdir('vaapi')
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/egl_compat.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/egl_compat.h
new file mode 100644 (file)
index 0000000..c417211
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * egl_compat.h - EGL compatiliby layer
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *   Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301
+ */
+
+#ifndef EGL_COMPAT_H
+#define EGL_COMPAT_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include "ogl_compat.h"
+
+#ifndef GL_OES_EGL_image
+#define GL_OES_EGL_image 1
+typedef void *GLeglImageOES;
+typedef void (*PFNGLEGLIMAGETARGETTEXTURE2DOESPROC)(GLenum target,
+    GLeglImageOES image);
+typedef void (*PFNGLEGLIMAGETARGETRENDERBUFFERSTORAGEOESPROC)(GLenum target,
+    GLeglImageOES image);
+#endif /* GL_OES_EGL_image */
+
+#endif /* EGL_COMPAT_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/egl_vtable.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/egl_vtable.h
new file mode 100644 (file)
index 0000000..53b3acc
--- /dev/null
@@ -0,0 +1,806 @@
+/*
+ * egl_vtable.h - EGL function definitions
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *   Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301
+ */
+
+/* ------------------------------------------------------------------------- */
+// Generate strings
+
+#define GL_PROTO_GEN_STRING(x) \
+  GL_PROTO_GEN_STRING_I(x)
+#define GL_PROTO_GEN_STRING_I(x) \
+  #x
+
+/* ------------------------------------------------------------------------- */
+// Concatenate arguments
+
+#define GL_PROTO_GEN_CONCAT(a1, a2) \
+  GL_PROTO_GEN_CONCAT2_I(a1, a2)
+#define GL_PROTO_GEN_CONCAT2(a1, a2) \
+  GL_PROTO_GEN_CONCAT2_I(a1, a2)
+#define GL_PROTO_GEN_CONCAT2_I(a1, a2) \
+  a1 ## a2
+
+#define GL_PROTO_GEN_CONCAT3(a1, a2, a3) \
+  GL_PROTO_GEN_CONCAT3_I(a1, a2, a3)
+#define GL_PROTO_GEN_CONCAT3_I(a1, a2, a3) \
+  a1 ## a2 ## a3
+
+#define GL_PROTO_GEN_CONCAT4(a1, a2, a3, a4) \
+  GL_PROTO_GEN_CONCAT4_I(a1, a2, a3, a4)
+#define GL_PROTO_GEN_CONCAT4_I(a1, a2, a3, a4) \
+  a1 ## a2 ## a3 ## a4
+
+#define GL_PROTO_GEN_CONCAT5(a1, a2, a3, a4, a5) \
+  GL_PROTO_GEN_CONCAT5_I(a1, a2, a3, a4, a5)
+#define GL_PROTO_GEN_CONCAT5_I(a1, a2, a3, a4, a5) \
+  a1 ## a2 ## a3 ## a4 ## a5
+
+/* ------------------------------------------------------------------------- */
+// Default macros
+
+#ifndef EGL_PROTO_BEGIN
+#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION)
+#endif
+#ifndef EGL_PROTO_ARG_LIST
+#define EGL_PROTO_ARG_LIST(...) GL_PROTO_ARG_LIST(__VA_ARGS__)
+#endif
+#ifndef EGL_PROTO_ARG
+#define EGL_PROTO_ARG(NAME, TYPE) GL_PROTO_ARG(NAME, TYPE)
+#endif
+#ifndef EGL_PROTO_INVOKE
+#define EGL_PROTO_INVOKE(NAME, TYPE, ARGS)
+#endif
+#ifndef EGL_PROTO_END
+#define EGL_PROTO_END()
+#endif
+#ifndef EGL_DEFINE_EXTENSION
+#define EGL_DEFINE_EXTENSION(EXTENSION)
+#endif
+
+#ifndef GL_PROTO_BEGIN
+#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION)
+#endif
+#ifndef GL_PROTO_ARG_LIST
+#define GL_PROTO_ARG_LIST(...)
+#endif
+#ifndef GL_PROTO_ARG
+#define GL_PROTO_ARG(NAME, TYPE)
+#endif
+#ifndef GL_PROTO_INVOKE
+#define GL_PROTO_INVOKE(NAME, TYPE, ARGS)
+#endif
+#ifndef GL_PROTO_END
+#define GL_PROTO_END()
+#endif
+#ifndef GL_DEFINE_EXTENSION
+#define GL_DEFINE_EXTENSION(EXTENSION)
+#endif
+
+/* NOTE: this is auto-generated code -- do not edit! */
+
+EGL_PROTO_BEGIN(CreateImageKHR, EGLImageKHR, KHR_image_base)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(ctx, EGLContext),
+EGL_PROTO_ARG(target, EGLenum),
+EGL_PROTO_ARG(buffer, EGLClientBuffer),
+EGL_PROTO_ARG(attrib_list, const EGLint *))
+EGL_PROTO_INVOKE(CreateImageKHR, EGLImageKHR, (dpy, ctx, target, buffer, attrib_list))
+EGL_PROTO_END()
+
+EGL_PROTO_BEGIN(DestroyImageKHR, EGLImageKHR, KHR_image_base)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(image, EGLImageKHR))
+EGL_PROTO_INVOKE(DestroyImageKHR, EGLImageKHR, (dpy, image))
+EGL_PROTO_END()
+
+EGL_PROTO_BEGIN(CreateDRMImageMESA, EGLImageKHR, MESA_drm_image)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(attrib_list, const EGLint *))
+EGL_PROTO_INVOKE(CreateDRMImageMESA, EGLImageKHR, (dpy, attrib_list))
+EGL_PROTO_END()
+
+EGL_PROTO_BEGIN(ExportDRMImageMESA, EGLImageKHR, MESA_drm_image)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(image, EGLImageKHR),
+EGL_PROTO_ARG(name, EGLint *),
+EGL_PROTO_ARG(handle, EGLint *),
+EGL_PROTO_ARG(stride, EGLint *))
+EGL_PROTO_INVOKE(ExportDRMImageMESA, EGLImageKHR, (dpy, image, name, handle, stride))
+EGL_PROTO_END()
+
+EGL_PROTO_BEGIN(ExportDMABUFImageMESA, EGLBoolean, MESA_image_dma_buf_export)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(image, EGLImageKHR),
+EGL_PROTO_ARG(fds, int *),
+EGL_PROTO_ARG(strides, EGLint *),
+EGL_PROTO_ARG(offsets, EGLint *))
+EGL_PROTO_INVOKE(ExportDMABUFImageMESA, EGLBoolean, (dpy, image, fds, strides, offsets))
+EGL_PROTO_END()
+
+EGL_PROTO_BEGIN(ExportDMABUFImageQueryMESA, EGLBoolean, MESA_image_dma_buf_export)
+EGL_PROTO_ARG_LIST(
+EGL_PROTO_ARG(dpy, EGLDisplay),
+EGL_PROTO_ARG(image, EGLImageKHR),
+EGL_PROTO_ARG(fourcc, int *),
+EGL_PROTO_ARG(num_planes, int *),
+EGL_PROTO_ARG(modifiers, EGLuint64KHR *))
+EGL_PROTO_INVOKE(ExportDMABUFImageQueryMESA, EGLBoolean, (dpy, image, fourcc, num_planes, modifiers))
+EGL_PROTO_END()
+
+EGL_DEFINE_EXTENSION(EXT_image_dma_buf_import)
+EGL_DEFINE_EXTENSION(KHR_create_context)
+EGL_DEFINE_EXTENSION(KHR_gl_texture_2D_image)
+EGL_DEFINE_EXTENSION(KHR_image_base)
+EGL_DEFINE_EXTENSION(KHR_surfaceless_context)
+EGL_DEFINE_EXTENSION(MESA_configless_context)
+EGL_DEFINE_EXTENSION(MESA_drm_image)
+EGL_DEFINE_EXTENSION(MESA_image_dma_buf_export)
+
+GL_PROTO_BEGIN(GetError, GLenum, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(GetError, GLenum, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetString, const GLubyte *, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(name, GLenum))
+GL_PROTO_INVOKE(GetString, const GLubyte *, (name))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetIntegerv, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, GLint *))
+GL_PROTO_INVOKE(GetIntegerv, void, (pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Enable, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(cap, GLenum))
+GL_PROTO_INVOKE(Enable, void, (cap))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Disable, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(cap, GLenum))
+GL_PROTO_INVOKE(Disable, void, (cap))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(IsEnabled, GLboolean, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(cap, GLenum))
+GL_PROTO_INVOKE(IsEnabled, GLboolean, (cap))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Finish, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(Finish, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Flush, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(Flush, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Begin, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mode, GLenum))
+GL_PROTO_INVOKE(Begin, void, (mode))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(End, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(End, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Color4f, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(red, GLfloat),
+GL_PROTO_ARG(green, GLfloat),
+GL_PROTO_ARG(blue, GLfloat),
+GL_PROTO_ARG(alpha, GLfloat))
+GL_PROTO_INVOKE(Color4f, void, (red, green, blue, alpha))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Clear, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mask, GLbitfield))
+GL_PROTO_INVOKE(Clear, void, (mask))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(ClearColor, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(red, GLclampf),
+GL_PROTO_ARG(green, GLclampf),
+GL_PROTO_ARG(blue, GLclampf),
+GL_PROTO_ARG(alpha, GLclampf))
+GL_PROTO_INVOKE(ClearColor, void, (red, green, blue, alpha))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PushMatrix, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(PushMatrix, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PopMatrix, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(PopMatrix, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(LoadIdentity, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(LoadIdentity, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(MatrixMode, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mode, GLenum))
+GL_PROTO_INVOKE(MatrixMode, void, (mode))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PushAttrib, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mask, GLbitfield))
+GL_PROTO_INVOKE(PushAttrib, void, (mask))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PopAttrib, void, CORE_1_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(PopAttrib, void, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Viewport, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(x, GLint),
+GL_PROTO_ARG(y, GLint),
+GL_PROTO_ARG(width, GLsizei),
+GL_PROTO_ARG(height, GLsizei))
+GL_PROTO_INVOKE(Viewport, void, (x, y, width, height))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Frustum, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(left, GLdouble),
+GL_PROTO_ARG(right, GLdouble),
+GL_PROTO_ARG(bottom, GLdouble),
+GL_PROTO_ARG(top, GLdouble),
+GL_PROTO_ARG(zNear, GLdouble),
+GL_PROTO_ARG(zFar, GLdouble))
+GL_PROTO_INVOKE(Frustum, void, (left, right, bottom, top, zNear, zFar))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Scalef, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(x, GLfloat),
+GL_PROTO_ARG(y, GLfloat),
+GL_PROTO_ARG(z, GLfloat))
+GL_PROTO_INVOKE(Scalef, void, (x, y, z))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Translatef, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(x, GLfloat),
+GL_PROTO_ARG(y, GLfloat),
+GL_PROTO_ARG(z, GLfloat))
+GL_PROTO_INVOKE(Translatef, void, (x, y, z))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(EnableClientState, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(array, GLenum))
+GL_PROTO_INVOKE(EnableClientState, void, (array))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DisableClientState, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(array, GLenum))
+GL_PROTO_INVOKE(DisableClientState, void, (array))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexCoordPointer, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(size, GLint),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(stride, GLsizei),
+GL_PROTO_ARG(pointer, const GLvoid *))
+GL_PROTO_INVOKE(TexCoordPointer, void, (size, type, stride, pointer))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(VertexPointer, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(size, GLint),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(stride, GLsizei),
+GL_PROTO_ARG(pointer, const GLvoid *))
+GL_PROTO_INVOKE(VertexPointer, void, (size, type, stride, pointer))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(EnableVertexAttribArray, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(index, GLuint))
+GL_PROTO_INVOKE(EnableVertexAttribArray, void, (index))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DisableVertexAttribArray, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(index, GLuint))
+GL_PROTO_INVOKE(DisableVertexAttribArray, void, (index))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetVertexAttribPointerv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(index, GLuint),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(pointer, GLvoid **))
+GL_PROTO_INVOKE(GetVertexAttribPointerv, void, (index, pname, pointer))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(VertexAttribPointer, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(index, GLuint),
+GL_PROTO_ARG(size, GLint),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(normalized, GLboolean),
+GL_PROTO_ARG(stride, GLsizei),
+GL_PROTO_ARG(pointer, const GLvoid *))
+GL_PROTO_INVOKE(VertexAttribPointer, void, (index, size, type, normalized, stride, pointer))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DrawArrays, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(mode, GLenum),
+GL_PROTO_ARG(first, GLint),
+GL_PROTO_ARG(count, GLsizei))
+GL_PROTO_INVOKE(DrawArrays, void, (mode, first, count))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GenTextures, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(n, GLsizei),
+GL_PROTO_ARG(textures, GLuint *))
+GL_PROTO_INVOKE(GenTextures, void, (n, textures))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DeleteTextures, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(n, GLsizei),
+GL_PROTO_ARG(textures, const GLuint *))
+GL_PROTO_INVOKE(DeleteTextures, void, (n, textures))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(BindTexture, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(texture, GLuint))
+GL_PROTO_INVOKE(BindTexture, void, (target, texture))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(ActiveTexture, void, CORE_1_3)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(texture, GLenum))
+GL_PROTO_INVOKE(ActiveTexture, void, (texture))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetTexLevelParameteriv, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(level, GLint),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, GLint *))
+GL_PROTO_INVOKE(GetTexLevelParameteriv, void, (target, level, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexParameterf, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(param, GLfloat))
+GL_PROTO_INVOKE(TexParameterf, void, (target, pname, param))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexParameterfv, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, const GLfloat *))
+GL_PROTO_INVOKE(TexParameterfv, void, (target, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexParameteri, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(param, GLint))
+GL_PROTO_INVOKE(TexParameteri, void, (target, pname, param))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexParameteriv, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, const GLint *))
+GL_PROTO_INVOKE(TexParameteriv, void, (target, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexImage2D, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(level, GLint),
+GL_PROTO_ARG(internalformat, GLint),
+GL_PROTO_ARG(width, GLsizei),
+GL_PROTO_ARG(height, GLsizei),
+GL_PROTO_ARG(border, GLint),
+GL_PROTO_ARG(format, GLenum),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(pixels, const GLvoid *))
+GL_PROTO_INVOKE(TexImage2D, void, (target, level, internalformat, width, height, border, format, type, pixels))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(TexSubImage2D, void, CORE_1_1)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(level, GLint),
+GL_PROTO_ARG(xoffset, GLint),
+GL_PROTO_ARG(yoffset, GLint),
+GL_PROTO_ARG(width, GLsizei),
+GL_PROTO_ARG(height, GLsizei),
+GL_PROTO_ARG(format, GLenum),
+GL_PROTO_ARG(type, GLenum),
+GL_PROTO_ARG(UNUSED, GLuint),
+GL_PROTO_ARG(pixels, const GLvoid *))
+GL_PROTO_INVOKE(TexSubImage2D, void, (target, level, xoffset, yoffset, width, height, format, type, UNUSED, pixels))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PixelStoref, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(param, GLfloat))
+GL_PROTO_INVOKE(PixelStoref, void, (pname, param))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(PixelStorei, void, CORE_1_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(param, GLint))
+GL_PROTO_INVOKE(PixelStorei, void, (pname, param))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(CreateShader, GLuint, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(type, GLenum))
+GL_PROTO_INVOKE(CreateShader, GLuint, (type))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DeleteShader, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint))
+GL_PROTO_INVOKE(DeleteShader, void, (program))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(ShaderSource, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(shader, GLuint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(string, const GLchar * const *),
+GL_PROTO_ARG(length, const GLint *))
+GL_PROTO_INVOKE(ShaderSource, void, (shader, count, string, length))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(CompileShader, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(shader, GLuint))
+GL_PROTO_INVOKE(CompileShader, void, (shader))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetShaderiv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(shader, GLuint),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, GLint *))
+GL_PROTO_INVOKE(GetShaderiv, void, (shader, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetShaderInfoLog, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(shader, GLuint),
+GL_PROTO_ARG(bufSize, GLsizei),
+GL_PROTO_ARG(length, GLsizei *),
+GL_PROTO_ARG(infoLog, GLchar *))
+GL_PROTO_INVOKE(GetShaderInfoLog, void, (shader, bufSize, length, infoLog))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(CreateProgram, GLuint, CORE_2_0)
+GL_PROTO_ARG_LIST()
+GL_PROTO_INVOKE(CreateProgram, GLuint, ())
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(DeleteProgram, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint))
+GL_PROTO_INVOKE(DeleteProgram, void, (program))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(AttachShader, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(shader, GLuint))
+GL_PROTO_INVOKE(AttachShader, void, (program, shader))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(LinkProgram, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint))
+GL_PROTO_INVOKE(LinkProgram, void, (program))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(UseProgram, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint))
+GL_PROTO_INVOKE(UseProgram, void, (program))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetProgramiv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(pname, GLenum),
+GL_PROTO_ARG(params, GLint *))
+GL_PROTO_INVOKE(GetProgramiv, void, (program, pname, params))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetProgramInfoLog, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(bufSize, GLsizei),
+GL_PROTO_ARG(length, GLsizei *),
+GL_PROTO_ARG(infoLog, GLchar *))
+GL_PROTO_INVOKE(GetProgramInfoLog, void, (program, bufSize, length, infoLog))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(BindAttribLocation, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(index, GLuint),
+GL_PROTO_ARG(name, const GLchar *))
+GL_PROTO_INVOKE(BindAttribLocation, void, (program, index, name))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(GetUniformLocation, GLint, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(program, GLuint),
+GL_PROTO_ARG(name, const GLchar *))
+GL_PROTO_INVOKE(GetUniformLocation, GLint, (program, name))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform1f, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLfloat))
+GL_PROTO_INVOKE(Uniform1f, void, (location, v0))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform1fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(Uniform1fv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform1i, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLint))
+GL_PROTO_INVOKE(Uniform1i, void, (location, v0))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform1iv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLint *))
+GL_PROTO_INVOKE(Uniform1iv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform2f, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLfloat),
+GL_PROTO_ARG(v1, GLfloat))
+GL_PROTO_INVOKE(Uniform2f, void, (location, v0, v1))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform2fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(Uniform2fv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform2i, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLint),
+GL_PROTO_ARG(v1, GLint))
+GL_PROTO_INVOKE(Uniform2i, void, (location, v0, v1))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform2iv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLint *))
+GL_PROTO_INVOKE(Uniform2iv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform3f, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLfloat),
+GL_PROTO_ARG(v1, GLfloat),
+GL_PROTO_ARG(v2, GLfloat))
+GL_PROTO_INVOKE(Uniform3f, void, (location, v0, v1, v2))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform3fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(Uniform3fv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform3i, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLint),
+GL_PROTO_ARG(v1, GLint),
+GL_PROTO_ARG(v2, GLint))
+GL_PROTO_INVOKE(Uniform3i, void, (location, v0, v1, v2))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform3iv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLint *))
+GL_PROTO_INVOKE(Uniform3iv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform4f, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLfloat),
+GL_PROTO_ARG(v1, GLfloat),
+GL_PROTO_ARG(v2, GLfloat),
+GL_PROTO_ARG(v3, GLfloat))
+GL_PROTO_INVOKE(Uniform4f, void, (location, v0, v1, v2, v3))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform4fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(Uniform4fv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform4i, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(v0, GLint),
+GL_PROTO_ARG(v1, GLint),
+GL_PROTO_ARG(v2, GLint),
+GL_PROTO_ARG(v3, GLint))
+GL_PROTO_INVOKE(Uniform4i, void, (location, v0, v1, v2, v3))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(Uniform4iv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(value, const GLint *))
+GL_PROTO_INVOKE(Uniform4iv, void, (location, count, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(UniformMatrix2fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(transpose, GLboolean),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(UniformMatrix2fv, void, (location, count, transpose, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(UniformMatrix3fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(transpose, GLboolean),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(UniformMatrix3fv, void, (location, count, transpose, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(UniformMatrix4fv, void, CORE_2_0)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(location, GLint),
+GL_PROTO_ARG(count, GLsizei),
+GL_PROTO_ARG(transpose, GLboolean),
+GL_PROTO_ARG(value, const GLfloat *))
+GL_PROTO_INVOKE(UniformMatrix4fv, void, (location, count, transpose, value))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(EGLImageTargetTexture2DOES, void, OES_EGL_image)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(image, void *))
+GL_PROTO_INVOKE(EGLImageTargetTexture2DOES, void, (target, image))
+GL_PROTO_END()
+
+GL_PROTO_BEGIN(EGLImageTargetRenderbufferStorageOES, void, OES_EGL_image)
+GL_PROTO_ARG_LIST(
+GL_PROTO_ARG(target, GLenum),
+GL_PROTO_ARG(image, void *))
+GL_PROTO_INVOKE(EGLImageTargetRenderbufferStorageOES, void, (target, image))
+GL_PROTO_END()
+
+GL_DEFINE_EXTENSION(CORE_1_0)
+GL_DEFINE_EXTENSION(CORE_1_1)
+GL_DEFINE_EXTENSION(CORE_1_3)
+GL_DEFINE_EXTENSION(CORE_2_0)
+GL_DEFINE_EXTENSION(OES_EGL_image)
+
+#undef EGL_PROTO_BEGIN
+#undef EGL_PROTO_BEGIN_I
+#undef EGL_PROTO_ARG_LIST
+#undef EGL_PROTO_ARG
+#undef EGL_PROTO_INVOKE
+#undef EGL_PROTO_INVOKE_I
+#undef EGL_PROTO_END
+#undef EGL_DEFINE_EXTENSION
+#undef EGL_DEFINE_EXTENSION_I
+
+#undef GL_PROTO_BEGIN
+#undef GL_PROTO_BEGIN_I
+#undef GL_PROTO_ARG_LIST
+#undef GL_PROTO_ARG
+#undef GL_PROTO_INVOKE
+#undef GL_PROTO_INVOKE_I
+#undef GL_PROTO_END
+#undef GL_DEFINE_EXTENSION
+#undef GL_DEFINE_EXTENSION_I
+
+#undef GL_PROTO_GEN_CONCAT5
+#undef GL_PROTO_GEN_CONCAT5_I
+#undef GL_PROTO_GEN_CONCAT4
+#undef GL_PROTO_GEN_CONCAT4_I
+#undef GL_PROTO_GEN_CONCAT3
+#undef GL_PROTO_GEN_CONCAT3_I
+#undef GL_PROTO_GEN_CONCAT2
+#undef GL_PROTO_GEN_CONCAT2_I
+#undef GL_PROTO_GEN_CONCAT
+#undef GL_PROTO_GEN_STRING
+#undef GL_PROTO_GEN_STRING_I
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiblend.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiblend.c
new file mode 100644 (file)
index 0000000..94be040
--- /dev/null
@@ -0,0 +1,329 @@
+/*
+ *  gstvaapiblend.c - Video processing blend
+ *
+ *  Copyright (C) 2019 Intel Corporation
+ *    Author: U. Artie Eoff <ullysses.a.eoff@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiblend.h"
+#include "gstvaapiutils.h"
+#include "gstvaapivalue.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapisurface_priv.h"
+
+struct _GstVaapiBlend
+{
+  GstObject parent_instance;
+
+  GstVaapiDisplay *display;
+
+  VAConfigID va_config;
+  VAContextID va_context;
+
+  guint32 flags;
+};
+
+typedef struct _GstVaapiBlendClass GstVaapiBlendClass;
+struct _GstVaapiBlendClass
+{
+  GstObjectClass parent_class;
+};
+
+GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_blend);
+#ifndef GST_DISABLE_GST_DEBUG
+#define GST_CAT_DEFAULT gst_debug_vaapi_blend
+#else
+#define GST_CAT_DEFAULT NULL
+#endif
+
+G_DEFINE_TYPE_WITH_CODE (GstVaapiBlend, gst_vaapi_blend, GST_TYPE_OBJECT,
+    GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_blend, "vaapiblend", 0,
+        "VA-API Blend"));
+
+enum
+{
+  PROP_DISPLAY = 1,
+};
+
+static void
+gst_vaapi_blend_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiBlend *const blend = GST_VAAPI_BLEND (object);
+
+  switch (property_id) {
+    case PROP_DISPLAY:{
+      GstVaapiDisplay *display = g_value_get_object (value);;
+      if (display) {
+        if (GST_VAAPI_DISPLAY_HAS_VPP (display)) {
+          blend->display = gst_object_ref (display);
+        } else {
+          GST_WARNING_OBJECT (blend, "GstVaapiDisplay doesn't support VPP");
+        }
+      }
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_blend_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiBlend *const blend = GST_VAAPI_BLEND (object);
+
+  switch (property_id) {
+    case PROP_DISPLAY:
+      g_value_set_object (value, blend->display);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_blend_finalize (GObject * object)
+{
+  GstVaapiBlend *const blend = GST_VAAPI_BLEND (object);
+
+  if (!blend->display)
+    goto bail;
+
+  GST_VAAPI_DISPLAY_LOCK (blend->display);
+
+  if (blend->va_context != VA_INVALID_ID) {
+    vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (blend->display),
+        blend->va_context);
+    blend->va_context = VA_INVALID_ID;
+  }
+
+  if (blend->va_config != VA_INVALID_ID) {
+    vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (blend->display),
+        blend->va_config);
+    blend->va_config = VA_INVALID_ID;
+  }
+
+  GST_VAAPI_DISPLAY_UNLOCK (blend->display);
+
+  gst_vaapi_display_replace (&blend->display, NULL);
+
+bail:
+  G_OBJECT_CLASS (gst_vaapi_blend_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_blend_class_init (GstVaapiBlendClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = gst_vaapi_blend_set_property;
+  object_class->get_property = gst_vaapi_blend_get_property;
+  object_class->finalize = gst_vaapi_blend_finalize;
+
+  g_object_class_install_property (object_class, PROP_DISPLAY,
+      g_param_spec_object ("display", "Gst VA-API Display",
+          "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME));
+}
+
+static void
+gst_vaapi_blend_init (GstVaapiBlend * blend)
+{
+  blend->display = NULL;
+  blend->va_config = VA_INVALID_ID;
+  blend->va_context = VA_INVALID_ID;
+  blend->flags = 0;
+}
+
+static gboolean
+gst_vaapi_blend_initialize (GstVaapiBlend * blend)
+{
+  VAStatus status;
+  VAProcPipelineCaps pipeline_caps = { 0, };
+
+  if (!blend->display)
+    return FALSE;
+
+  status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (blend->display),
+      VAProfileNone, VAEntrypointVideoProc, NULL, 0, &blend->va_config);
+  if (!vaapi_check_status (status, "vaCreateConfig() [VPP]"))
+    return FALSE;
+
+  status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (blend->display),
+      blend->va_config, 0, 0, 0, NULL, 0, &blend->va_context);
+  if (!vaapi_check_status (status, "vaCreateContext() [VPP]"))
+    return FALSE;
+
+#if VA_CHECK_VERSION(1,1,0)
+  status =
+      vaQueryVideoProcPipelineCaps (GST_VAAPI_DISPLAY_VADISPLAY
+      (blend->display), blend->va_context, NULL, 0, &pipeline_caps);
+  if (vaapi_check_status (status, "vaQueryVideoProcPipelineCaps()"))
+    blend->flags = pipeline_caps.blend_flags;
+
+  if (!(blend->flags & VA_BLEND_GLOBAL_ALPHA)) {
+    GST_WARNING_OBJECT (blend, "VPP does not support global alpha blending");
+    return FALSE;
+  }
+#else
+  return FALSE;
+#endif
+
+  return TRUE;
+}
+
+GstVaapiBlend *
+gst_vaapi_blend_new (GstVaapiDisplay * display)
+{
+  GstVaapiBlend *blend = g_object_new (GST_TYPE_VAAPI_BLEND,
+      "display", display, NULL);
+
+  if (!gst_vaapi_blend_initialize (blend)) {
+    gst_object_unref (blend);
+    blend = NULL;
+  }
+
+  return blend;
+}
+
+void
+gst_vaapi_blend_replace (GstVaapiBlend ** old_blend_ptr,
+    GstVaapiBlend * new_blend)
+{
+  g_return_if_fail (old_blend_ptr != NULL);
+
+  gst_object_replace ((GstObject **) old_blend_ptr, GST_OBJECT (new_blend));
+}
+
+static gboolean
+gst_vaapi_blend_process_unlocked (GstVaapiBlend * blend,
+    GstVaapiSurface * output, GstVaapiBlendSurfaceNextFunc next,
+    gpointer user_data)
+{
+  VAStatus va_status;
+  VADisplay va_display;
+  GstVaapiBlendSurface *current;
+
+  va_display = GST_VAAPI_DISPLAY_VADISPLAY (blend->display);
+
+  va_status = vaBeginPicture (va_display, blend->va_context,
+      GST_VAAPI_SURFACE_ID (output));
+  if (!vaapi_check_status (va_status, "vaBeginPicture()"))
+    return FALSE;
+
+  current = next (user_data);
+  for (; current; current = next (user_data)) {
+    VAProcPipelineParameterBuffer *param = NULL;
+    VABufferID id = VA_INVALID_ID;
+    VARectangle src_rect = { 0, };
+    VARectangle dst_rect = { 0, };
+#if VA_CHECK_VERSION(1,1,0)
+    VABlendState blend_state;
+#endif
+
+    if (!current->surface)
+      return FALSE;
+
+    /* Build surface region (source) */
+    src_rect.width = GST_VAAPI_SURFACE_WIDTH (current->surface);
+    src_rect.height = GST_VAAPI_SURFACE_HEIGHT (current->surface);
+    if (current->crop) {
+      if ((current->crop->x + current->crop->width > src_rect.width) ||
+          (current->crop->y + current->crop->height > src_rect.height))
+        return FALSE;
+      src_rect.x = current->crop->x;
+      src_rect.y = current->crop->y;
+      src_rect.width = current->crop->width;
+      src_rect.height = current->crop->height;
+    }
+
+    /* Build output region (target) */
+    dst_rect.x = current->target.x;
+    dst_rect.y = current->target.y;
+    dst_rect.width = current->target.width;
+    dst_rect.height = current->target.height;
+
+    if (!vaapi_create_buffer (va_display, blend->va_context,
+            VAProcPipelineParameterBufferType, sizeof (*param), NULL, &id,
+            (gpointer *) & param))
+      return FALSE;
+
+    memset (param, 0, sizeof (*param));
+
+    param->surface = GST_VAAPI_SURFACE_ID (current->surface);
+    param->surface_region = &src_rect;
+    param->output_region = &dst_rect;
+    param->output_background_color = 0xff000000;
+    param->filter_flags = VA_FILTER_SCALING_DEFAULT;
+
+#if VA_CHECK_VERSION(1,1,0)
+    if (current->alpha < 1.0) {
+      blend_state.flags = VA_BLEND_GLOBAL_ALPHA;
+      blend_state.global_alpha = current->alpha;
+      param->blend_state = &blend_state;
+    }
+#endif
+
+    vaapi_unmap_buffer (va_display, id, NULL);
+
+    va_status = vaRenderPicture (va_display, blend->va_context, &id, 1);
+    vaapi_destroy_buffer (va_display, &id);
+    if (!vaapi_check_status (va_status, "vaRenderPicture()"))
+      return FALSE;
+  }
+
+  va_status = vaEndPicture (va_display, blend->va_context);
+  if (!vaapi_check_status (va_status, "vaEndPicture()"))
+    return FALSE;
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_blend_process:
+ * @blend: a #GstVaapiBlend instance.
+ * @output: a #GstVaapiSurface to be composed.
+ * @next: a function to fetch the next #GstVaapiBlendSurface to
+ *    process.
+ * @data: state storage for @next.
+ *
+ * This function will process all the input surfaces defined through
+ * #GstVaapiBlendSurface and will blend them onto the @output surface.
+ *
+ * Returns: %TRUE if the blend process succeed; otherwise %FALSE.
+ **/
+gboolean
+gst_vaapi_blend_process (GstVaapiBlend * blend, GstVaapiSurface * output,
+    GstVaapiBlendSurfaceNextFunc next, gpointer user_data)
+{
+  gboolean result;
+
+  g_return_val_if_fail (blend != NULL, FALSE);
+  g_return_val_if_fail (output != NULL, FALSE);
+  g_return_val_if_fail (next != NULL, FALSE);
+
+  GST_VAAPI_DISPLAY_LOCK (blend->display);
+  result = gst_vaapi_blend_process_unlocked (blend, output, next, user_data);
+  GST_VAAPI_DISPLAY_UNLOCK (blend->display);
+
+  return result;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiblend.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiblend.h
new file mode 100644 (file)
index 0000000..8c94128
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  gstvaapiblend.h - Video processing blend
+ *
+ *  Copyright (C) 2019 Intel Corporation
+ *    Author: U. Artie Eoff <ullysses.a.eoff@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_BLEND_H
+#define GST_VAAPI_BLEND_H
+
+#include <gst/vaapi/gstvaapisurface.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_BLEND \
+  (gst_vaapi_blend_get_type ())
+#define GST_VAAPI_BLEND(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_BLEND, GstVaapiBlend))
+#define GST_IS_VAAPI_BLEND(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_BLEND))
+
+typedef struct _GstVaapiBlend GstVaapiBlend;
+typedef struct _GstVaapiBlendSurface GstVaapiBlendSurface;
+
+struct _GstVaapiBlendSurface
+{
+  GstVaapiSurface const *surface;
+  const GstVaapiRectangle *crop;
+  GstVaapiRectangle target;
+  gdouble alpha;
+};
+
+typedef GstVaapiBlendSurface* (*GstVaapiBlendSurfaceNextFunc)(gpointer data);
+
+GstVaapiBlend *
+gst_vaapi_blend_new (GstVaapiDisplay * display);
+
+void
+gst_vaapi_blend_replace (GstVaapiBlend ** old_blend_ptr,
+    GstVaapiBlend * new_blend);
+
+gboolean
+gst_vaapi_blend_process (GstVaapiBlend * blend, GstVaapiSurface * output,
+    GstVaapiBlendSurfaceNextFunc next, gpointer user_data);
+
+GType
+gst_vaapi_blend_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiBlend, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_FILTER_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapibufferproxy.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapibufferproxy.c
new file mode 100644 (file)
index 0000000..71547ee
--- /dev/null
@@ -0,0 +1,297 @@
+/*
+ *  gstvaapibufferproxy.c - Buffer proxy abstraction
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapibufferproxy.h"
+#include "gstvaapibufferproxy_priv.h"
+#include "gstvaapisurface_priv.h"
+#include "gstvaapiutils.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+static gboolean
+gst_vaapi_buffer_proxy_acquire_handle (GstVaapiBufferProxy * proxy)
+{
+  GstVaapiDisplay *display;
+  const guint mem_type = proxy->va_info.mem_type;
+  VAStatus va_status;
+
+  if (proxy->va_info.handle)
+    return TRUE;
+
+  if (!proxy->surface || proxy->va_buf == VA_INVALID_ID)
+    return FALSE;
+
+  display = GST_VAAPI_SURFACE_DISPLAY (GST_VAAPI_SURFACE (proxy->surface));
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  va_status = vaAcquireBufferHandle (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      proxy->va_buf, &proxy->va_info);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (va_status, "vaAcquireBufferHandle()"))
+    return FALSE;
+  if (proxy->va_info.mem_type != mem_type)
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_buffer_proxy_release_handle (GstVaapiBufferProxy * proxy)
+{
+  GstVaapiDisplay *display;
+  VAStatus va_status;
+
+  if (!proxy->va_info.handle)
+    return TRUE;
+
+  if (!proxy->surface || proxy->va_buf == VA_INVALID_ID)
+    return FALSE;
+
+  display = GST_VAAPI_SURFACE_DISPLAY (GST_VAAPI_SURFACE (proxy->surface));
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  va_status = vaReleaseBufferHandle (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      proxy->va_buf);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (va_status, "vaReleaseBufferHandle()"))
+    return FALSE;
+  return TRUE;
+}
+
+static void
+gst_vaapi_buffer_proxy_finalize (GstVaapiBufferProxy * proxy)
+{
+  gst_vaapi_buffer_proxy_release_handle (proxy);
+
+  /* Notify the user function that the object is now destroyed */
+  if (proxy->destroy_func)
+    proxy->destroy_func (proxy->destroy_data);
+
+  proxy->surface = NULL;
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_buffer_proxy_class (void)
+{
+  static const GstVaapiMiniObjectClass GstVaapiBufferProxyClass = {
+    sizeof (GstVaapiBufferProxy),
+    (GDestroyNotify) gst_vaapi_buffer_proxy_finalize
+  };
+  return &GstVaapiBufferProxyClass;
+}
+
+GstVaapiBufferProxy *
+gst_vaapi_buffer_proxy_new (guintptr handle, guint type, gsize size,
+    GDestroyNotify destroy_func, gpointer user_data)
+{
+  GstVaapiBufferProxy *proxy;
+
+  g_return_val_if_fail (handle != 0, NULL);
+  g_return_val_if_fail (size > 0, NULL);
+
+  proxy = (GstVaapiBufferProxy *)
+      gst_vaapi_mini_object_new (gst_vaapi_buffer_proxy_class ());
+  if (!proxy)
+    return NULL;
+
+  proxy->surface = NULL;
+  proxy->destroy_func = destroy_func;
+  proxy->destroy_data = user_data;
+  proxy->type = type;
+  proxy->va_buf = VA_INVALID_ID;
+  proxy->va_info.handle = handle;
+  proxy->va_info.type = VAImageBufferType;
+  proxy->va_info.mem_type = from_GstVaapiBufferMemoryType (proxy->type);
+  proxy->va_info.mem_size = size;
+  if (!proxy->va_info.mem_type)
+    goto error_unsupported_mem_type;
+  return proxy;
+
+  /* ERRORS */
+error_unsupported_mem_type:
+  {
+    GST_ERROR ("unsupported buffer type (%d)", proxy->type);
+    gst_vaapi_buffer_proxy_unref (proxy);
+    return NULL;
+  }
+}
+
+GstVaapiBufferProxy *
+gst_vaapi_buffer_proxy_new_from_surface (GstMiniObject * surface,
+    VABufferID buf_id, guint type, GDestroyNotify destroy_func, gpointer data)
+{
+  GstVaapiBufferProxy *proxy;
+
+  g_return_val_if_fail (surface != NULL, NULL);
+
+  proxy = (GstVaapiBufferProxy *)
+      gst_vaapi_mini_object_new (gst_vaapi_buffer_proxy_class ());
+  if (!proxy)
+    return NULL;
+
+  proxy->surface = surface;
+  proxy->destroy_func = destroy_func;
+  proxy->destroy_data = data;
+  proxy->type = type;
+  proxy->va_buf = buf_id;
+  memset (&proxy->va_info, 0, sizeof (proxy->va_info));
+  proxy->va_info.mem_type = from_GstVaapiBufferMemoryType (proxy->type);
+  if (!proxy->va_info.mem_type)
+    goto error_unsupported_mem_type;
+  if (!gst_vaapi_buffer_proxy_acquire_handle (proxy))
+    goto error_acquire_handle;
+  return proxy;
+
+  /* ERRORS */
+error_unsupported_mem_type:
+  {
+    GST_ERROR ("unsupported buffer type (%d)", proxy->type);
+    gst_vaapi_buffer_proxy_unref (proxy);
+    return NULL;
+  }
+error_acquire_handle:
+  {
+    GST_ERROR ("failed to acquire the underlying VA buffer handle");
+    gst_vaapi_buffer_proxy_unref (proxy);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_buffer_proxy_ref:
+ * @proxy: a #GstVaapiBufferProxy
+ *
+ * Atomically increases the reference count of the given @proxy by one.
+ *
+ * Returns: The same @proxy argument
+ */
+GstVaapiBufferProxy *
+gst_vaapi_buffer_proxy_ref (GstVaapiBufferProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  return (GstVaapiBufferProxy *)
+      gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (proxy));
+}
+
+/**
+ * gst_vaapi_buffer_proxy_unref:
+ * @proxy: a #GstVaapiBufferProxy
+ *
+ * Atomically decreases the reference count of the @proxy by one. If
+ * the reference count reaches zero, the object will be free'd.
+ */
+void
+gst_vaapi_buffer_proxy_unref (GstVaapiBufferProxy * proxy)
+{
+  g_return_if_fail (proxy != NULL);
+
+  gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (proxy));
+}
+
+/**
+ * gst_vaapi_buffer_proxy_replace:
+ * @old_proxy_ptr: a pointer to a #GstVaapiBufferProxy
+ * @new_proxy: a #GstVaapiBufferProxy
+ *
+ * Atomically replaces the proxy object held in @old_proxy_ptr with
+ * @new_proxy. This means that @old_proxy_ptr shall reference a valid
+ * object. However, @new_proxy can be NULL.
+ */
+void
+gst_vaapi_buffer_proxy_replace (GstVaapiBufferProxy ** old_proxy_ptr,
+    GstVaapiBufferProxy * new_proxy)
+{
+  g_return_if_fail (old_proxy_ptr != NULL);
+
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) (old_proxy_ptr),
+      GST_VAAPI_MINI_OBJECT (new_proxy));
+}
+
+/**
+ * gst_vaapi_buffer_proxy_get_type:
+ * @proxy: a #GstVaapiBufferProxy
+ *
+ * Returns the underlying VA buffer memory type.
+ *
+ * Return value: the buffer memory type
+ */
+guint
+gst_vaapi_buffer_proxy_get_type (GstVaapiBufferProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, 0);
+
+  return GST_VAAPI_BUFFER_PROXY_TYPE (proxy);
+}
+
+/**
+ * gst_vaapi_buffer_proxy_get_handle:
+ * @proxy: a #GstVaapiBufferProxy
+ *
+ * Returns the underlying VA buffer handle stored in the @proxy.
+ *
+ * Return value: the buffer handle
+ */
+guintptr
+gst_vaapi_buffer_proxy_get_handle (GstVaapiBufferProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, 0);
+
+  return GST_VAAPI_BUFFER_PROXY_HANDLE (proxy);
+}
+
+/**
+ * gst_vaapi_buffer_proxy_get_size:
+ * @proxy: a #GstVaapiBufferProxy
+ *
+ * Returns the underlying VA buffer memory size in bytes.
+ *
+ * Return value: the buffer size in bytes
+ */
+gsize
+gst_vaapi_buffer_proxy_get_size (GstVaapiBufferProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, 0);
+
+  return GST_VAAPI_BUFFER_PROXY_SIZE (proxy);
+}
+
+/**
+ * gst_vaapi_buffer_proxy_release_data:
+ * @proxy: a #GstVaapiBufferProxy
+ *
+ * Notifies the user to destroy the user's data, though the @proxy is
+ * not going to be destroyed.
+ **/
+void
+gst_vaapi_buffer_proxy_release_data (GstVaapiBufferProxy * proxy)
+{
+  g_return_if_fail (proxy != NULL);
+
+  if (proxy->destroy_func) {
+    proxy->destroy_func (proxy->destroy_data);
+    proxy->destroy_func = NULL;
+    proxy->destroy_data = NULL;
+  }
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapibufferproxy.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapibufferproxy.h
new file mode 100644 (file)
index 0000000..4b1cebe
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  gstvaapibufferproxy.h - Buffer proxy abstraction
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_BUFFER_PROXY_H
+#define GST_VAAPI_BUFFER_PROXY_H
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_BUFFER_PROXY(obj) \
+  ((GstVaapiBufferProxy *)(obj))
+
+/**
+ * GST_VAAPI_BUFFER_PROXY_TYPE:
+ * @buf: a #GstVaapiBufferProxy
+ *
+ * Macro that evaluates to the type of the underlying VA buffer @buf
+ */
+#define GST_VAAPI_BUFFER_PROXY_TYPE(buf) \
+  gst_vaapi_buffer_proxy_get_type (GST_VAAPI_BUFFER_PROXY (buf))
+
+/**
+ * GST_VAAPI_BUFFER_PROXY_HANDLE:
+ * @buf: a #GstVaapiBufferProxy
+ *
+ * Macro that evaluates to the handle of the underlying VA buffer @buf
+ */
+#define GST_VAAPI_BUFFER_PROXY_HANDLE(buf) \
+  gst_vaapi_buffer_proxy_get_handle (GST_VAAPI_BUFFER_PROXY (buf))
+
+/**
+ * GST_VAAPI_BUFFER_PROXY_SIZE:
+ * @buf: a #GstVaapiBufferProxy
+ *
+ * Macro that evaluates to the size of the underlying VA buffer @buf
+ */
+#define GST_VAAPI_BUFFER_PROXY_SIZE(buf) \
+  gst_vaapi_buffer_proxy_get_size (GST_VAAPI_BUFFER_PROXY (buf))
+
+typedef struct _GstVaapiBufferProxy             GstVaapiBufferProxy;
+
+/**
+ * GstVaapiBufferMemoryType:
+ * @GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF: DRM PRIME buffer memory type (old version).
+ * @GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2: DRM PRIME buffer memory type.
+ * @GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF: Kernel DRM buffer memory type.
+ * @GST_VAAPI_BUFFER_MEMORY_TYPE_V4L2: V4L2 buffer memory type.
+ * @GST_VAAPI_BUFFER_MEMORY_TYPE_USER_PTR: User pointer memory type.
+ *
+ * Set of underlying VA buffer memory types.
+ */
+typedef enum {
+  GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF = 1,
+  GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2,
+  GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF,
+  GST_VAAPI_BUFFER_MEMORY_TYPE_V4L2,
+  GST_VAAPI_BUFFER_MEMORY_TYPE_USER_PTR,
+} GstVaapiBufferMemoryType;
+
+GstVaapiBufferProxy *
+gst_vaapi_buffer_proxy_new (guintptr handle, guint type, gsize size,
+    GDestroyNotify destroy_func, gpointer user_data);
+
+GstVaapiBufferProxy *
+gst_vaapi_buffer_proxy_ref (GstVaapiBufferProxy * proxy);
+
+void
+gst_vaapi_buffer_proxy_unref (GstVaapiBufferProxy * proxy);
+
+void
+gst_vaapi_buffer_proxy_replace (GstVaapiBufferProxy ** old_proxy_ptr,
+    GstVaapiBufferProxy * new_proxy);
+
+guint
+gst_vaapi_buffer_proxy_get_type (GstVaapiBufferProxy * proxy);
+
+guintptr
+gst_vaapi_buffer_proxy_get_handle (GstVaapiBufferProxy * proxy);
+
+gsize
+gst_vaapi_buffer_proxy_get_size (GstVaapiBufferProxy * proxy);
+
+void
+gst_vaapi_buffer_proxy_release_data (GstVaapiBufferProxy * proxy);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_BUFFER_PROXY_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapibufferproxy_priv.h
new file mode 100644 (file)
index 0000000..445201d
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  gstvaapibufferproxy_priv.h - Buffer proxy abstraction (private definitions)
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_BUFFER_PROXY_PRIV_H
+#define GST_VAAPI_BUFFER_PROXY_PRIV_H
+
+#include "gstvaapibufferproxy.h"
+#include "gstvaapiminiobject.h"
+
+G_BEGIN_DECLS
+
+/**
+ * GST_VAAPI_BUFFER_PROXY_TYPE:
+ * @buf: a #GstVaapiBufferProxy
+ *
+ * Macro that evaluates to the type of the underlying VA buffer @buf
+ */
+#undef  GST_VAAPI_BUFFER_PROXY_TYPE
+#define GST_VAAPI_BUFFER_PROXY_TYPE(buf) \
+  (GST_VAAPI_BUFFER_PROXY (buf)->type)
+
+/**
+ * GST_VAAPI_BUFFER_PROXY_HANDLE:
+ * @buf: a #GstVaapiBufferProxy
+ *
+ * Macro that evaluates to the handle of the underlying VA buffer @buf
+ */
+#undef  GST_VAAPI_BUFFER_PROXY_HANDLE
+#define GST_VAAPI_BUFFER_PROXY_HANDLE(buf) \
+  (GST_VAAPI_BUFFER_PROXY (buf)->va_info.handle)
+
+/**
+ * GST_VAAPI_BUFFER_PROXY_SIZE:
+ * @buf: a #GstVaapiBufferProxy
+ *
+ * Macro that evaluates to the size of the underlying VA buffer @buf
+ */
+#undef  GST_VAAPI_BUFFER_PROXY_SIZE
+#define GST_VAAPI_BUFFER_PROXY_SIZE(buf) \
+  (GST_VAAPI_BUFFER_PROXY (buf)->va_info.mem_size)
+
+struct _GstVaapiBufferProxy {
+  /*< private >*/
+  GstVaapiMiniObject    parent_instance;
+  GstMiniObject        *surface;
+
+  GDestroyNotify        destroy_func;
+  gpointer              destroy_data;
+  guint                 type;
+  VABufferID            va_buf;
+  VABufferInfo          va_info;
+};
+
+G_GNUC_INTERNAL
+GstVaapiBufferProxy *
+gst_vaapi_buffer_proxy_new_from_surface (GstMiniObject * surface,
+    VABufferID buf_id, guint type, GDestroyNotify destroy_func, gpointer data);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiBufferMemoryType (guint type);
+
+G_GNUC_INTERNAL
+guint
+to_GstVaapiBufferMemoryType (guint va_type);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_BUFFER_PROXY_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodec_objects.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodec_objects.c
new file mode 100644 (file)
index 0000000..1bdd93b
--- /dev/null
@@ -0,0 +1,255 @@
+/*
+ *  gstvaapicodec_objects.c - VA codec objects abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <gst/vaapi/gstvaapicontext.h>
+#include "gstvaapicodec_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/* ------------------------------------------------------------------------- */
+/* --- Base Codec Object                                                 --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_CODEC_OBJECT_GET_CLASS(object) \
+    gst_vaapi_codec_object_get_class(object)
+
+const GstVaapiCodecObjectClass *
+gst_vaapi_codec_object_get_class (GstVaapiCodecObject * object)
+{
+  return (const GstVaapiCodecObjectClass *)
+      GST_VAAPI_MINI_OBJECT_GET_CLASS (object);
+}
+
+static gboolean
+gst_vaapi_codec_object_create (GstVaapiCodecObject * object,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  const GstVaapiCodecObjectClass *klass;
+
+  g_return_val_if_fail (args->param_size > 0, FALSE);
+
+  if (GST_VAAPI_MINI_OBJECT_FLAG_IS_SET (object,
+          GST_VAAPI_CODEC_OBJECT_FLAG_CONSTRUCTED))
+    return TRUE;
+
+  klass = GST_VAAPI_CODEC_OBJECT_GET_CLASS (object);
+  if (!klass->create || !klass->create (object, args))
+    return FALSE;
+
+  GST_VAAPI_MINI_OBJECT_FLAG_SET (object,
+      GST_VAAPI_CODEC_OBJECT_FLAG_CONSTRUCTED);
+  return TRUE;
+}
+
+GstVaapiCodecObject *
+gst_vaapi_codec_object_new_with_param_num (const GstVaapiCodecObjectClass *
+    object_class, GstVaapiCodecBase * codec, gconstpointer param,
+    guint param_size, guint param_num, gconstpointer data,
+    guint data_size, guint flags)
+{
+  GstVaapiCodecObject *obj;
+  GstVaapiCodecObjectConstructorArgs args;
+
+  obj = (GstVaapiCodecObject *)
+      gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (object_class));
+  if (!obj)
+    return NULL;
+
+  obj = GST_VAAPI_CODEC_OBJECT (obj);
+  obj->codec = codec;
+
+  args.param = param;
+  args.param_size = param_size;
+  args.param_num = param_num;
+  args.data = data;
+  args.data_size = data_size;
+  args.flags = flags;
+
+  if (gst_vaapi_codec_object_create (obj, &args))
+    return obj;
+
+  gst_vaapi_codec_object_unref (obj);
+  return NULL;
+}
+
+GstVaapiCodecObject *
+gst_vaapi_codec_object_new (const GstVaapiCodecObjectClass * object_class,
+    GstVaapiCodecBase * codec, gconstpointer param, guint param_size,
+    gconstpointer data, guint data_size, guint flags)
+{
+  return gst_vaapi_codec_object_new_with_param_num (object_class, codec, param,
+      param_size, 1, data, data_size, flags);
+}
+
+#define GET_DECODER(obj)    GST_VAAPI_DECODER_CAST((obj)->parent_instance.codec)
+#define GET_VA_DISPLAY(obj) GET_DECODER(obj)->va_display
+#define GET_VA_CONTEXT(obj) GET_DECODER(obj)->va_context
+
+/* ------------------------------------------------------------------------- */
+/* --- Inverse Quantization Matrices                                     --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiIqMatrix, gst_vaapi_iq_matrix);
+
+void
+gst_vaapi_iq_matrix_destroy (GstVaapiIqMatrix * iq_matrix)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (iq_matrix), &iq_matrix->param_id);
+  iq_matrix->param = NULL;
+}
+
+gboolean
+gst_vaapi_iq_matrix_create (GstVaapiIqMatrix * iq_matrix,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  iq_matrix->param_id = VA_INVALID_ID;
+  return vaapi_create_buffer (GET_VA_DISPLAY (iq_matrix),
+      GET_VA_CONTEXT (iq_matrix), VAIQMatrixBufferType,
+      args->param_size, args->param, &iq_matrix->param_id, &iq_matrix->param);
+}
+
+GstVaapiIqMatrix *
+gst_vaapi_iq_matrix_new (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiIqMatrixClass,
+      GST_VAAPI_CODEC_BASE (decoder), param, param_size, NULL, 0, 0);
+  if (!object)
+    return NULL;
+  return GST_VAAPI_IQ_MATRIX_CAST (object);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- VC-1 Bit Planes                                                   --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiBitPlane, gst_vaapi_bitplane);
+
+void
+gst_vaapi_bitplane_destroy (GstVaapiBitPlane * bitplane)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (bitplane), &bitplane->data_id);
+  bitplane->data = NULL;
+}
+
+gboolean
+gst_vaapi_bitplane_create (GstVaapiBitPlane * bitplane,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  bitplane->data_id = VA_INVALID_ID;
+  return vaapi_create_buffer (GET_VA_DISPLAY (bitplane),
+      GET_VA_CONTEXT (bitplane), VABitPlaneBufferType, args->param_size,
+      args->param, &bitplane->data_id, (void **) &bitplane->data);
+}
+
+
+GstVaapiBitPlane *
+gst_vaapi_bitplane_new (GstVaapiDecoder * decoder, guint8 * data,
+    guint data_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiBitPlaneClass,
+      GST_VAAPI_CODEC_BASE (decoder), data, data_size, NULL, 0, 0);
+  if (!object)
+    return NULL;
+  return GST_VAAPI_BITPLANE_CAST (object);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- JPEG Huffman Tables                                               --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiHuffmanTable, gst_vaapi_huffman_table);
+
+void
+gst_vaapi_huffman_table_destroy (GstVaapiHuffmanTable * huf_table)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (huf_table), &huf_table->param_id);
+  huf_table->param = NULL;
+}
+
+gboolean
+gst_vaapi_huffman_table_create (GstVaapiHuffmanTable * huf_table,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  huf_table->param_id = VA_INVALID_ID;
+  return vaapi_create_buffer (GET_VA_DISPLAY (huf_table),
+      GET_VA_CONTEXT (huf_table), VAHuffmanTableBufferType, args->param_size,
+      args->param, &huf_table->param_id, (void **) &huf_table->param);
+}
+
+GstVaapiHuffmanTable *
+gst_vaapi_huffman_table_new (GstVaapiDecoder * decoder,
+    guint8 * data, guint data_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiHuffmanTableClass,
+      GST_VAAPI_CODEC_BASE (decoder), data, data_size, NULL, 0, 0);
+  if (!object)
+    return NULL;
+  return GST_VAAPI_HUFFMAN_TABLE_CAST (object);
+}
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiProbabilityTable,
+    gst_vaapi_probability_table);
+
+void
+gst_vaapi_probability_table_destroy (GstVaapiProbabilityTable * prob_table)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (prob_table), &prob_table->param_id);
+  prob_table->param = NULL;
+}
+
+gboolean
+gst_vaapi_probability_table_create (GstVaapiProbabilityTable * prob_table,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  prob_table->param_id = VA_INVALID_ID;
+  return vaapi_create_buffer (GET_VA_DISPLAY (prob_table),
+      GET_VA_CONTEXT (prob_table),
+      VAProbabilityBufferType,
+      args->param_size, args->param, &prob_table->param_id, &prob_table->param);
+}
+
+GstVaapiProbabilityTable *
+gst_vaapi_probability_table_new (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiProbabilityTableClass,
+      GST_VAAPI_CODEC_BASE (decoder), param, param_size, NULL, 0, 0);
+  if (!object)
+    return NULL;
+  return GST_VAAPI_PROBABILITY_TABLE_CAST (object);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodec_objects.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodec_objects.h
new file mode 100644 (file)
index 0000000..ab30dab
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ *  gstvaapicodec_objects.h - VA codec objects abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_CODEC_COMMON_H
+#define GST_VAAPI_CODEC_COMMON_H
+
+#include <gst/vaapi/gstvaapiminiobject.h>
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+typedef gpointer                                GstVaapiCodecBase;
+typedef struct _GstVaapiCodecObject             GstVaapiCodecObject;
+typedef struct _GstVaapiCodecObjectClass        GstVaapiCodecObjectClass;
+typedef struct _GstVaapiIqMatrix                GstVaapiIqMatrix;
+typedef struct _GstVaapiBitPlane                GstVaapiBitPlane;
+typedef struct _GstVaapiHuffmanTable            GstVaapiHuffmanTable;
+typedef struct _GstVaapiProbabilityTable        GstVaapiProbabilityTable;
+
+/* ------------------------------------------------------------------------- */
+/* --- Base Codec Object                                                 --- */
+/* ------------------------------------------------------------------------- */
+
+/* XXX: remove when a common base class for decoder and encoder is available */
+#define GST_VAAPI_CODEC_BASE(obj) \
+  ((GstVaapiCodecBase *) (obj))
+
+#define GST_VAAPI_CODEC_OBJECT(obj) \
+  ((GstVaapiCodecObject *) (obj))
+
+enum
+{
+  GST_VAAPI_CODEC_OBJECT_FLAG_CONSTRUCTED = (1 << 0),
+  GST_VAAPI_CODEC_OBJECT_FLAG_LAST        = (1 << 1)
+};
+
+typedef struct
+{
+  gconstpointer param;
+  guint param_size;
+  guint param_num;
+  gconstpointer data;
+  guint data_size;
+  guint flags;
+} GstVaapiCodecObjectConstructorArgs;
+
+typedef gboolean
+(*GstVaapiCodecObjectCreateFunc)(GstVaapiCodecObject * object,
+    const GstVaapiCodecObjectConstructorArgs * args);
+
+typedef GDestroyNotify GstVaapiCodecObjectDestroyFunc;
+
+/**
+ * GstVaapiCodecObject:
+ *
+ * A #GstVaapiMiniObject holding the base codec object data
+ */
+struct _GstVaapiCodecObject
+{
+  /*< private >*/
+  GstVaapiMiniObject parent_instance;
+  GstVaapiCodecBase *codec;
+};
+
+/**
+ * GstVaapiCodecObjectClass:
+ *
+ * The #GstVaapiCodecObject base class.
+ */
+struct _GstVaapiCodecObjectClass
+{
+  /*< private >*/
+  GstVaapiMiniObjectClass parent_class;
+
+  GstVaapiCodecObjectCreateFunc create;
+};
+
+G_GNUC_INTERNAL
+const GstVaapiCodecObjectClass *
+gst_vaapi_codec_object_get_class (GstVaapiCodecObject * object) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GstVaapiCodecObject *
+gst_vaapi_codec_object_new (const GstVaapiCodecObjectClass * object_class,
+    GstVaapiCodecBase * codec, gconstpointer param, guint param_size,
+    gconstpointer data, guint data_size, guint flags);
+
+G_GNUC_INTERNAL
+GstVaapiCodecObject *
+gst_vaapi_codec_object_new_with_param_num (const GstVaapiCodecObjectClass *
+    object_class, GstVaapiCodecBase * codec, gconstpointer param,
+    guint param_size, guint param_num, gconstpointer data,
+    guint data_size, guint flags);
+
+#define gst_vaapi_codec_object_ref(object) \
+  ((gpointer) gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (object)))
+
+#define gst_vaapi_codec_object_unref(object) \
+  gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (object))
+
+#define gst_vaapi_codec_object_replace(old_object_ptr, new_object) \
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) (old_object_ptr), \
+      GST_VAAPI_MINI_OBJECT (new_object))
+
+/* ------------------------------------------------------------------------- */
+/* --- Inverse Quantization Matrices                                     --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_IQ_MATRIX_CAST(obj) \
+  ((GstVaapiIqMatrix *) (obj))
+
+/**
+ * GstVaapiIqMatrix:
+ *
+ * A #GstVaapiCodecObject holding an inverse quantization matrix parameter.
+ */
+struct _GstVaapiIqMatrix
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+  VABufferID param_id;
+
+  /*< public >*/
+  gpointer param;
+};
+
+G_GNUC_INTERNAL
+GstVaapiIqMatrix *
+gst_vaapi_iq_matrix_new (GstVaapiDecoder * decoder, gconstpointer param,
+    guint param_size);
+
+/* ------------------------------------------------------------------------- */
+/* --- VC-1 Bit Planes                                                   --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_BITPLANE_CAST(obj) \
+  ((GstVaapiBitPlane *) (obj))
+
+/**
+ * GstVaapiBitPlane:
+ *
+ * A #GstVaapiCodecObject holding a VC-1 bit plane parameter.
+ */
+struct _GstVaapiBitPlane
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+  VABufferID data_id;
+
+  /*< public >*/
+  guint8 *data;
+};
+
+G_GNUC_INTERNAL
+GstVaapiBitPlane *
+gst_vaapi_bitplane_new (GstVaapiDecoder * decoder, guint8 * data,
+    guint data_size);
+
+/* ------------------------------------------------------------------------- */
+/* --- JPEG Huffman Tables                                               --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_HUFFMAN_TABLE_CAST(obj) \
+  ((GstVaapiHuffmanTable *) (obj))
+
+/**
+ * GstVaapiHuffmanTable:
+ *
+ * A #GstVaapiCodecObject holding huffman table.
+ */
+struct _GstVaapiHuffmanTable
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+  VABufferID param_id;
+
+  /*< public >*/
+  gpointer param;
+};
+
+G_GNUC_INTERNAL
+GstVaapiHuffmanTable *
+gst_vaapi_huffman_table_new (GstVaapiDecoder * decoder, guint8 * data,
+    guint data_size);
+
+/* ------------------------------------------------------------------------- */
+/* ---                   Probability (Update) Table                      --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_PROBABILITY_TABLE_CAST(obj) \
+    ((GstVaapiProbabilityTable *)(obj))
+
+/**
+ * GstVaapiProbabilityTable:
+ *
+ * A #GstVaapiCodecObject holding an Probability (Update) Table for RAC decoding
+ */
+struct _GstVaapiProbabilityTable
+{
+  /*< private > */
+  GstVaapiCodecObject parent_instance;
+  VABufferID param_id;
+
+  /*< public > */
+  gpointer param;
+};
+
+G_GNUC_INTERNAL
+GstVaapiProbabilityTable *
+gst_vaapi_probability_table_new (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size);
+
+/* ------------------------------------------------------------------------- */
+/* --- Helpers to create codec-dependent objects                         --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_CODEC_DEFINE_TYPE(type, prefix)                       \
+G_GNUC_INTERNAL                                                         \
+void                                                                    \
+G_PASTE (prefix, _destroy) (type *);                                    \
+                                                                        \
+G_GNUC_INTERNAL                                                         \
+gboolean                                                                \
+G_PASTE (prefix, _create) (type *,                                      \
+    const GstVaapiCodecObjectConstructorArgs * args);                   \
+                                                                        \
+static const GstVaapiCodecObjectClass G_PASTE (type, Class) = {         \
+  .parent_class = {                                                     \
+    .size = sizeof (type),                                              \
+    .finalize = (GstVaapiCodecObjectDestroyFunc)                        \
+        G_PASTE (prefix, _destroy)                                      \
+  },                                                                    \
+  .create = (GstVaapiCodecObjectCreateFunc)                             \
+      G_PASTE (prefix, _create),                                        \
+}
+
+#define GST_VAAPI_IQ_MATRIX_NEW(codec, decoder)                         \
+  gst_vaapi_iq_matrix_new (GST_VAAPI_DECODER_CAST (decoder),            \
+      NULL, sizeof (G_PASTE (VAIQMatrixBuffer, codec)))
+
+#define GST_VAAPI_BITPLANE_NEW(decoder, size) \
+  gst_vaapi_bitplane_new (GST_VAAPI_DECODER_CAST (decoder), NULL, size)
+
+#define GST_VAAPI_HUFFMAN_TABLE_NEW(codec, decoder)                     \
+  gst_vaapi_huffman_table_new (GST_VAAPI_DECODER_CAST (decoder),        \
+      NULL, sizeof (G_PASTE (VAHuffmanTableBuffer, codec)))
+
+#define GST_VAAPI_PROBABILITY_TABLE_NEW(codec, decoder)                 \
+  gst_vaapi_probability_table_new (GST_VAAPI_DECODER_CAST (decoder),    \
+      NULL, sizeof (G_PASTE (VAProbabilityDataBuffer, codec)))
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_CODEC_OBJECTS_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbuffer.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbuffer.c
new file mode 100644 (file)
index 0000000..5d5f3a2
--- /dev/null
@@ -0,0 +1,251 @@
+/*
+ *  gstvaapicodedbuffer.c - VA coded buffer abstraction
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicodedbuffer.h"
+#include "gstvaapicodedbuffer_priv.h"
+#include "gstvaapiencoder_priv.h"
+#include "gstvaapiutils.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+static gboolean
+coded_buffer_create (GstVaapiCodedBuffer * buf, guint buf_size,
+    GstVaapiContext * context)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_CODED_BUFFER_DISPLAY (buf);
+  VABufferID buf_id;
+  gboolean success;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  success = vaapi_create_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_CONTEXT_ID (context), VAEncCodedBufferType, buf_size,
+      NULL, &buf_id, NULL);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!success)
+    return FALSE;
+
+  GST_DEBUG ("coded buffer %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (buf_id));
+  GST_VAAPI_CODED_BUFFER_ID (buf) = buf_id;
+  return TRUE;
+}
+
+static void
+coded_buffer_free (GstVaapiCodedBuffer * buf)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_CODED_BUFFER_DISPLAY (buf);
+  VABufferID buf_id;
+
+  buf_id = GST_VAAPI_CODED_BUFFER_ID (buf);
+  GST_DEBUG ("coded buffer %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (buf_id));
+
+  if (buf_id != VA_INVALID_ID) {
+    GST_VAAPI_DISPLAY_LOCK (display);
+    vaapi_destroy_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display), &buf_id);
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+    GST_VAAPI_CODED_BUFFER_ID (buf) = VA_INVALID_ID;
+  }
+
+  gst_vaapi_display_replace (&GST_VAAPI_CODED_BUFFER_DISPLAY (buf), NULL);
+
+  g_slice_free1 (sizeof (GstVaapiCodedBuffer), buf);
+}
+
+static gboolean
+coded_buffer_map (GstVaapiCodedBuffer * buf)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_CODED_BUFFER_DISPLAY (buf);
+
+  if (buf->segment_list)
+    return TRUE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  buf->segment_list =
+      vaapi_map_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_CODED_BUFFER_ID (buf));
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  return buf->segment_list != NULL;
+}
+
+static void
+coded_buffer_unmap (GstVaapiCodedBuffer * buf)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_CODED_BUFFER_DISPLAY (buf);
+
+  if (!buf->segment_list)
+    return;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  vaapi_unmap_buffer (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_CODED_BUFFER_ID (buf), (void **) &buf->segment_list);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+}
+
+GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiCodedBuffer, gst_vaapi_coded_buffer);
+
+/*
+ * gst_vaapi_coded_buffer_new:
+ * @context: the parent #GstVaapiContext object
+ * @buf_size: the buffer size in bytes
+ *
+ * Creates a new VA coded buffer bound to the supplied @context.
+ *
+ * Return value: the newly allocated #GstVaapiCodedBuffer object, or
+ *   %NULL if an error occurred
+ */
+GstVaapiCodedBuffer *
+gst_vaapi_coded_buffer_new (GstVaapiContext * context, guint buf_size)
+{
+  GstVaapiCodedBuffer *buf;
+  GstVaapiDisplay *display;
+
+  g_return_val_if_fail (context != NULL, NULL);
+  g_return_val_if_fail (buf_size > 0, NULL);
+
+  display = GST_VAAPI_CONTEXT_DISPLAY (context);
+  g_return_val_if_fail (display != NULL, NULL);
+
+  buf = g_slice_new (GstVaapiCodedBuffer);
+  if (!buf)
+    return NULL;
+
+  gst_mini_object_init (GST_MINI_OBJECT_CAST (buf), 0,
+      GST_TYPE_VAAPI_CODED_BUFFER, NULL, NULL,
+      (GstMiniObjectFreeFunction) coded_buffer_free);
+
+  GST_VAAPI_CODED_BUFFER_DISPLAY (buf) = gst_object_ref (display);
+  GST_VAAPI_CODED_BUFFER_ID (buf) = VA_INVALID_ID;
+  buf->segment_list = NULL;
+
+  if (!coded_buffer_create (buf, buf_size, context))
+    goto error;
+  return buf;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_coded_buffer_unref (buf);
+    return NULL;
+  }
+}
+
+/*
+ * gst_vaapi_coded_buffer_map:
+ * @buf: a #GstVaapiCodedBuffer
+ * @data: pointer to the mapped buffer data (VACodedBufferSegment)
+ *
+ * Maps the VA coded buffer and returns the data pointer into @data.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ */
+gboolean
+gst_vaapi_coded_buffer_map (GstVaapiCodedBuffer * buf,
+    VACodedBufferSegment ** out_segment_list_ptr)
+{
+  g_return_val_if_fail (buf != NULL, FALSE);
+  g_return_val_if_fail (out_segment_list_ptr != NULL, FALSE);
+
+  if (!coded_buffer_map (buf))
+    return FALSE;
+
+  *out_segment_list_ptr = buf->segment_list;
+  return TRUE;
+}
+
+/*
+ * gst_vaapi_coded_buffer_unmap:
+ * @buf: a #GstVaapiCodedBuffer
+ *
+ * Unamps the VA coded buffer.
+ */
+void
+gst_vaapi_coded_buffer_unmap (GstVaapiCodedBuffer * buf)
+{
+  g_return_if_fail (buf != NULL);
+
+  coded_buffer_unmap (buf);
+}
+
+/**
+ * gst_vaapi_coded_buffer_get_size:
+ * @buf: a #GstVaapiCodedBuffer
+ *
+ * Returns the VA coded buffer size in bytes. That represents the
+ * exact buffer size, as filled in so far, not the size of the
+ * allocated buffer.
+ *
+ * Return value: the size of the VA coded buffer, or -1 on error
+ */
+gssize
+gst_vaapi_coded_buffer_get_size (GstVaapiCodedBuffer * buf)
+{
+  VACodedBufferSegment *segment;
+  gssize size;
+
+  g_return_val_if_fail (buf != NULL, -1);
+
+  if (!coded_buffer_map (buf))
+    return -1;
+
+  size = 0;
+  for (segment = buf->segment_list; segment != NULL; segment = segment->next)
+    size += segment->size;
+
+  coded_buffer_unmap (buf);
+  return size;
+}
+
+/**
+ * gst_vaapi_coded_buffer_copy_into:
+ * @dest: the destination #GstBuffer
+ * @src: the source #GstVaapiCodedBuffer
+ *
+ * Copies the coded buffer data from @src into the regular buffer @dest.
+ *
+ * Return value: %TRUE if successful, %FALSE otherwise
+ */
+gboolean
+gst_vaapi_coded_buffer_copy_into (GstBuffer * dest, GstVaapiCodedBuffer * src)
+{
+  VACodedBufferSegment *segment;
+  goffset offset;
+  gsize size;
+
+  g_return_val_if_fail (src != NULL, FALSE);
+  g_return_val_if_fail (dest != NULL, FALSE);
+
+  if (!coded_buffer_map (src))
+    return FALSE;
+
+  offset = 0;
+  for (segment = src->segment_list; segment != NULL; segment = segment->next) {
+    size = gst_buffer_fill (dest, offset, segment->buf, segment->size);
+    if (size != segment->size)
+      break;
+    offset += segment->size;
+  }
+
+  coded_buffer_unmap (src);
+  return segment == NULL;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbuffer.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbuffer.h
new file mode 100644 (file)
index 0000000..bee4cc4
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  gstvaapicodedbuffer.h - VA coded buffer abstraction
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_CODED_BUFFER_H
+#define GST_VAAPI_CODED_BUFFER_H
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_CODED_BUFFER(obj) \
+  ((GstVaapiCodedBuffer *)(obj))
+
+/**
+ * GST_VAAPI_CODED_BUFFER_SIZE:
+ * @buf: a #GstVaapiCodedBuffer
+ *
+ * Macro that evaluates to the size of the underlying VA coded buffer @buf
+ */
+#define GST_VAAPI_CODED_BUFFER_SIZE(buf) \
+  gst_vaapi_coded_buffer_get_size (GST_VAAPI_CODED_BUFFER(buf))
+
+typedef struct _GstVaapiCodedBuffer             GstVaapiCodedBuffer;
+typedef struct _GstVaapiCodedBufferProxy        GstVaapiCodedBufferProxy;
+typedef struct _GstVaapiCodedBufferPool         GstVaapiCodedBufferPool;
+
+#define GST_TYPE_VAAPI_CODED_BUFFER (gst_vaapi_coded_buffer_get_type ())
+
+GType
+gst_vaapi_coded_buffer_get_type (void) G_GNUC_CONST;
+
+/**
+ * gst_vaapi_coded_buffer_unref: (skip)
+ * @buf: (transfer full): a #GstVaapiCodedBuffer.
+ *
+ * Decreases the refcount of @buf. If the refcount reaches 0, the
+ * @buf will be freed.
+ */
+static inline void
+gst_vaapi_coded_buffer_unref (GstVaapiCodedBuffer * buf)
+{
+  gst_mini_object_unref (GST_MINI_OBJECT_CAST (buf));
+}
+
+gssize
+gst_vaapi_coded_buffer_get_size (GstVaapiCodedBuffer * buf);
+
+gboolean
+gst_vaapi_coded_buffer_copy_into (GstBuffer * dest, GstVaapiCodedBuffer * src);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiCodedBuffer, gst_vaapi_coded_buffer_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_CODED_BUFFER_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbuffer_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbuffer_priv.h
new file mode 100644 (file)
index 0000000..b872b9c
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *  gstvaapicodedbuffer_priv.h - VA coded buffer abstraction (private defs)
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_CODED_BUFFER_PRIV_H
+#define GST_VAAPI_CODED_BUFFER_PRIV_H
+
+#include <gst/vaapi/gstvaapicontext.h>
+#include "gstvaapicodedbuffer.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_CODED_BUFFER_CAST(obj) \
+    ((GstVaapiCodedBuffer *)(obj))
+
+/**
+ * GstVaapiCodedBuffer:
+ *
+ * A VA coded buffer object wrapper.
+ */
+struct _GstVaapiCodedBuffer
+{
+  /*< private >*/
+  GstMiniObject         mini_object;
+  GstVaapiDisplay      *display;
+  GstVaapiID            object_id;
+
+  /*< public >*/
+  VACodedBufferSegment *segment_list;
+};
+
+/**
+ * GST_VAAPI_CODED_BUFFER_DISPLAY:
+ * @buf: a #GstVaapiCodedBuffer
+ *
+ * Macro that evaluates to the #GstVaapiDisplay of @buf
+ */
+#undef GST_VAAPI_CODED_BUFFER_DISPLAY
+#define GST_VAAPI_CODED_BUFFER_DISPLAY(buf) (GST_VAAPI_CODED_BUFFER (buf)->display)
+
+/**
+ * GST_VAAPI_CODED_BUFFER_ID:
+ * @buf: a #GstVaapiCodedBuffer
+ *
+ * Macro that evaluates to the object ID of @buf
+ */
+#undef GST_VAAPI_CODED_BUFFER_ID
+#define GST_VAAPI_CODED_BUFFER_ID(buf) (GST_VAAPI_CODED_BUFFER (buf)->object_id)
+
+G_GNUC_INTERNAL
+GstVaapiCodedBuffer *
+gst_vaapi_coded_buffer_new (GstVaapiContext * context, guint buf_size);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_coded_buffer_map (GstVaapiCodedBuffer * buf,
+    VACodedBufferSegment ** out_segment_list_ptr);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_coded_buffer_unmap (GstVaapiCodedBuffer * buf);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_CODED_BUFFER_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferpool.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferpool.c
new file mode 100644 (file)
index 0000000..3262a94
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *  gstvaapicodedbufferpool.c - VA coded buffer pool
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicodedbufferpool.h"
+#include "gstvaapicodedbuffer_priv.h"
+#include "gstvaapivideopool_priv.h"
+#include "gstvaapiencoder_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/**
+ * GstVaapiCodedBufferPool:
+ *
+ * A pool of lazily allocated #GstVaapiCodedBuffer objects.
+ */
+struct _GstVaapiCodedBufferPool
+{
+  /*< private > */
+  GstVaapiVideoPool parent_instance;
+
+  GstVaapiContext *context;
+  gsize buf_size;
+};
+
+static void
+coded_buffer_pool_init (GstVaapiCodedBufferPool * pool,
+    GstVaapiContext * context, gsize buf_size)
+{
+  pool->context = gst_vaapi_context_ref (context);
+  pool->buf_size = buf_size;
+}
+
+static void
+coded_buffer_pool_finalize (GstVaapiCodedBufferPool * pool)
+{
+  gst_vaapi_video_pool_finalize (GST_VAAPI_VIDEO_POOL (pool));
+  gst_vaapi_context_unref (pool->context);
+  pool->context = NULL;
+}
+
+static gpointer
+coded_buffer_pool_alloc_object (GstVaapiVideoPool * base_pool)
+{
+  GstVaapiCodedBufferPool *const pool = GST_VAAPI_CODED_BUFFER_POOL (base_pool);
+
+  return gst_vaapi_coded_buffer_new (pool->context, pool->buf_size);
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_coded_buffer_pool_class (void)
+{
+  static const GstVaapiVideoPoolClass GstVaapiCodedBufferPoolClass = {
+    {sizeof (GstVaapiCodedBufferPool),
+        (GDestroyNotify) coded_buffer_pool_finalize}
+    ,
+    .alloc_object = coded_buffer_pool_alloc_object
+  };
+  return GST_VAAPI_MINI_OBJECT_CLASS (&GstVaapiCodedBufferPoolClass);
+}
+
+/**
+ * gst_vaapi_coded_buffer_pool_new:
+ * @encoder: a #GstVaapiEncoder
+ * @buf_size: the max size of #GstVaapiCodedBuffer objects, in bytes
+ *
+ * Creates a new #GstVaapiVideoPool of #GstVaapiCodedBuffer objects
+ * with the supplied maximum size in bytes, and bound to the specified
+ * @encoder object.
+ *
+ * Return value: the newly allocated #GstVaapiVideoPool
+ */
+GstVaapiVideoPool *
+gst_vaapi_coded_buffer_pool_new (GstVaapiEncoder * encoder, gsize buf_size)
+{
+  GstVaapiVideoPool *pool;
+  GstVaapiContext *context;
+
+  g_return_val_if_fail (encoder != NULL, NULL);
+  g_return_val_if_fail (buf_size > 0, NULL);
+
+  context = GST_VAAPI_ENCODER_CONTEXT (encoder);
+  g_return_val_if_fail (context != NULL, NULL);
+
+  pool = (GstVaapiVideoPool *)
+      gst_vaapi_mini_object_new (gst_vaapi_coded_buffer_pool_class ());
+  if (!pool)
+    return NULL;
+
+  gst_vaapi_video_pool_init (pool, GST_VAAPI_CONTEXT_DISPLAY (context),
+      GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_CODED_BUFFER);
+  coded_buffer_pool_init (GST_VAAPI_CODED_BUFFER_POOL (pool),
+      context, buf_size);
+  return pool;
+}
+
+/**
+ * gst_vaapi_coded_buffer_pool_get_buffer_size:
+ * @pool: a #GstVaapiCodedBufferPool
+ *
+ * Determines the maximum size of each #GstVaapiCodedBuffer held in
+ * the @pool.
+ *
+ * Return value: size of a #GstVaapiCodedBuffer in @pool
+ */
+gsize
+gst_vaapi_coded_buffer_pool_get_buffer_size (GstVaapiCodedBufferPool * pool)
+{
+  g_return_val_if_fail (pool != NULL, 0);
+
+  return pool->buf_size;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferpool.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferpool.h
new file mode 100644 (file)
index 0000000..c8b9e1b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  gstvaapicodedbufferpool.h - VA coded buffer pool
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_CODED_BUFFER_POOL_H
+#define GST_VAAPI_CODED_BUFFER_POOL_H
+
+#include <gst/vaapi/gstvaapivideopool.h>
+#include <gst/vaapi/gstvaapiencoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_CODED_BUFFER_POOL(obj) \
+    ((GstVaapiCodedBufferPool *)(obj))
+
+struct _GstVaapiEncoder;
+
+GstVaapiVideoPool *
+gst_vaapi_coded_buffer_pool_new (struct _GstVaapiEncoder * encoder,
+    gsize buf_size);
+
+gsize
+gst_vaapi_coded_buffer_pool_get_buffer_size (GstVaapiCodedBufferPool * pool);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_CODED_BUFFER_POOL_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.c
new file mode 100644 (file)
index 0000000..ececae9
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ *  gstvaapicodedbufferproxy.c - VA coded buffer proxy
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicodedbufferproxy.h"
+#include "gstvaapicodedbufferproxy_priv.h"
+#include "gstvaapivideopool_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+static void
+coded_buffer_proxy_set_user_data (GstVaapiCodedBufferProxy * proxy,
+    gpointer user_data, GDestroyNotify destroy_func)
+{
+  if (proxy->user_data_destroy)
+    proxy->user_data_destroy (proxy->user_data);
+
+  proxy->user_data = user_data;
+  proxy->user_data_destroy = destroy_func;
+}
+
+static void
+coded_buffer_proxy_finalize (GstVaapiCodedBufferProxy * proxy)
+{
+  if (proxy->buffer) {
+    if (proxy->pool)
+      gst_vaapi_video_pool_put_object (proxy->pool, proxy->buffer);
+    gst_vaapi_coded_buffer_unref (proxy->buffer);
+    proxy->buffer = NULL;
+  }
+  gst_vaapi_video_pool_replace (&proxy->pool, NULL);
+  coded_buffer_proxy_set_user_data (proxy, NULL, NULL);
+
+  /* Notify the user function that the object is now destroyed */
+  if (proxy->destroy_func)
+    proxy->destroy_func (proxy->destroy_data);
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_coded_buffer_proxy_class (void)
+{
+  static const GstVaapiMiniObjectClass GstVaapiCodedBufferProxyClass = {
+    sizeof (GstVaapiCodedBufferProxy),
+    (GDestroyNotify) coded_buffer_proxy_finalize
+  };
+  return &GstVaapiCodedBufferProxyClass;
+}
+
+/**
+ * gst_vaapi_coded_buffer_proxy_new_from_pool:
+ * @pool: a #GstVaapiCodedBufferPool
+ *
+ * Allocates a new coded buffer from the supplied @pool and creates
+ * the wrapped coded buffer proxy object from it. When the last
+ * reference to the proxy object is released, then the underlying VA
+ * coded buffer is pushed back to its parent pool.
+ *
+ * Returns: The same newly allocated @proxy object, or %NULL on error
+ */
+GstVaapiCodedBufferProxy *
+gst_vaapi_coded_buffer_proxy_new_from_pool (GstVaapiCodedBufferPool * pool)
+{
+  GstVaapiCodedBufferProxy *proxy;
+
+  g_return_val_if_fail (pool != NULL, NULL);
+  g_return_val_if_fail (GST_VAAPI_VIDEO_POOL (pool)->object_type ==
+      GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_CODED_BUFFER, NULL);
+
+  proxy = (GstVaapiCodedBufferProxy *)
+      gst_vaapi_mini_object_new (gst_vaapi_coded_buffer_proxy_class ());
+  if (!proxy)
+    return NULL;
+
+  proxy->destroy_func = NULL;
+  proxy->user_data_destroy = NULL;
+  proxy->pool = gst_vaapi_video_pool_ref (GST_VAAPI_VIDEO_POOL (pool));
+  proxy->buffer = gst_vaapi_video_pool_get_object (proxy->pool);
+  if (!proxy->buffer)
+    goto error;
+  gst_mini_object_ref (GST_MINI_OBJECT_CAST (proxy->buffer));
+  return proxy;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_coded_buffer_proxy_unref (proxy);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_coded_buffer_proxy_ref:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Atomically increases the reference count of the given @proxy by one.
+ *
+ * Returns: The same @proxy argument
+ */
+GstVaapiCodedBufferProxy *
+gst_vaapi_coded_buffer_proxy_ref (GstVaapiCodedBufferProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  return GST_VAAPI_CODED_BUFFER_PROXY (gst_vaapi_mini_object_ref
+      (GST_VAAPI_MINI_OBJECT (proxy)));
+}
+
+/**
+ * gst_vaapi_coded_buffer_proxy_unref:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Atomically decreases the reference count of the @proxy by one. If
+ * the reference count reaches zero, the object will be free'd.
+ */
+void
+gst_vaapi_coded_buffer_proxy_unref (GstVaapiCodedBufferProxy * proxy)
+{
+  g_return_if_fail (proxy != NULL);
+
+  gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (proxy));
+}
+
+/**
+ * gst_vaapi_coded_buffer_proxy_replace:
+ * @old_proxy_ptr: a pointer to a #GstVaapiCodedBufferProxy
+ * @new_proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Atomically replaces the proxy object held in @old_proxy_ptr with
+ * @new_proxy. This means that @old_proxy_ptr shall reference a valid
+ * object. However, @new_proxy can be NULL.
+ */
+void
+gst_vaapi_coded_buffer_proxy_replace (GstVaapiCodedBufferProxy ** old_proxy_ptr,
+    GstVaapiCodedBufferProxy * new_proxy)
+{
+  g_return_if_fail (old_proxy_ptr != NULL);
+
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) old_proxy_ptr,
+      GST_VAAPI_MINI_OBJECT (new_proxy));
+}
+
+/**
+ * gst_vaapi_coded_buffer_proxy_get_buffer:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Returns the #GstVaapiCodedBuffer stored in the @proxy.
+ *
+ * Return value: the #GstVaapiCodedBuffer, or %NULL if an error occurred
+ */
+GstVaapiCodedBuffer *
+gst_vaapi_coded_buffer_proxy_get_buffer (GstVaapiCodedBufferProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  return GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (proxy);
+}
+
+/**
+ * gst_vaapi_coded_buffer_proxy_get_buffer_size:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Returns the size of the underlying #GstVaapiCodedBuffer object
+ * stored in the @proxy.
+ *
+ * Return value: the underlying #GstVaapiCodedBuffer size, or -1 if an
+ *   error occurred
+ */
+gssize
+gst_vaapi_coded_buffer_proxy_get_buffer_size (GstVaapiCodedBufferProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, -1);
+
+  return GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE (proxy);
+}
+
+/**
+ * gst_vaapi_coded_buffer_proxy_set_destroy_notify:
+ * @proxy: a @GstVaapiCodedBufferProxy
+ * @destroy_func: a #GDestroyNotify function
+ * @user_data: some extra data to pass to the @destroy_func function
+ *
+ * Sets @destroy_func as the function to call when the coded buffer
+ * @proxy was released. At this point, the proxy object is considered
+ * released, i.e. the underlying data storage is no longer valid and
+ * the callback function shall not expect anything from that.
+ */
+void
+gst_vaapi_coded_buffer_proxy_set_destroy_notify (GstVaapiCodedBufferProxy *
+    proxy, GDestroyNotify destroy_func, gpointer user_data)
+{
+  g_return_if_fail (proxy != NULL);
+
+  proxy->destroy_func = destroy_func;
+  proxy->destroy_data = user_data;
+}
+
+/**
+ * gst_vaapi_coded_buffer_proxy_get_user_data:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Gets private data previously set on the VA coded buffer proxy
+ * object through the gst_vaapi_coded_buffer_proxy_set_user_data()
+ * function.
+ *
+ * Return value: the previously set user-data
+ */
+gpointer
+gst_vaapi_coded_buffer_proxy_get_user_data (GstVaapiCodedBufferProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  return proxy->user_data;
+}
+
+/**
+ * gst_vaapi_coded_buffer_proxy_set_user_data:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ * @user_data: user-defined data
+ * @destroy_func: a #GDestroyNotify
+ *
+ * Sets @user_data on the VA coded buffer proxy object and the
+ * #GDestroyNotify function that will be called when the coded buffer
+ * proxy object is released.
+ *
+ * If a @user_data was previously set, then the previously set
+ * @destroy_func function, if any, will be called before the
+ * @user_data is replaced.
+ */
+void
+gst_vaapi_coded_buffer_proxy_set_user_data (GstVaapiCodedBufferProxy * proxy,
+    gpointer user_data, GDestroyNotify destroy_func)
+{
+  g_return_if_fail (proxy != NULL);
+
+  coded_buffer_proxy_set_user_data (proxy, user_data, destroy_func);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferproxy.h
new file mode 100644 (file)
index 0000000..4968c63
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *  gstvaapicodedbufferproxy_priv.h - VA coded buffer proxy
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_CODED_BUFFER_PROXY_H
+#define GST_VAAPI_CODED_BUFFER_PROXY_H
+
+#include <gst/vaapi/gstvaapicodedbuffer.h>
+#include <gst/vaapi/gstvaapicodedbufferpool.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GST_VAAPI_CODED_BUFFER_PROXY_BUFFER:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Macro that evaluated to the underlying #GstVaapiCodedBuffer of @proxy.
+ */
+#define GST_VAAPI_CODED_BUFFER_PROXY_BUFFER(proxy) \
+  gst_vaapi_coded_buffer_proxy_get_buffer(proxy)
+
+/**
+ * GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Macro that evaluated to the underlying #GstVaapiCodedBuffer size of
+ * @proxy.
+ */
+#define GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE(proxy) \
+  gst_vaapi_coded_buffer_proxy_get_buffer_size(proxy)
+
+GstVaapiCodedBufferProxy *
+gst_vaapi_coded_buffer_proxy_new_from_pool (GstVaapiCodedBufferPool * pool);
+
+GstVaapiCodedBufferProxy *
+gst_vaapi_coded_buffer_proxy_ref (GstVaapiCodedBufferProxy * proxy);
+
+void
+gst_vaapi_coded_buffer_proxy_unref (GstVaapiCodedBufferProxy * proxy);
+
+void
+gst_vaapi_coded_buffer_proxy_replace (GstVaapiCodedBufferProxy ** old_proxy_ptr,
+    GstVaapiCodedBufferProxy * new_proxy);
+
+GstVaapiCodedBuffer *
+gst_vaapi_coded_buffer_proxy_get_buffer (GstVaapiCodedBufferProxy * proxy);
+
+gssize
+gst_vaapi_coded_buffer_proxy_get_buffer_size (GstVaapiCodedBufferProxy * proxy);
+
+void
+gst_vaapi_coded_buffer_proxy_set_destroy_notify (GstVaapiCodedBufferProxy *
+    proxy, GDestroyNotify destroy_func, gpointer user_data);
+
+gpointer
+gst_vaapi_coded_buffer_proxy_get_user_data (GstVaapiCodedBufferProxy * proxy);
+
+void
+gst_vaapi_coded_buffer_proxy_set_user_data (GstVaapiCodedBufferProxy * proxy,
+    gpointer user_data, GDestroyNotify destroy_func);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_CODED_BUFFER_PROXY_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferproxy_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicodedbufferproxy_priv.h
new file mode 100644 (file)
index 0000000..6feb8f9
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  gstvaapicodedbufferproxy_priv.h - VA coded buffer proxy (private defs)
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_CODED_BUFFER_PROXY_PRIV_H
+#define GST_VAAPI_CODED_BUFFER_PROXY_PRIV_H
+
+#include "gstvaapicodedbuffer_priv.h"
+#include "gstvaapiminiobject.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_CODED_BUFFER_PROXY(proxy) \
+  ((GstVaapiCodedBufferProxy *)(proxy))
+
+struct _GstVaapiCodedBufferProxy
+{
+  /*< private >*/
+  GstVaapiMiniObject parent_instance;
+
+  GstVaapiVideoPool    *pool;
+  GstVaapiCodedBuffer  *buffer;
+  GDestroyNotify        destroy_func;
+  gpointer              destroy_data;
+  GDestroyNotify        user_data_destroy;
+  gpointer              user_data;
+};
+
+/**
+ * GST_VAAPI_CODED_BUFFER_PROXY_BUFFER:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Macro that evaluated to the underlying #GstVaapiCodedBuffer of @proxy.
+ */
+#undef  GST_VAAPI_CODED_BUFFER_PROXY_BUFFER
+#define GST_VAAPI_CODED_BUFFER_PROXY_BUFFER(proxy) \
+  GST_VAAPI_CODED_BUFFER_PROXY(proxy)->buffer
+
+/**
+ * GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE:
+ * @proxy: a #GstVaapiCodedBufferProxy
+ *
+ * Macro that evaluated to the underlying #GstVaapiCodedBuffer size of
+ * @proxy.
+ */
+#undef  GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE
+#define GST_VAAPI_CODED_BUFFER_PROXY_BUFFER_SIZE(proxy) \
+  GST_VAAPI_CODED_BUFFER_SIZE(GST_VAAPI_CODED_BUFFER_PROXY_BUFFER(proxy))
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_CODED_BUFFER_PROXY_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicompat.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicompat.h
new file mode 100644 (file)
index 0000000..f75a9ea
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  gstvapicompat.h - VA-API compatibility glue
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_COMPAT_H
+#define GST_VAAPI_COMPAT_H
+
+#include <va/va.h>
+
+#if VA_CHECK_VERSION(1,0,0)
+#define VA_ROI_RC_QP_DELTA_SUPPORT(x) x->bits.roi_rc_qp_delta_support
+#define VA_ENC_PACKED_HEADER_H264_SEI VAEncPackedHeaderRawData
+#else
+#define VA_ROI_RC_QP_DELTA_SUPPORT(x) x->bits.roi_rc_qp_delat_support
+#define VA_ENC_PACKED_HEADER_H264_SEI VAEncPackedHeaderH264_SEI
+#endif
+
+#include <va/va_compat.h>
+#include <va/va_drmcommon.h>
+
+#endif /* GST_VAAPI_COMPAT_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicontext.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicontext.c
new file mode 100644 (file)
index 0000000..97b81dc
--- /dev/null
@@ -0,0 +1,788 @@
+/*
+ *  gstvaapicontext.c - VA context abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapicontext
+ * @short_description: VA context abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapicontext.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapisurface_priv.h"
+#include "gstvaapisurfacepool.h"
+#include "gstvaapisurfaceproxy.h"
+#include "gstvaapivideopool_priv.h"
+#include "gstvaapiutils.h"
+
+/* Define default VA surface chroma format to YUV 4:2:0 */
+#define DEFAULT_CHROMA_TYPE (GST_VAAPI_CHROMA_TYPE_YUV420)
+
+/* Number of scratch surfaces beyond those used as reference */
+#define SCRATCH_SURFACES_COUNT (4)
+
+/* Debug category for GstVaapiContext */
+GST_DEBUG_CATEGORY (gst_debug_vaapi_context);
+#define GST_CAT_DEFAULT gst_debug_vaapi_context
+
+static void
+_init_vaapi_context_debug (void)
+{
+#ifndef GST_DISABLE_GST_DEBUG
+  static gsize _init = 0;
+
+  if (g_once_init_enter (&_init)) {
+    GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_context, "vaapicontext", 0,
+        "VA-API context");
+    g_once_init_leave (&_init, 1);
+  }
+#endif
+}
+
+static inline gboolean
+_context_is_broken_jpeg_decoder (GstVaapiContext * context)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
+
+  return (context->info.profile == GST_VAAPI_PROFILE_JPEG_BASELINE
+      && context->info.entrypoint == GST_VAAPI_ENTRYPOINT_VLD
+      && gst_vaapi_display_has_driver_quirks (display,
+          GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS));
+}
+
+static gboolean
+ensure_attributes (GstVaapiContext * context)
+{
+  if (G_LIKELY (context->attribs))
+    return TRUE;
+
+  context->attribs =
+      gst_vaapi_config_surface_attributes_get (GST_VAAPI_CONTEXT_DISPLAY
+      (context), context->va_config);
+
+  if (!context->attribs)
+    return FALSE;
+
+  if (_context_is_broken_jpeg_decoder (context)) {
+    GstVideoFormat fmt = GST_VIDEO_FORMAT_NV12;
+    g_array_prepend_val (context->attribs->formats, fmt);
+
+    context->attribs->mem_types &= ~VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
+  }
+  return TRUE;
+}
+
+/* XXX(victor): verify the preferred video format concords with the
+ * chroma type; otherwise it is changed for the (very arbritrary)
+ * preferred format from the requested context chroma type, in the
+ * context attributes */
+static void
+ensure_preferred_format (GstVaapiContext * context)
+{
+  const GstVaapiContextInfo *const cip = &context->info;
+  GArray *formats;
+  guint i;
+
+  if (context->preferred_format != GST_VIDEO_FORMAT_UNKNOWN)
+    return;
+
+  if (_context_is_broken_jpeg_decoder (context))
+    return;
+
+  if (!ensure_attributes (context) || !context->attribs->formats)
+    return;
+
+  formats = context->attribs->formats;
+  for (i = 0; i < formats->len; i++) {
+    GstVideoFormat format = g_array_index (formats, GstVideoFormat, i);
+    if (format == gst_vaapi_video_format_from_chroma (cip->chroma_type)) {
+      context->preferred_format = format;
+      break;
+    }
+  }
+
+  return;
+}
+
+static inline gboolean
+context_get_attribute (GstVaapiContext * context, VAConfigAttribType type,
+    guint * out_value_ptr)
+{
+  return gst_vaapi_get_config_attribute (GST_VAAPI_CONTEXT_DISPLAY (context),
+      context->va_profile, context->va_entrypoint, type, out_value_ptr);
+}
+
+static void
+context_destroy_surfaces (GstVaapiContext * context)
+{
+  if (context->surfaces) {
+    g_ptr_array_unref (context->surfaces);
+    context->surfaces = NULL;
+  }
+
+  context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN;
+
+  gst_vaapi_video_pool_replace (&context->surfaces_pool, NULL);
+}
+
+static void
+context_destroy (GstVaapiContext * context)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
+  VAContextID context_id;
+  VAStatus status;
+
+  context_id = GST_VAAPI_CONTEXT_ID (context);
+  GST_DEBUG ("context 0x%08x / config 0x%08x", context_id, context->va_config);
+
+  if (context_id != VA_INVALID_ID) {
+    GST_VAAPI_DISPLAY_LOCK (display);
+    status = vaDestroyContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
+        context_id);
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+    if (!vaapi_check_status (status, "vaDestroyContext()"))
+      GST_WARNING ("failed to destroy context 0x%08x", context_id);
+    GST_VAAPI_CONTEXT_ID (context) = VA_INVALID_ID;
+  }
+
+  if (context->va_config != VA_INVALID_ID) {
+    GST_VAAPI_DISPLAY_LOCK (display);
+    status = vaDestroyConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
+        context->va_config);
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+    if (!vaapi_check_status (status, "vaDestroyConfig()"))
+      GST_WARNING ("failed to destroy config 0x%08x", context->va_config);
+    context->va_config = VA_INVALID_ID;
+  }
+
+  if (context->attribs) {
+    gst_vaapi_config_surface_attributes_free (context->attribs);
+    context->attribs = NULL;
+  }
+}
+
+static gboolean
+context_ensure_surfaces (GstVaapiContext * context)
+{
+  GstVaapiDisplay *display = GST_VAAPI_CONTEXT_DISPLAY (context);
+  const GstVaapiContextInfo *const cip = &context->info;
+  const guint num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
+  GstVaapiSurface *surface;
+  GstVideoFormat format;
+  guint i, capacity;
+
+  ensure_preferred_format (context);
+  format = context->preferred_format;
+  for (i = context->surfaces->len; i < num_surfaces; i++) {
+    if (format != GST_VIDEO_FORMAT_UNKNOWN) {
+      surface = gst_vaapi_surface_new_with_format (display, format, cip->width,
+          cip->height, 0);
+    } else {
+      surface = gst_vaapi_surface_new (display, cip->chroma_type, cip->width,
+          cip->height);
+    }
+    if (!surface)
+      return FALSE;
+    g_ptr_array_add (context->surfaces, surface);
+    if (!gst_vaapi_video_pool_add_object (context->surfaces_pool, surface))
+      return FALSE;
+  }
+
+  capacity = cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE ? 0 : num_surfaces;
+  gst_vaapi_video_pool_set_capacity (context->surfaces_pool, capacity);
+  return TRUE;
+}
+
+static gboolean
+context_create_surfaces (GstVaapiContext * context)
+{
+  const GstVaapiContextInfo *const cip = &context->info;
+  GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
+  guint num_surfaces;
+
+  num_surfaces = cip->ref_frames + SCRATCH_SURFACES_COUNT;
+  if (!context->surfaces) {
+    context->surfaces = g_ptr_array_new_full (num_surfaces,
+        (GDestroyNotify) gst_mini_object_unref);
+    if (!context->surfaces)
+      return FALSE;
+  }
+
+  if (!context->surfaces_pool) {
+    context->surfaces_pool =
+        gst_vaapi_surface_pool_new_with_chroma_type (display, cip->chroma_type,
+        cip->width, cip->height, 0);
+
+    if (!context->surfaces_pool)
+      return FALSE;
+  }
+  return context_ensure_surfaces (context);
+}
+
+static gboolean
+context_create (GstVaapiContext * context)
+{
+  const GstVaapiContextInfo *const cip = &context->info;
+  GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
+  VAContextID context_id;
+  VASurfaceID surface_id;
+  VASurfaceID *surfaces_data = NULL;
+  VAStatus status;
+  GArray *surfaces = NULL;
+  gboolean success = FALSE;
+  guint i;
+  gint num_surfaces = 0;
+
+  if (!context->surfaces && !context_create_surfaces (context))
+    goto cleanup;
+
+  /* Create VA surfaces list for vaCreateContext() */
+  surfaces = g_array_sized_new (FALSE,
+      FALSE, sizeof (VASurfaceID), context->surfaces->len);
+  if (!surfaces)
+    goto cleanup;
+
+  for (i = 0; i < context->surfaces->len; i++) {
+    GstVaapiSurface *const surface = g_ptr_array_index (context->surfaces, i);
+    if (!surface)
+      goto cleanup;
+    surface_id = GST_VAAPI_SURFACE_ID (surface);
+    g_array_append_val (surfaces, surface_id);
+  }
+
+  g_assert (surfaces->len == context->surfaces->len);
+
+  /* vaCreateContext() doesn't really need an array of VASurfaceIDs (see
+   * https://lists.01.org/pipermail/intel-vaapi-media/2017-July/000052.html and
+   * https://github.com/intel/libva/issues/251); pass a dummy list of valid
+   * (non-null) IDs until the signature gets updated. */
+  if (cip->usage != GST_VAAPI_CONTEXT_USAGE_DECODE) {
+    surfaces_data = (VASurfaceID *) surfaces->data;
+    num_surfaces = surfaces->len;
+  }
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaCreateContext (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      context->va_config, cip->width, cip->height, VA_PROGRESSIVE,
+      surfaces_data, num_surfaces, &context_id);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaCreateContext()"))
+    goto cleanup;
+
+  GST_VAAPI_CONTEXT_ID (context) = context_id;
+  success = TRUE;
+
+cleanup:
+  if (surfaces)
+    g_array_unref (surfaces);
+  return success;
+}
+
+static gboolean
+config_create (GstVaapiContext * context)
+{
+  const GstVaapiContextInfo *const cip = &context->info;
+  GstVaapiDisplay *const display = GST_VAAPI_CONTEXT_DISPLAY (context);
+  VAConfigAttrib attribs[7], *attrib;
+  VAStatus status;
+  guint value, va_chroma_format, attrib_index;
+
+  /* Reset profile and entrypoint */
+  if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN
+      || cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
+    goto cleanup;
+  context->va_profile = gst_vaapi_profile_get_va_profile (cip->profile);
+  context->va_entrypoint =
+      gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint);
+
+  attrib_index = 0;
+  attrib = &attribs[attrib_index];
+  g_assert (attrib_index < G_N_ELEMENTS (attribs));
+
+  /* Validate VA surface format */
+  va_chroma_format = from_GstVaapiChromaType (cip->chroma_type);
+  if (!va_chroma_format)
+    goto cleanup;
+  attrib->type = VAConfigAttribRTFormat;
+  if (!context_get_attribute (context, attrib->type, &value))
+    goto cleanup;
+  if (!(value & va_chroma_format)) {
+    GST_ERROR ("unsupported chroma format (%s)",
+        string_of_va_chroma_format (va_chroma_format));
+    goto cleanup;
+  }
+  attrib->value = value;
+  attrib = &attribs[++attrib_index];
+  g_assert (attrib_index < G_N_ELEMENTS (attribs));
+
+  switch (cip->usage) {
+#if GST_VAAPI_USE_ENCODERS
+    case GST_VAAPI_CONTEXT_USAGE_ENCODE:
+    {
+      const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
+      guint va_rate_control;
+
+      /* Rate control */
+      va_rate_control = from_GstVaapiRateControl (config->rc_mode);
+      if (va_rate_control != VA_RC_NONE) {
+        attrib->type = VAConfigAttribRateControl;
+        if (!context_get_attribute (context, attrib->type, &value))
+          goto cleanup;
+
+        if ((value & va_rate_control) != va_rate_control) {
+          GST_ERROR ("unsupported %s rate control",
+              string_of_VARateControl (va_rate_control));
+          goto cleanup;
+        }
+        attrib->value = va_rate_control;
+        attrib = &attribs[++attrib_index];
+        g_assert (attrib_index < G_N_ELEMENTS (attribs));
+      }
+      /* Packed headers */
+      if (config->packed_headers) {
+        attrib->type = VAConfigAttribEncPackedHeaders;
+        if (!context_get_attribute (context, attrib->type, &value))
+          goto cleanup;
+
+        if ((value & config->packed_headers) != config->packed_headers) {
+          GST_ERROR ("unsupported packed headers 0x%08x",
+              config->packed_headers & ~(value & config->packed_headers));
+          goto cleanup;
+        }
+        attrib->value = config->packed_headers;
+        attrib = &attribs[++attrib_index];
+        g_assert (attrib_index < G_N_ELEMENTS (attribs));
+      }
+      if (cip->profile == GST_VAAPI_PROFILE_JPEG_BASELINE) {
+        attrib->type = VAConfigAttribEncJPEG;
+        if (!context_get_attribute (context, attrib->type, &value))
+          goto cleanup;
+        attrib->value = value;
+        attrib = &attribs[++attrib_index];
+        g_assert (attrib_index < G_N_ELEMENTS (attribs));
+      }
+#if VA_CHECK_VERSION(0,39,1)
+      if (config->roi_capability) {
+        VAConfigAttribValEncROI *roi_config;
+
+        attrib->type = VAConfigAttribEncROI;
+        if (!context_get_attribute (context, attrib->type, &value))
+          goto cleanup;
+        roi_config = (VAConfigAttribValEncROI *) & value;
+        if (roi_config->bits.num_roi_regions != config->roi_num_supported) {
+          GST_ERROR ("Mismatched ROI support: number of regions supported: %d",
+              roi_config->bits.num_roi_regions);
+          goto cleanup;
+        }
+        if (config->rc_mode != GST_VAAPI_RATECONTROL_CQP
+            && VA_ROI_RC_QP_DELTA_SUPPORT (roi_config) == 0) {
+          GST_ERROR ("Mismatched ROI support:  ROI delta QP: %d",
+              VA_ROI_RC_QP_DELTA_SUPPORT (roi_config));
+          goto cleanup;
+        }
+        attrib->value = value;
+        attrib = &attribs[++attrib_index];
+        g_assert (attrib_index < G_N_ELEMENTS (attribs));
+      }
+#endif
+      break;
+    }
+#endif
+    default:
+      break;
+  }
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaCreateConfig (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      context->va_profile, context->va_entrypoint, attribs, attrib_index,
+      &context->va_config);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaCreateConfig()"))
+    goto cleanup;
+
+  return TRUE;
+cleanup:
+  GST_WARNING ("Failed to create vaConfig");
+  return FALSE;
+}
+
+/** Updates config for encoding. Returns %TRUE if config changed */
+static gboolean
+context_update_config_encoder (GstVaapiContext * context,
+    const GstVaapiConfigInfoEncoder * new_config)
+{
+  GstVaapiConfigInfoEncoder *const config = &context->info.config.encoder;
+  gboolean config_changed = FALSE;
+
+  g_assert (context->info.usage == GST_VAAPI_CONTEXT_USAGE_ENCODE);
+
+  if (config->rc_mode != new_config->rc_mode) {
+    config->rc_mode = new_config->rc_mode;
+    config_changed = TRUE;
+  }
+
+  if (config->packed_headers != new_config->packed_headers) {
+    config->packed_headers = new_config->packed_headers;
+    config_changed = TRUE;
+  }
+
+  if (config->roi_capability != new_config->roi_capability ||
+      config->roi_num_supported != new_config->roi_num_supported) {
+    config->roi_capability = new_config->roi_capability;
+    config->roi_num_supported = new_config->roi_num_supported;
+    config_changed = TRUE;
+  }
+
+  return config_changed;
+}
+
+static inline void
+gst_vaapi_context_init (GstVaapiContext * context,
+    const GstVaapiContextInfo * new_cip)
+{
+  GstVaapiContextInfo *const cip = &context->info;
+
+  *cip = *new_cip;
+  if (!cip->chroma_type)
+    cip->chroma_type = DEFAULT_CHROMA_TYPE;
+
+  context->va_config = VA_INVALID_ID;
+  context->reset_on_resize = TRUE;
+
+  context->attribs = NULL;
+  context->preferred_format = GST_VIDEO_FORMAT_UNKNOWN;
+}
+
+/**
+ * gst_vaapi_context_new:
+ * @display: a #GstVaapiDisplay
+ * @cip: a pointer to the #GstVaapiContextInfo
+ *
+ * Creates a new #GstVaapiContext with the configuration specified by
+ * @cip, thus including profile, entry-point, encoded size and maximum
+ * number of reference frames reported by the bitstream.
+ *
+ * Return value: the newly allocated #GstVaapiContext object
+ */
+GstVaapiContext *
+gst_vaapi_context_new (GstVaapiDisplay * display,
+    const GstVaapiContextInfo * cip)
+{
+  GstVaapiContext *context;
+
+  g_return_val_if_fail (display, NULL);
+
+  _init_vaapi_context_debug ();
+
+  if (cip->profile == GST_VAAPI_PROFILE_UNKNOWN
+      || cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
+    return NULL;
+
+  context = g_slice_new (GstVaapiContext);
+  if (!context)
+    return NULL;
+
+  GST_VAAPI_CONTEXT_DISPLAY (context) = gst_object_ref (display);
+  GST_VAAPI_CONTEXT_ID (context) = VA_INVALID_ID;
+  g_atomic_int_set (&context->ref_count, 1);
+  context->surfaces = NULL;
+  context->surfaces_pool = NULL;
+
+  gst_vaapi_context_init (context, cip);
+
+  if (!config_create (context))
+    goto error;
+
+  /* this means we don't want to create a VAcontext */
+  if (cip->width == 0 && cip->height == 0)
+    goto done;
+
+  /* this is not valid */
+  if (cip->width == 0 || cip->height == 0)
+    goto error;
+
+  if (!context_create (context))
+    goto error;
+
+done:
+  GST_DEBUG ("context 0x%08" G_GSIZE_MODIFIER "x / config 0x%08x",
+      GST_VAAPI_CONTEXT_ID (context), context->va_config);
+  return context;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_context_unref (context);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_context_reset:
+ * @context: a #GstVaapiContext
+ * @new_cip: a pointer to the new #GstVaapiContextInfo details
+ *
+ * Resets @context to the configuration specified by @new_cip, thus
+ * including profile, entry-point, encoded size and maximum number of
+ * reference frames reported by the bitstream.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_context_reset (GstVaapiContext * context,
+    const GstVaapiContextInfo * new_cip)
+{
+  GstVaapiContextInfo *const cip = &context->info;
+  gboolean reset_surfaces = FALSE, reset_config = FALSE;
+  gboolean grow_surfaces = FALSE;
+  GstVaapiChromaType chroma_type;
+
+  if (new_cip->profile == GST_VAAPI_PROFILE_UNKNOWN
+      || new_cip->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID)
+    return FALSE;
+
+  chroma_type = new_cip->chroma_type ? new_cip->chroma_type :
+      DEFAULT_CHROMA_TYPE;
+  if (cip->chroma_type != chroma_type) {
+    cip->chroma_type = chroma_type;
+    reset_surfaces = TRUE;
+  }
+
+  if (cip->width != new_cip->width || cip->height != new_cip->height) {
+    cip->width = new_cip->width;
+    cip->height = new_cip->height;
+    reset_surfaces = TRUE;
+  }
+
+  if (cip->profile != new_cip->profile ||
+      cip->entrypoint != new_cip->entrypoint) {
+    cip->profile = new_cip->profile;
+    cip->entrypoint = new_cip->entrypoint;
+    reset_config = TRUE;
+  }
+
+  if (cip->ref_frames < new_cip->ref_frames) {
+    cip->ref_frames = new_cip->ref_frames;
+    grow_surfaces = TRUE;
+  }
+
+  if (cip->usage != new_cip->usage) {
+    cip->usage = new_cip->usage;
+    reset_config = TRUE;
+    memcpy (&cip->config, &new_cip->config, sizeof (cip->config));
+  } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) {
+    if (context_update_config_encoder (context, &new_cip->config.encoder))
+      reset_config = TRUE;
+  } else if (new_cip->usage == GST_VAAPI_CONTEXT_USAGE_DECODE) {
+    if ((reset_surfaces && context->reset_on_resize) || grow_surfaces)
+      reset_config = TRUE;
+  }
+
+  if (reset_surfaces)
+    context_destroy_surfaces (context);
+  if (reset_config)
+    context_destroy (context);
+
+  if (reset_config && !(config_create (context) && context_create (context)))
+    return FALSE;
+  if (reset_surfaces && !context_create_surfaces (context))
+    return FALSE;
+  else if (grow_surfaces && !context_ensure_surfaces (context))
+    return FALSE;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_context_get_id:
+ * @context: a #GstVaapiContext
+ *
+ * Returns the underlying VAContextID of the @context.
+ *
+ * Return value: the underlying VA context id
+ */
+GstVaapiID
+gst_vaapi_context_get_id (GstVaapiContext * context)
+{
+  g_return_val_if_fail (context != NULL, VA_INVALID_ID);
+
+  return GST_VAAPI_CONTEXT_ID (context);
+}
+
+/**
+ * gst_vaapi_context_get_surface_proxy:
+ * @context: a #GstVaapiContext
+ *
+ * Acquires a free surface, wrapped into a #GstVaapiSurfaceProxy. The
+ * returned surface will be automatically released when the proxy is
+ * destroyed. So, it is enough to call gst_vaapi_surface_proxy_unref()
+ * after usage.
+ *
+ * This function returns %NULL if there is no free surface available
+ * in the pool. The surfaces are pre-allocated during context creation
+ * though.
+ *
+ * Return value: a free surface, or %NULL if none is available
+ */
+GstVaapiSurfaceProxy *
+gst_vaapi_context_get_surface_proxy (GstVaapiContext * context)
+{
+  g_return_val_if_fail (context != NULL, NULL);
+
+  return
+      gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
+      (context->surfaces_pool));
+}
+
+/**
+ * gst_vaapi_context_get_surface_count:
+ * @context: a #GstVaapiContext
+ *
+ * Retrieves the number of free surfaces left in the pool.
+ *
+ * Return value: the number of free surfaces available in the pool
+ */
+guint
+gst_vaapi_context_get_surface_count (GstVaapiContext * context)
+{
+  g_return_val_if_fail (context != NULL, 0);
+
+  if (gst_vaapi_video_pool_get_capacity (context->surfaces_pool) == 0)
+    return G_MAXUINT;
+  return gst_vaapi_video_pool_get_size (context->surfaces_pool);
+}
+
+/**
+ * gst_vaapi_context_reset_on_resize:
+ * @context: a #GstVaapiContext
+ * @reset_on_resize: Should the context be reset on size change
+ *
+ * Sets whether the underlying context should be reset when a size change
+ * happens. The proper setting for this is codec dependent.
+ */
+void
+gst_vaapi_context_reset_on_resize (GstVaapiContext * context,
+    gboolean reset_on_resize)
+{
+  g_return_if_fail (context != NULL);
+
+  context->reset_on_resize = reset_on_resize;
+}
+
+/**
+ * gst_vaapi_context_get_surface_formats:
+ * @context: a #GstVaapiContext
+ *
+ * Determines the set of supported formats by the surfaces associated
+ * to @context. The caller owns an extra reference of the resulting
+ * array of #GstVideoFormat elements, so it shall be released with
+ * g_array_unref after usage.
+ *
+ * Return value: (transfer full): the set of target formats supported
+ * by the surfaces in @context.
+ */
+GArray *
+gst_vaapi_context_get_surface_formats (GstVaapiContext * context)
+{
+  g_return_val_if_fail (context, NULL);
+
+  if (!ensure_attributes (context))
+    return NULL;
+
+  if (context->attribs->formats)
+    return g_array_ref (context->attribs->formats);
+  return NULL;
+}
+
+/**
+ * gst_vaapi_context_get_surface_attributes:
+ * @context: a #GstVaapiContext
+ * @out_attribs: an allocated #GstVaapiConfigSurfaceAttributes
+ *
+ * Copy context's surface restrictions to @out_attribs, EXCEPT the
+ * color formats. Use gst_vaapi_context_get_surface_formats() to get
+ * them.
+ *
+ * Returns: %TRUE if the attributes were extracted and copied; %FALSE,
+ * otherwise
+ **/
+gboolean
+gst_vaapi_context_get_surface_attributes (GstVaapiContext * context,
+    GstVaapiConfigSurfaceAttributes * out_attribs)
+{
+  g_return_val_if_fail (context, FALSE);
+
+  if (!ensure_attributes (context))
+    return FALSE;
+
+  if (out_attribs) {
+    out_attribs->min_width = context->attribs->min_width;
+    out_attribs->min_height = context->attribs->min_height;
+    out_attribs->max_width = context->attribs->max_width;
+    out_attribs->max_height = context->attribs->max_height;
+    out_attribs->mem_types = context->attribs->mem_types;
+    out_attribs->formats = NULL;
+  }
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_context_ref:
+ * @context: a #GstVaapiContext
+ *
+ * Atomically increases the reference count of the given @context by one.
+ *
+ * Returns: The same @context argument
+ */
+GstVaapiContext *
+gst_vaapi_context_ref (GstVaapiContext * context)
+{
+  g_return_val_if_fail (context != NULL, NULL);
+
+  g_atomic_int_inc (&context->ref_count);
+
+  return context;
+}
+
+/**
+ * gst_vaapi_context_unref:
+ * @context: a #GstVaapiContext
+ *
+ * Atomically decreases the reference count of the @context by one. If
+ * the reference count reaches zero, the object will be free'd.
+ */
+void
+gst_vaapi_context_unref (GstVaapiContext * context)
+{
+  g_return_if_fail (context != NULL);
+  g_return_if_fail (context->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test (&context->ref_count)) {
+    context_destroy (context);
+    context_destroy_surfaces (context);
+    gst_vaapi_display_replace (&context->display, NULL);
+    g_slice_free (GstVaapiContext, context);
+  }
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicontext.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapicontext.h
new file mode 100644 (file)
index 0000000..7117722
--- /dev/null
@@ -0,0 +1,170 @@
+/*
+ *  gstvaapicontext.h - VA context abstraction (private)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_CONTEXT_H
+#define GST_VAAPI_CONTEXT_H
+
+#include "gstvaapiprofile.h"
+#include "gstvaapidisplay.h"
+#include "gstvaapisurface.h"
+#include "gstvaapiutils_core.h"
+#include "gstvaapivideopool.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_CONTEXT(obj) \
+  ((GstVaapiContext *) (obj))
+
+typedef struct _GstVaapiConfigInfoEncoder GstVaapiConfigInfoEncoder;
+typedef struct _GstVaapiContextInfo GstVaapiContextInfo;
+typedef struct _GstVaapiContext GstVaapiContext;
+
+/**
+ * GstVaapiContextUsage:
+ * @GST_VAAPI_CONTEXT_MODE_DECODE: context used for decoding.
+ * @GST_VAAPI_CONTEXT_MODE_ENCODE: context used for encoding.
+ * @GST_VAAPI_CONTEXT_MODE_VPP: context used for video processing.
+ *
+ * The set of supported VA context usages.
+ */
+typedef enum {
+  GST_VAAPI_CONTEXT_USAGE_DECODE = 1,
+  GST_VAAPI_CONTEXT_USAGE_ENCODE,
+  GST_VAAPI_CONTEXT_USAGE_VPP,
+} GstVaapiContextUsage;
+
+/**
+ * GstVaapiConfigInfoEncoder:
+ * @rc_mode: rate-control mode (#GstVaapiRateControl).
+ * @packed_headers: notify encoder that packed headers are submitted (mask).
+ * @roi_capability: if encoder supports regions-of-interest.
+ * @roi_num_supported: The number of regions-of-interest supported.
+ *
+ * Extra configuration for encoding.
+ */
+struct _GstVaapiConfigInfoEncoder
+{
+  GstVaapiRateControl rc_mode;
+  guint packed_headers;
+  gboolean roi_capability;
+  guint roi_num_supported;
+};
+
+/**
+ * GstVaapiContextInfo:
+ *
+ * Structure holding VA context info like encoded size, decoder
+ * profile and entry-point to use, and maximum number of reference
+ * frames reported by the bitstream.
+ */
+struct _GstVaapiContextInfo
+{
+  GstVaapiContextUsage usage;
+  GstVaapiProfile profile;
+  GstVaapiEntrypoint entrypoint;
+  GstVaapiChromaType chroma_type;
+  guint width;
+  guint height;
+  guint ref_frames;
+  union _GstVaapiConfigInfo {
+    GstVaapiConfigInfoEncoder encoder;
+  } config;
+};
+
+/**
+ * GstVaapiContext:
+ *
+ * A VA context wrapper.
+ */
+struct _GstVaapiContext
+{
+  /*< private >*/
+  gint ref_count;
+  GstVaapiDisplay *display;
+  GstVaapiID object_id;
+
+  /*< public >*/
+  GstVaapiContextInfo info;
+  VAProfile va_profile;
+  VAEntrypoint va_entrypoint;
+  VAConfigID va_config;
+  GPtrArray *surfaces;
+  GstVaapiVideoPool *surfaces_pool;
+  gboolean reset_on_resize;
+  GstVaapiConfigSurfaceAttributes *attribs;
+  GstVideoFormat preferred_format;
+};
+
+#define GST_VAAPI_CONTEXT_ID(context)        (((GstVaapiContext *)(context))->object_id)
+#define GST_VAAPI_CONTEXT_DISPLAY(context)   (((GstVaapiContext *)(context))->display)
+
+G_GNUC_INTERNAL
+GstVaapiContext *
+gst_vaapi_context_new (GstVaapiDisplay * display,
+    const GstVaapiContextInfo * cip);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_context_reset (GstVaapiContext * context,
+    const GstVaapiContextInfo * new_cip);
+
+G_GNUC_INTERNAL
+GstVaapiID
+gst_vaapi_context_get_id (GstVaapiContext * context);
+
+G_GNUC_INTERNAL
+GstVaapiSurfaceProxy *
+gst_vaapi_context_get_surface_proxy (GstVaapiContext * context);
+
+G_GNUC_INTERNAL
+guint
+gst_vaapi_context_get_surface_count (GstVaapiContext * context);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_context_reset_on_resize (GstVaapiContext * context,
+    gboolean reset_on_resize);
+
+G_GNUC_INTERNAL
+GArray *
+gst_vaapi_context_get_surface_formats (GstVaapiContext * context);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_context_get_surface_attributes (GstVaapiContext * context,
+    GstVaapiConfigSurfaceAttributes * out_attribs);
+
+G_GNUC_INTERNAL
+GstVaapiContext *
+gst_vaapi_context_ref (GstVaapiContext * context);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_context_unref (GstVaapiContext * context);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiContext, gst_vaapi_context_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_CONTEXT_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidebug.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidebug.h
new file mode 100644 (file)
index 0000000..88ea312
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  gstvaapidebug.h - VA-API debugging utilities
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DEBUG_H
+#define GST_VAAPI_DEBUG_H
+
+#include <gst/gstinfo.h>
+
+#if DEBUG
+GST_DEBUG_CATEGORY_EXTERN(gst_debug_vaapi);
+#define GST_CAT_DEFAULT gst_debug_vaapi
+#endif
+
+#if DEBUG_VAAPI_DISPLAY
+GST_DEBUG_CATEGORY_EXTERN(gst_debug_vaapi_display);
+#define GST_CAT_DEFAULT gst_debug_vaapi_display
+#endif
+
+#endif /* GST_VAAPI_DEBUG_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder.c
new file mode 100644 (file)
index 0000000..ed70231
--- /dev/null
@@ -0,0 +1,1213 @@
+/*
+ *  gstvaapidecoder.c - VA decoder abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder
+ * @short_description: VA decoder abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapidecoder.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapiparser_frame.h"
+#include "gstvaapisurfaceproxy_priv.h"
+#include "gstvaapiutils.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+enum
+{
+  PROP_DISPLAY = 1,
+  PROP_CAPS,
+  N_PROPERTIES
+};
+static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
+
+G_DEFINE_TYPE (GstVaapiDecoder, gst_vaapi_decoder, GST_TYPE_OBJECT);
+
+static void drop_frame (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame);
+
+static void
+parser_state_reset (GstVaapiParserState * ps)
+{
+
+  if (ps->input_adapter)
+    gst_adapter_clear (ps->input_adapter);
+  if (ps->output_adapter)
+    gst_adapter_clear (ps->output_adapter);
+  ps->current_adapter = NULL;
+
+  if (ps->next_unit_pending) {
+    gst_vaapi_decoder_unit_clear (&ps->next_unit);
+    ps->next_unit_pending = FALSE;
+  }
+
+  ps->current_frame_number = 0;
+  ps->input_offset1 = ps->input_offset2 = 0;
+  ps->at_eos = FALSE;
+}
+
+static void
+parser_state_finalize (GstVaapiParserState * ps)
+{
+  if (ps->input_adapter) {
+    gst_adapter_clear (ps->input_adapter);
+    g_object_unref (ps->input_adapter);
+    ps->input_adapter = NULL;
+  }
+
+  if (ps->output_adapter) {
+    gst_adapter_clear (ps->output_adapter);
+    g_object_unref (ps->output_adapter);
+    ps->output_adapter = NULL;
+  }
+
+  if (ps->next_unit_pending) {
+    gst_vaapi_decoder_unit_clear (&ps->next_unit);
+    ps->next_unit_pending = FALSE;
+  }
+}
+
+static gboolean
+parser_state_init (GstVaapiParserState * ps)
+{
+  memset (ps, 0, sizeof (*ps));
+
+  ps->input_adapter = gst_adapter_new ();
+  if (!ps->input_adapter)
+    return FALSE;
+
+  ps->output_adapter = gst_adapter_new ();
+  if (!ps->output_adapter)
+    return FALSE;
+  return TRUE;
+}
+
+static void
+parser_state_prepare (GstVaapiParserState * ps, GstAdapter * adapter)
+{
+  /* XXX: check we really have a continuity from the previous call */
+  if (ps->current_adapter != adapter)
+    goto reset;
+  return;
+
+reset:
+  ps->current_adapter = adapter;
+  ps->input_offset1 = -1;
+  ps->input_offset2 = -1;
+}
+
+static gboolean
+push_buffer (GstVaapiDecoder * decoder, GstBuffer * buffer)
+{
+  if (!buffer) {
+    buffer = gst_buffer_new ();
+    if (!buffer)
+      return FALSE;
+    GST_BUFFER_FLAG_SET (buffer, GST_BUFFER_FLAG_EOS);
+  }
+
+  GST_DEBUG ("queue encoded data buffer %p (%zu bytes)",
+      buffer, gst_buffer_get_size (buffer));
+
+  g_async_queue_push (decoder->buffers, buffer);
+  return TRUE;
+}
+
+static GstBuffer *
+pop_buffer (GstVaapiDecoder * decoder)
+{
+  GstBuffer *buffer;
+
+  buffer = g_async_queue_try_pop (decoder->buffers);
+  if (!buffer)
+    return NULL;
+
+  GST_DEBUG ("dequeue buffer %p for decoding (%zu bytes)",
+      buffer, gst_buffer_get_size (buffer));
+
+  return buffer;
+}
+
+static GstVaapiDecoderStatus
+do_parse (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame * base_frame, GstAdapter * adapter, gboolean at_eos,
+    guint * got_unit_size_ptr, gboolean * got_frame_ptr)
+{
+  GstVaapiParserState *const ps = &decoder->parser_state;
+  GstVaapiParserFrame *frame;
+  GstVaapiDecoderUnit *unit;
+  GstVaapiDecoderStatus status;
+
+  *got_unit_size_ptr = 0;
+  *got_frame_ptr = FALSE;
+
+  frame = gst_video_codec_frame_get_user_data (base_frame);
+  if (!frame) {
+    GstVideoCodecState *const codec_state = decoder->codec_state;
+    frame = gst_vaapi_parser_frame_new (codec_state->info.width,
+        codec_state->info.height);
+    if (!frame)
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    gst_video_codec_frame_set_user_data (base_frame,
+        frame, (GDestroyNotify) gst_vaapi_mini_object_unref);
+  }
+
+  parser_state_prepare (ps, adapter);
+
+  unit = &ps->next_unit;
+  if (ps->next_unit_pending) {
+    ps->next_unit_pending = FALSE;
+    goto got_unit;
+  }
+  gst_vaapi_decoder_unit_init (unit);
+
+  ps->current_frame = base_frame;
+  status = GST_VAAPI_DECODER_GET_CLASS (decoder)->parse (decoder,
+      adapter, at_eos, unit);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    if (at_eos && frame->units->len > 0 &&
+        status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA) {
+      /* XXX: assume the frame is complete at <EOS> */
+      *got_frame_ptr = TRUE;
+      return GST_VAAPI_DECODER_STATUS_SUCCESS;
+    }
+    return status;
+  }
+
+  if (GST_VAAPI_DECODER_UNIT_IS_FRAME_START (unit) && frame->units->len > 0) {
+    ps->next_unit_pending = TRUE;
+    *got_frame_ptr = TRUE;
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  }
+
+got_unit:
+  gst_vaapi_parser_frame_append_unit (frame, unit);
+  *got_unit_size_ptr = unit->size;
+  *got_frame_ptr = GST_VAAPI_DECODER_UNIT_IS_FRAME_END (unit);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+do_decode_units (GstVaapiDecoder * decoder, GArray * units)
+{
+  GstVaapiDecoderClass *const klass = GST_VAAPI_DECODER_GET_CLASS (decoder);
+  GstVaapiDecoderStatus status;
+  guint i;
+
+  for (i = 0; i < units->len; i++) {
+    GstVaapiDecoderUnit *const unit =
+        &g_array_index (units, GstVaapiDecoderUnit, i);
+    if (GST_VAAPI_DECODER_UNIT_IS_SKIPPED (unit))
+      continue;
+    status = klass->decode (decoder, unit);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+do_decode_1 (GstVaapiDecoder * decoder, GstVaapiParserFrame * frame)
+{
+  GstVaapiDecoderClass *const klass = GST_VAAPI_DECODER_GET_CLASS (decoder);
+  GstVaapiDecoderStatus status;
+
+  if (frame->pre_units->len > 0) {
+    status = do_decode_units (decoder, frame->pre_units);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+
+  if (frame->units->len > 0) {
+    if (klass->start_frame) {
+      GstVaapiDecoderUnit *const unit =
+          &g_array_index (frame->units, GstVaapiDecoderUnit, 0);
+      status = klass->start_frame (decoder, unit);
+      if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+        return status;
+    }
+
+    status = do_decode_units (decoder, frame->units);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+
+    if (klass->end_frame) {
+      status = klass->end_frame (decoder);
+      if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+        return status;
+    }
+  }
+
+  if (frame->post_units->len > 0) {
+    status = do_decode_units (decoder, frame->post_units);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+
+  /* Drop frame if there is no slice data unit in there */
+  if (G_UNLIKELY (frame->units->len == 0))
+    return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline GstVaapiDecoderStatus
+do_decode (GstVaapiDecoder * decoder, GstVideoCodecFrame * base_frame)
+{
+  GstVaapiParserState *const ps = &decoder->parser_state;
+  GstVaapiParserFrame *const frame = base_frame->user_data;
+  GstVaapiDecoderStatus status;
+
+  ps->current_frame = base_frame;
+
+  gst_vaapi_parser_frame_ref (frame);
+  status = do_decode_1 (decoder, frame);
+  gst_vaapi_parser_frame_unref (frame);
+
+  switch ((guint) status) {
+    case GST_VAAPI_DECODER_STATUS_DROP_FRAME:
+      drop_frame (decoder, base_frame);
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+  }
+  return status;
+}
+
+static GstVaapiDecoderStatus
+decode_step (GstVaapiDecoder * decoder)
+{
+  GstVaapiParserState *const ps = &decoder->parser_state;
+  GstVaapiDecoderStatus status;
+  GstBuffer *buffer;
+  gboolean got_frame;
+  guint got_unit_size, input_size;
+
+  /* Fill adapter with all buffers we have in the queue */
+  for (;;) {
+    buffer = pop_buffer (decoder);
+    if (!buffer)
+      break;
+
+    ps->at_eos = GST_BUFFER_IS_EOS (buffer);
+    if (!ps->at_eos)
+      gst_adapter_push (ps->input_adapter, buffer);
+  }
+
+  /* Parse and decode all decode units */
+  input_size = gst_adapter_available (ps->input_adapter);
+  if (input_size == 0) {
+    if (ps->at_eos)
+      return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+  }
+
+  do {
+    if (!ps->current_frame) {
+      ps->current_frame = g_slice_new0 (GstVideoCodecFrame);
+      if (!ps->current_frame)
+        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+      ps->current_frame->ref_count = 1;
+      ps->current_frame->system_frame_number = ps->current_frame_number++;
+    }
+
+    status = do_parse (decoder, ps->current_frame, ps->input_adapter,
+        ps->at_eos, &got_unit_size, &got_frame);
+    GST_DEBUG ("parse frame (status = %d)", status);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+      if (status == GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA && ps->at_eos)
+        status = GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
+      break;
+    }
+
+    if (got_unit_size > 0) {
+      buffer = gst_adapter_take_buffer (ps->input_adapter, got_unit_size);
+      input_size -= got_unit_size;
+
+      if (gst_adapter_available (ps->output_adapter) == 0) {
+        ps->current_frame->pts = gst_adapter_prev_pts (ps->input_adapter, NULL);
+      }
+      gst_adapter_push (ps->output_adapter, buffer);
+    }
+
+    if (got_frame) {
+      ps->current_frame->input_buffer =
+          gst_adapter_take_buffer (ps->output_adapter,
+          gst_adapter_available (ps->output_adapter));
+
+      status = do_decode (decoder, ps->current_frame);
+      GST_DEBUG ("decode frame (status = %d)", status);
+
+      gst_video_codec_frame_unref (ps->current_frame);
+      ps->current_frame = NULL;
+      break;
+    }
+  } while (input_size > 0);
+  return status;
+}
+
+static void
+drop_frame (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame)
+{
+  GST_DEBUG ("drop frame %d", frame->system_frame_number);
+
+  /* no surface proxy */
+  gst_video_codec_frame_set_user_data (frame, NULL, NULL);
+
+  frame->pts = GST_CLOCK_TIME_NONE;
+  GST_VIDEO_CODEC_FRAME_FLAG_SET (frame,
+      GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
+
+  g_async_queue_push (decoder->frames, gst_video_codec_frame_ref (frame));
+}
+
+static inline void
+push_frame (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame)
+{
+  GstVaapiSurfaceProxy *const proxy = frame->user_data;
+
+  GST_DEBUG ("push frame %d (surface 0x%08x)", frame->system_frame_number,
+      (guint32) GST_VAAPI_SURFACE_PROXY_SURFACE_ID (proxy));
+
+  g_async_queue_push (decoder->frames, gst_video_codec_frame_ref (frame));
+}
+
+static inline GstVideoCodecFrame *
+pop_frame (GstVaapiDecoder * decoder, guint64 timeout)
+{
+  GstVideoCodecFrame *frame;
+  GstVaapiSurfaceProxy *proxy;
+
+  if (G_LIKELY (timeout > 0))
+    frame = g_async_queue_timeout_pop (decoder->frames, timeout);
+  else
+    frame = g_async_queue_try_pop (decoder->frames);
+  if (!frame)
+    return NULL;
+
+  proxy = frame->user_data;
+  GST_DEBUG ("pop frame %d (surface 0x%08x)", frame->system_frame_number,
+      (proxy ? (guint32) GST_VAAPI_SURFACE_PROXY_SURFACE_ID (proxy) :
+          VA_INVALID_ID));
+
+  return frame;
+}
+
+static gboolean
+set_caps (GstVaapiDecoder * decoder, const GstCaps * caps)
+{
+  GstVideoCodecState *const codec_state = decoder->codec_state;
+  GstStructure *const structure = gst_caps_get_structure (caps, 0);
+  const GValue *v_codec_data;
+
+  decoder->codec = gst_vaapi_get_codec_from_caps (caps);
+  if (!decoder->codec)
+    return FALSE;
+
+  if (!gst_video_info_from_caps (&codec_state->info, caps))
+    return FALSE;
+
+  if (codec_state->caps)
+    gst_caps_unref (codec_state->caps);
+  codec_state->caps = gst_caps_copy (caps);
+
+  v_codec_data = gst_structure_get_value (structure, "codec_data");
+  if (v_codec_data)
+    gst_buffer_replace (&codec_state->codec_data,
+        gst_value_get_buffer (v_codec_data));
+  return TRUE;
+}
+
+static inline GstCaps *
+get_caps (GstVaapiDecoder * decoder)
+{
+  return GST_VAAPI_DECODER_CODEC_STATE (decoder)->caps;
+}
+
+static void
+notify_codec_state_changed (GstVaapiDecoder * decoder)
+{
+  if (decoder->codec_state_changed_func)
+    decoder->codec_state_changed_func (decoder, decoder->codec_state,
+        decoder->codec_state_changed_data);
+}
+
+static void
+gst_vaapi_decoder_finalize (GObject * object)
+{
+  GstVaapiDecoder *const decoder = GST_VAAPI_DECODER (object);
+
+  gst_video_codec_state_unref (decoder->codec_state);
+  decoder->codec_state = NULL;
+
+  parser_state_finalize (&decoder->parser_state);
+
+  if (decoder->buffers) {
+    g_async_queue_unref (decoder->buffers);
+    decoder->buffers = NULL;
+  }
+
+  if (decoder->frames) {
+    g_async_queue_unref (decoder->frames);
+    decoder->frames = NULL;
+  }
+
+  if (decoder->context) {
+    gst_vaapi_context_unref (decoder->context);
+    decoder->context = NULL;
+  }
+  decoder->va_context = VA_INVALID_ID;
+
+  gst_vaapi_display_replace (&decoder->display, NULL);
+  decoder->va_display = NULL;
+
+  G_OBJECT_CLASS (gst_vaapi_decoder_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDecoder *const decoder = GST_VAAPI_DECODER (object);
+
+  switch (property_id) {
+    case PROP_DISPLAY:
+      g_assert (decoder->display == NULL);
+      decoder->display = g_value_dup_object (value);
+      g_assert (decoder->display != NULL);
+      decoder->va_display = GST_VAAPI_DISPLAY_VADISPLAY (decoder->display);
+      break;
+    case PROP_CAPS:{
+      GstCaps *caps = g_value_get_boxed (value);
+      if (!set_caps (decoder, caps)) {
+        GST_WARNING_OBJECT (decoder, "failed to set caps %" GST_PTR_FORMAT,
+            caps);
+      }
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_decoder_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDecoder *const decoder = GST_VAAPI_DECODER (object);
+
+  switch (property_id) {
+    case PROP_DISPLAY:
+      g_value_set_object (value, decoder->display);
+      break;
+    case PROP_CAPS:
+      g_value_set_boxed (value, gst_caps_ref (get_caps (decoder)));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_decoder_class_init (GstVaapiDecoderClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = gst_vaapi_decoder_set_property;
+  object_class->get_property = gst_vaapi_decoder_get_property;
+  object_class->finalize = gst_vaapi_decoder_finalize;
+
+  /**
+   * GstVaapiDecoder:display:
+   *
+   * #GstVaapiDisplay to be used.
+   */
+  g_properties[PROP_DISPLAY] =
+      g_param_spec_object ("display", "Gst VA-API Display",
+      "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY,
+      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME);
+
+  /**
+   * GstCaps:caps:
+   *
+   * #GstCaps the caps describing the media to process.
+   */
+  g_properties[PROP_CAPS] =
+      g_param_spec_boxed ("caps", "Caps",
+      "The caps describing the media to process", GST_TYPE_CAPS,
+      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME);
+
+  g_object_class_install_properties (object_class, N_PROPERTIES, g_properties);
+}
+
+static void
+gst_vaapi_decoder_init (GstVaapiDecoder * decoder)
+{
+  GstVideoCodecState *codec_state;
+
+  parser_state_init (&decoder->parser_state);
+
+  codec_state = g_slice_new0 (GstVideoCodecState);
+  codec_state->ref_count = 1;
+  gst_video_info_init (&codec_state->info);
+
+  decoder->va_context = VA_INVALID_ID;
+  decoder->codec_state = codec_state;
+  decoder->buffers = g_async_queue_new_full ((GDestroyNotify) gst_buffer_unref);
+  decoder->frames = g_async_queue_new_full ((GDestroyNotify)
+      gst_video_codec_frame_unref);
+}
+
+/**
+ * gst_vaapi_decoder_replace:
+ * @old_decoder_ptr: a pointer to a #GstVaapiDecoder
+ * @new_decoder: a #GstVaapiDecoder
+ *
+ * Atomically replaces the decoder decoder held in @old_decoder_ptr
+ * with @new_decoder. This means that @old_decoder_ptr shall reference
+ * a valid decoder. However, @new_decoder can be NULL.
+ */
+void
+gst_vaapi_decoder_replace (GstVaapiDecoder ** old_decoder_ptr,
+    GstVaapiDecoder * new_decoder)
+{
+  gst_object_replace ((GstObject **) old_decoder_ptr, GST_OBJECT (new_decoder));
+}
+
+/**
+ * gst_vaapi_decoder_get_user_data:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Retrieves the user-defined data associated with the @decoder, if any.
+ *
+ * Return value: the user-defined data associated with the @decoder
+ */
+gpointer
+gst_vaapi_decoder_get_user_data (GstVaapiDecoder * decoder)
+{
+  g_return_val_if_fail (decoder != NULL, NULL);
+
+  return decoder->user_data;
+}
+
+/**
+ * gst_vaapi_decoder_set_user_data:
+ * @decoder: a #GstVaapiDecoder
+ * @user_data: the pointer to user-defined data
+ *
+ * Associates user-defined @user_data to the @decoder. Retrieve the
+ * attached value with gst_vaapi_decoder_get_user_data() function.
+ */
+void
+gst_vaapi_decoder_set_user_data (GstVaapiDecoder * decoder, gpointer user_data)
+{
+  g_return_if_fail (decoder != NULL);
+
+  decoder->user_data = user_data;
+}
+
+/**
+ * gst_vaapi_decoder_get_codec:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Retrieves the @decoder codec type.
+ *
+ * Return value: the #GstVaapiCodec type for @decoder
+ */
+GstVaapiCodec
+gst_vaapi_decoder_get_codec (GstVaapiDecoder * decoder)
+{
+  g_return_val_if_fail (decoder != NULL, (GstVaapiCodec) 0);
+
+  return decoder->codec;
+}
+
+/**
+ * gst_vaapi_decoder_get_codec_state:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Retrieves the @decoder codec state. The decoder owns the returned
+ * #GstVideoCodecState structure, so use gst_video_codec_state_ref()
+ * whenever necessary.
+ *
+ * Return value: the #GstVideoCodecState object for @decoder
+ */
+GstVideoCodecState *
+gst_vaapi_decoder_get_codec_state (GstVaapiDecoder * decoder)
+{
+  g_return_val_if_fail (decoder != NULL, NULL);
+
+  return GST_VAAPI_DECODER_CODEC_STATE (decoder);
+}
+
+/**
+ * gst_vaapi_decoder_set_codec_state_changed_func:
+ * @decoder: a #GstVaapiDecoder
+ * @func: the function to call when codec state changed
+ * @user_data: a pointer to user-defined data
+ *
+ * Sets @func as the function to call whenever the @decoder codec
+ * state changes.
+ */
+void
+gst_vaapi_decoder_set_codec_state_changed_func (GstVaapiDecoder * decoder,
+    GstVaapiDecoderStateChangedFunc func, gpointer user_data)
+{
+  g_return_if_fail (decoder != NULL);
+
+  decoder->codec_state_changed_func = func;
+  decoder->codec_state_changed_data = user_data;
+}
+
+/**
+ * gst_vaapi_decoder_get_caps:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Retrieves the @decoder caps. The decoder owns the returned caps, so
+ * use gst_caps_ref() whenever necessary.
+ *
+ * Returns: (transfer none): the @decoder caps
+ */
+GstCaps *
+gst_vaapi_decoder_get_caps (GstVaapiDecoder * decoder)
+{
+  return get_caps (decoder);
+}
+
+/**
+ * gst_vaapi_decoder_put_buffer:
+ * @decoder: a #GstVaapiDecoder
+ * @buf: a #GstBuffer
+ *
+ * Queues a #GstBuffer to the HW decoder. The decoder holds a
+ * reference to @buf.
+ *
+ * Caller can notify an End-Of-Stream with @buf set to %NULL. However,
+ * if an empty buffer is passed, i.e. a buffer with %NULL data pointer
+ * or size equals to zero, then the function ignores this buffer and
+ * returns %TRUE.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_decoder_put_buffer (GstVaapiDecoder * decoder, GstBuffer * buf)
+{
+  g_return_val_if_fail (decoder != NULL, FALSE);
+
+  if (buf) {
+    if (gst_buffer_get_size (buf) == 0)
+      return TRUE;
+    buf = gst_buffer_ref (buf);
+  }
+  return push_buffer (decoder, buf);
+}
+
+/**
+ * gst_vaapi_decoder_get_surface:
+ * @decoder: a #GstVaapiDecoder
+ * @out_proxy_ptr: the next decoded surface as a #GstVaapiSurfaceProxy
+ *
+ * Flushes encoded buffers to the decoder and returns a decoded
+ * surface, if any.
+ *
+ * On successful return, *@out_proxy_ptr contains the decoded surface
+ * as a #GstVaapiSurfaceProxy. The caller owns this object, so
+ * gst_vaapi_surface_proxy_unref() shall be called after usage.
+ *
+ * Return value: a #GstVaapiDecoderStatus
+ */
+GstVaapiDecoderStatus
+gst_vaapi_decoder_get_surface (GstVaapiDecoder * decoder,
+    GstVaapiSurfaceProxy ** out_proxy_ptr)
+{
+  GstVideoCodecFrame *frame;
+  GstVaapiDecoderStatus status;
+
+  g_return_val_if_fail (decoder != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (out_proxy_ptr != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+
+  do {
+    frame = pop_frame (decoder, 0);
+    while (frame) {
+      if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY (frame)) {
+        GstVaapiSurfaceProxy *const proxy = frame->user_data;
+        proxy->timestamp = frame->pts;
+        proxy->duration = frame->duration;
+        *out_proxy_ptr = gst_vaapi_surface_proxy_ref (proxy);
+        gst_video_codec_frame_unref (frame);
+        return GST_VAAPI_DECODER_STATUS_SUCCESS;
+      }
+      gst_video_codec_frame_unref (frame);
+      frame = pop_frame (decoder, 0);
+    }
+    status = decode_step (decoder);
+  } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
+
+  *out_proxy_ptr = NULL;
+  return status;
+}
+
+/**
+ * gst_vaapi_decoder_get_frame:
+ * @decoder: a #GstVaapiDecoder
+ * @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame
+ *
+ * On successful return, *@out_frame_ptr contains the next decoded
+ * frame available as a #GstVideoCodecFrame. The caller owns this
+ * object, so gst_video_codec_frame_unref() shall be called after
+ * usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is
+ * returned if no decoded frame is available.
+ *
+ * The actual surface is available as a #GstVaapiSurfaceProxy attached
+ * to the user-data anchor of the output frame. Ownership of the proxy
+ * is transferred to the frame.
+ *
+ * This is equivalent to gst_vaapi_decoder_get_frame_with_timeout()
+ * with a timeout value of zero.
+ *
+ * Return value: a #GstVaapiDecoderStatus
+ */
+GstVaapiDecoderStatus
+gst_vaapi_decoder_get_frame (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame ** out_frame_ptr)
+{
+  return gst_vaapi_decoder_get_frame_with_timeout (decoder, out_frame_ptr, 0);
+}
+
+/**
+ * gst_vaapi_decoder_get_frame_with_timeout:
+ * @decoder: a #GstVaapiDecoder
+ * @out_frame_ptr: the next decoded frame as a #GstVideoCodecFrame
+ * @timeout: the number of microseconds to wait for the frame, at most
+ *
+ * On successful return, *@out_frame_ptr contains the next decoded
+ * frame available as a #GstVideoCodecFrame. The caller owns this
+ * object, so gst_video_codec_frame_unref() shall be called after
+ * usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA is
+ * returned if no decoded frame is available.
+ *
+ * The actual surface is available as a #GstVaapiSurfaceProxy attached
+ * to the user-data anchor of the output frame. Ownership of the proxy
+ * is transferred to the frame.
+ *
+ * Return value: a #GstVaapiDecoderStatus
+ */
+GstVaapiDecoderStatus
+gst_vaapi_decoder_get_frame_with_timeout (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame ** out_frame_ptr, guint64 timeout)
+{
+  GstVideoCodecFrame *out_frame;
+
+  g_return_val_if_fail (decoder != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (out_frame_ptr != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+
+  out_frame = pop_frame (decoder, timeout);
+  if (!out_frame)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  *out_frame_ptr = out_frame;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+void
+gst_vaapi_decoder_set_picture_size (GstVaapiDecoder * decoder,
+    guint width, guint height)
+{
+  GstVideoCodecState *const codec_state = decoder->codec_state;
+  gboolean size_changed = FALSE;
+
+  if (codec_state->info.width != width) {
+    GST_DEBUG ("picture width changed to %d", width);
+    codec_state->info.width = width;
+    gst_caps_set_simple (codec_state->caps, "width", G_TYPE_INT, width, NULL);
+    size_changed = TRUE;
+  }
+
+  if (codec_state->info.height != height) {
+    GST_DEBUG ("picture height changed to %d", height);
+    codec_state->info.height = height;
+    gst_caps_set_simple (codec_state->caps, "height", G_TYPE_INT, height, NULL);
+    size_changed = TRUE;
+  }
+
+  if (size_changed)
+    notify_codec_state_changed (decoder);
+}
+
+void
+gst_vaapi_decoder_set_framerate (GstVaapiDecoder * decoder,
+    guint fps_n, guint fps_d)
+{
+  GstVideoCodecState *const codec_state = decoder->codec_state;
+
+  if (!fps_n || !fps_d)
+    return;
+
+  if (codec_state->info.fps_n != fps_n || codec_state->info.fps_d != fps_d) {
+    GST_DEBUG ("framerate changed to %u/%u", fps_n, fps_d);
+    codec_state->info.fps_n = fps_n;
+    codec_state->info.fps_d = fps_d;
+    gst_caps_set_simple (codec_state->caps,
+        "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
+    notify_codec_state_changed (decoder);
+  }
+}
+
+void
+gst_vaapi_decoder_set_pixel_aspect_ratio (GstVaapiDecoder * decoder,
+    guint par_n, guint par_d)
+{
+  GstVideoCodecState *const codec_state = decoder->codec_state;
+
+  if (!par_n || !par_d)
+    return;
+
+  if (codec_state->info.par_n != par_n || codec_state->info.par_d != par_d) {
+    GST_DEBUG ("pixel-aspect-ratio changed to %u/%u", par_n, par_d);
+    codec_state->info.par_n = par_n;
+    codec_state->info.par_d = par_d;
+    gst_caps_set_simple (codec_state->caps,
+        "pixel-aspect-ratio", GST_TYPE_FRACTION, par_n, par_d, NULL);
+    notify_codec_state_changed (decoder);
+  }
+}
+
+static const gchar *
+gst_interlace_mode_to_string (GstVideoInterlaceMode mode)
+{
+  switch (mode) {
+    case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
+      return "progressive";
+    case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
+      return "interleaved";
+    case GST_VIDEO_INTERLACE_MODE_MIXED:
+      return "mixed";
+    default:
+      return "<unknown>";
+  }
+}
+
+void
+gst_vaapi_decoder_set_interlace_mode (GstVaapiDecoder * decoder,
+    GstVideoInterlaceMode mode)
+{
+  GstVideoCodecState *const codec_state = decoder->codec_state;
+
+  if (codec_state->info.interlace_mode != mode) {
+    GST_DEBUG ("interlace mode changed to %s",
+        gst_interlace_mode_to_string (mode));
+    codec_state->info.interlace_mode = mode;
+    gst_caps_set_simple (codec_state->caps, "interlaced",
+        G_TYPE_BOOLEAN, mode != GST_VIDEO_INTERLACE_MODE_PROGRESSIVE, NULL);
+    notify_codec_state_changed (decoder);
+  }
+}
+
+void
+gst_vaapi_decoder_set_interlaced (GstVaapiDecoder * decoder,
+    gboolean interlaced)
+{
+  gst_vaapi_decoder_set_interlace_mode (decoder,
+      (interlaced ?
+          GST_VIDEO_INTERLACE_MODE_INTERLEAVED :
+          GST_VIDEO_INTERLACE_MODE_PROGRESSIVE));
+}
+
+void
+gst_vaapi_decoder_set_multiview_mode (GstVaapiDecoder * decoder,
+    gint views, GstVideoMultiviewMode mv_mode, GstVideoMultiviewFlags mv_flags)
+{
+  GstVideoCodecState *const codec_state = decoder->codec_state;
+  GstVideoInfo *info = &codec_state->info;
+
+  if (GST_VIDEO_INFO_VIEWS (info) != views ||
+      GST_VIDEO_INFO_MULTIVIEW_MODE (info) != mv_mode ||
+      GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) != mv_flags) {
+    const gchar *mv_mode_str =
+        gst_video_multiview_mode_to_caps_string (mv_mode);
+
+    GST_DEBUG ("Multiview mode changed to %s flags 0x%x views %d",
+        mv_mode_str, mv_flags, views);
+    GST_VIDEO_INFO_MULTIVIEW_MODE (info) = mv_mode;
+    GST_VIDEO_INFO_MULTIVIEW_FLAGS (info) = mv_flags;
+    GST_VIDEO_INFO_VIEWS (info) = views;
+
+    gst_caps_set_simple (codec_state->caps, "multiview-mode",
+        G_TYPE_STRING, mv_mode_str,
+        "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET, mv_flags,
+        GST_FLAG_SET_MASK_EXACT, "views", G_TYPE_INT, views, NULL);
+
+    notify_codec_state_changed (decoder);
+  }
+}
+
+gboolean
+gst_vaapi_decoder_ensure_context (GstVaapiDecoder * decoder,
+    GstVaapiContextInfo * cip)
+{
+  gst_vaapi_decoder_set_picture_size (decoder, cip->width, cip->height);
+
+  cip->usage = GST_VAAPI_CONTEXT_USAGE_DECODE;
+  if (decoder->context) {
+    if (!gst_vaapi_context_reset (decoder->context, cip))
+      return FALSE;
+  } else {
+    decoder->context = gst_vaapi_context_new (decoder->display, cip);
+    if (!decoder->context)
+      return FALSE;
+  }
+  decoder->va_context = gst_vaapi_context_get_id (decoder->context);
+  return TRUE;
+}
+
+void
+gst_vaapi_decoder_push_frame (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame * frame)
+{
+  push_frame (decoder, frame);
+}
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_parse (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame * base_frame, GstAdapter * adapter, gboolean at_eos,
+    guint * got_unit_size_ptr, gboolean * got_frame_ptr)
+{
+  g_return_val_if_fail (decoder != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (base_frame != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (adapter != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (got_unit_size_ptr != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (got_frame_ptr != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+
+  return do_parse (decoder, base_frame, adapter, at_eos,
+      got_unit_size_ptr, got_frame_ptr);
+}
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_decode (GstVaapiDecoder * decoder, GstVideoCodecFrame * frame)
+{
+  g_return_val_if_fail (decoder != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (frame != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (frame->user_data != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+
+  return do_decode (decoder, frame);
+}
+
+/* This function really marks the end of input,
+ * so that the decoder will drain out any pending
+ * frames on calls to gst_vaapi_decoder_get_frame_with_timeout() */
+GstVaapiDecoderStatus
+gst_vaapi_decoder_flush (GstVaapiDecoder * decoder)
+{
+  GstVaapiDecoderClass *klass;
+
+  g_return_val_if_fail (decoder != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+
+  klass = GST_VAAPI_DECODER_GET_CLASS (decoder);
+
+  if (klass->flush)
+    return klass->flush (decoder);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+/* Reset the decoder instance to a clean state,
+ * clearing any pending decode state, without
+ * reallocating the entire decoder */
+GstVaapiDecoderStatus
+gst_vaapi_decoder_reset (GstVaapiDecoder * decoder)
+{
+  GstVaapiDecoderClass *klass;
+  GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  g_return_val_if_fail (decoder != NULL,
+      GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER);
+
+  klass = GST_VAAPI_DECODER_GET_CLASS (decoder);
+
+  GST_DEBUG ("Resetting decoder");
+
+  if (klass->reset) {
+    ret = klass->reset (decoder);
+  } else {
+    GST_WARNING_OBJECT (decoder, "missing reset() implementation");
+  }
+
+  if (ret != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return ret;
+
+  /* Clear any buffers and frame in the queues */
+  {
+    GstVideoCodecFrame *frame;
+    GstBuffer *buffer;
+
+    while ((frame = g_async_queue_try_pop (decoder->frames)) != NULL)
+      gst_video_codec_frame_unref (frame);
+
+    while ((buffer = g_async_queue_try_pop (decoder->buffers)) != NULL)
+      gst_buffer_unref (buffer);
+  }
+
+  parser_state_reset (&decoder->parser_state);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_decode_codec_data (GstVaapiDecoder * decoder)
+{
+  GstVaapiDecoderClass *const klass = GST_VAAPI_DECODER_GET_CLASS (decoder);
+  GstBuffer *const codec_data = GST_VAAPI_DECODER_CODEC_DATA (decoder);
+  GstVaapiDecoderStatus status;
+  GstMapInfo map_info;
+  const guchar *buf;
+  guint buf_size;
+
+  if (!codec_data)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* FIXME: add a meaningful error code? */
+  if (!klass->decode_codec_data)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_buffer_map (codec_data, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  buf = map_info.data;
+  buf_size = map_info.size;
+  if (G_LIKELY (buf && buf_size > 0))
+    status = klass->decode_codec_data (decoder, buf, buf_size);
+  else
+    status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  gst_buffer_unmap (codec_data, &map_info);
+  return status;
+}
+
+/**
+ * gst_vaapi_decoder_update_caps:
+ * @decoder: a #GstVaapiDecoder
+ * @caps: a #GstCaps
+ *
+ * If @caps is compatible with the current caps, or they have the same
+ * codec, the caps are updated internally.
+ *
+ * This method will not call codec_state_changed() callback, since
+ * this function is intended to run sync and during the set_format()
+ * vmethod.
+ *
+ * Returns: %TRUE if the caps were updated internally.
+ **/
+gboolean
+gst_vaapi_decoder_update_caps (GstVaapiDecoder * decoder, GstCaps * caps)
+{
+  GstCaps *decoder_caps;
+  GstVaapiCodec codec;
+
+  g_return_val_if_fail (decoder != NULL, FALSE);
+  g_return_val_if_fail (caps != NULL, FALSE);
+
+  decoder_caps = get_caps (decoder);
+  if (!decoder_caps)
+    return FALSE;
+
+  if (gst_caps_is_always_compatible (caps, decoder_caps))
+    return set_caps (decoder, caps);
+
+  codec = gst_vaapi_get_codec_from_caps (caps);
+  if (codec == 0)
+    return FALSE;
+  if (codec == decoder->codec) {
+    if (set_caps (decoder, caps)) {
+      return
+          gst_vaapi_decoder_decode_codec_data (decoder) ==
+          GST_VAAPI_DECODER_STATUS_SUCCESS;
+    }
+  }
+
+  return FALSE;
+}
+
+/**
+ * gst_vaapi_decoder_get_surface_attributres:
+ * @decoder: a #GstVaapiDecoder instances
+ * @min_width (out): the minimal surface width
+ * @min_height (out): the minimal surface height
+ * @max_width (out): the maximal surface width
+ * @max_height (out): the maximal surface height
+ *
+ * Fetches the valid surface's attributes for the current context.
+ *
+ * Returns: a #GArray of valid formats we get or %NULL if failed.
+ **/
+GArray *
+gst_vaapi_decoder_get_surface_attributes (GstVaapiDecoder * decoder,
+    gint * min_width, gint * min_height, gint * max_width, gint * max_height,
+    guint * mem_types)
+{
+  gboolean ret;
+  GstVaapiConfigSurfaceAttributes attribs = { 0, };
+
+  g_return_val_if_fail (decoder != NULL, FALSE);
+
+  if (!decoder->context)
+    return NULL;
+
+  ret = gst_vaapi_context_get_surface_attributes (decoder->context, &attribs);
+  if (ret)
+    attribs.formats = gst_vaapi_context_get_surface_formats (decoder->context);
+
+  if (!attribs.formats)
+    return NULL;
+  if (attribs.formats->len == 0) {
+    g_array_unref (attribs.formats);
+    return NULL;
+  }
+
+  if (min_width)
+    *min_width = attribs.min_width;
+  if (min_height)
+    *min_height = attribs.min_height;
+  if (max_width)
+    *max_width = attribs.max_width;
+  if (max_height)
+    *max_height = attribs.max_height;
+  if (mem_types)
+    *mem_types = attribs.mem_types;
+  return attribs.formats;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder.h
new file mode 100644 (file)
index 0000000..2c55e2e
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ *  gstvaapidecoder.h - VA decoder abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_H
+#define GST_VAAPI_DECODER_H
+
+#include <gst/gstbuffer.h>
+#include <gst/base/gstadapter.h>
+#include <gst/vaapi/gstvaapisurfaceproxy.h>
+#include <gst/video/gstvideoutils.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER \
+    (gst_vaapi_decoder_get_type ())
+#define GST_VAAPI_DECODER(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER, GstVaapiDecoder))
+#define GST_VAAPI_IS_DECODER(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER))
+
+typedef struct _GstVaapiDecoder GstVaapiDecoder;
+typedef void (*GstVaapiDecoderStateChangedFunc) (GstVaapiDecoder * decoder,
+    const GstVideoCodecState * codec_state, gpointer user_data);
+
+/**
+ * GstVaapiDecoderStatus:
+ * @GST_VAAPI_DECODER_STATUS_SUCCESS: Success.
+ * @GST_VAAPI_DECODER_STATUS_END_OF_STREAM: End-Of-Stream.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED: No memory left.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED: Decoder initialization failure.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC: Unsupported codec.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA: Not enough input data to decode.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE: No surface left to hold the decoded picture.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE: Invalid surface.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER: Invalid or unsupported bitstream data.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE: Unsupported codec profile.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT: Unsupported chroma format.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER: Unsupported parameter.
+ * @GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN: Unknown error.
+ *
+ * Decoder status for gst_vaapi_decoder_get_surface().
+ */
+typedef enum {
+  GST_VAAPI_DECODER_STATUS_SUCCESS = 0,
+  GST_VAAPI_DECODER_STATUS_END_OF_STREAM,
+  GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED,
+  GST_VAAPI_DECODER_STATUS_ERROR_INIT_FAILED,
+  GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC,
+  GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA,
+  GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE,
+  GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE,
+  GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER,
+  GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE,
+  GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT,
+  GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER,
+  GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN = -1
+} GstVaapiDecoderStatus;
+
+GType
+gst_vaapi_decoder_get_type (void) G_GNUC_CONST;
+
+void
+gst_vaapi_decoder_replace (GstVaapiDecoder ** old_decoder_ptr,
+    GstVaapiDecoder * new_decoder);
+
+gpointer
+gst_vaapi_decoder_get_user_data (GstVaapiDecoder * decoder);
+
+void
+gst_vaapi_decoder_set_user_data (GstVaapiDecoder * decoder, gpointer user_data);
+
+GstVaapiCodec
+gst_vaapi_decoder_get_codec (GstVaapiDecoder * decoder);
+
+GstVideoCodecState *
+gst_vaapi_decoder_get_codec_state (GstVaapiDecoder * decoder);
+
+void
+gst_vaapi_decoder_set_codec_state_changed_func (GstVaapiDecoder * decoder,
+    GstVaapiDecoderStateChangedFunc func, gpointer user_data);
+
+GstCaps *
+gst_vaapi_decoder_get_caps (GstVaapiDecoder * decoder);
+
+gboolean
+gst_vaapi_decoder_put_buffer (GstVaapiDecoder * decoder, GstBuffer * buf);
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_get_surface (GstVaapiDecoder * decoder,
+    GstVaapiSurfaceProxy ** out_proxy_ptr);
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_get_frame (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame ** out_frame_ptr);
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_get_frame_with_timeout (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame ** out_frame_ptr, guint64 timeout);
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_parse (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos,
+    guint * got_unit_size_ptr, gboolean * got_frame_ptr);
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_decode (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame * frame);
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_flush (GstVaapiDecoder * decoder);
+
+GstVaapiDecoderStatus
+gst_vaapi_decoder_reset (GstVaapiDecoder * decoder);
+
+gboolean
+gst_vaapi_decoder_update_caps (GstVaapiDecoder * decoder, GstCaps * caps);
+
+GArray *
+gst_vaapi_decoder_get_surface_attributes (GstVaapiDecoder * decoder,
+    gint * min_width, gint * min_height, gint * max_width, gint * max_height,
+    guint * mem_types);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoder, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_av1.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_av1.c
new file mode 100644 (file)
index 0000000..e8a0e31
--- /dev/null
@@ -0,0 +1,1273 @@
+/*
+ *  gstvaapidecoder_av1.c - AV1 decoder
+ *
+ *  Copyright (C) 2019-2020 Intel Corporation
+ *    Author: Junyan He <junyan.he@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_av1
+ * @short_description: AV1 decoder
+ */
+
+#include "sysdeps.h"
+#include <gst/codecparsers/gstav1parser.h>
+#include "gstvaapidecoder_av1.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+
+#include "gstvaapicompat.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_DECODER_AV1_CAST(decoder) ((GstVaapiDecoderAV1 *)(decoder))
+
+typedef struct _GstVaapiDecoderAV1Private GstVaapiDecoderAV1Private;
+typedef struct _GstVaapiDecoderAV1Class GstVaapiDecoderAV1Class;
+typedef struct _GstVaapiPictureAV1 GstVaapiPictureAV1;
+
+struct _GstVaapiDecoderAV1Private
+{
+  GstVaapiProfile profile;
+  guint width;
+  guint height;
+  gboolean reset_context;
+  GstVaapiPictureAV1 *current_picture;
+  gboolean annex_b;
+  GstAV1Parser *parser;
+  GstAV1SequenceHeaderOBU *seq_header;
+  GstVaapiPictureAV1 *ref_frames[GST_AV1_NUM_REF_FRAMES];
+};
+
+/**
+ * GstVaapiDecoderAV1:
+ *
+ * A decoder based on AV1.
+ */
+struct _GstVaapiDecoderAV1
+{
+  /*< private > */
+  GstVaapiDecoder parent_instance;
+  GstVaapiDecoderAV1Private priv;
+};
+
+/**
+ * GstVaapiDecoderAV1Class:
+ *
+ * A decoder class based on AV1.
+ */
+struct _GstVaapiDecoderAV1Class
+{
+  /*< private > */
+  GstVaapiDecoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiDecoderAV1, gst_vaapi_decoder_av1,
+    GST_TYPE_VAAPI_DECODER);
+
+/* ------------------------------------------------------------------------- */
+/* --- AV1 Parser Info                                                   --- */
+/* ------------------------------------------------------------------------- */
+typedef struct _GstVaapiParserInfoAV1 GstVaapiParserInfoAV1;
+struct _GstVaapiParserInfoAV1
+{
+  GstVaapiMiniObject parent_instance;
+  GstAV1OBU obu;
+  union
+  {
+    GstAV1SequenceHeaderOBU seq_header;
+    GstAV1MetadataOBU metadata;
+    GstAV1FrameHeaderOBU frame_header;
+    GstAV1TileListOBU tile_list;
+    GstAV1TileGroupOBU tile_group;
+    GstAV1FrameOBU frame;
+  };
+  /* The offset between input data and real OBU data */
+  gint data_offset;
+};
+
+static void
+parser_info_av1_finalize (GstVaapiParserInfoAV1 * pi)
+{
+}
+
+static inline const GstVaapiMiniObjectClass *
+parser_info_av1_class (void)
+{
+  static const GstVaapiMiniObjectClass GstVaapiParserInfoAV1Class = {
+    .size = sizeof (GstVaapiParserInfoAV1),
+    .finalize = (GDestroyNotify) parser_info_av1_finalize
+  };
+  return &GstVaapiParserInfoAV1Class;
+}
+
+static inline GstVaapiParserInfoAV1 *
+parser_info_av1_new (GstAV1OBU * obu)
+{
+  GstVaapiParserInfoAV1 *pi = (GstVaapiParserInfoAV1 *)
+      gst_vaapi_mini_object_new (parser_info_av1_class ());
+
+  if (pi)
+    pi->obu = *obu;
+
+  return pi;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- AV1 Picture                                                       --- */
+/* ------------------------------------------------------------------------- */
+struct _GstVaapiPictureAV1
+{
+  GstVaapiPicture base;
+  /* When apply_grain enabled, recon proxy is different from the display
+     proxy, otherwise the same. */
+  GstVaapiSurfaceProxy *recon_proxy;
+  GstAV1FrameHeaderOBU frame_header;
+  gboolean cloned;
+};
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiPictureAV1, gst_vaapi_picture_av1);
+
+void
+gst_vaapi_picture_av1_destroy (GstVaapiPictureAV1 * picture)
+{
+  if (picture->recon_proxy) {
+    gst_vaapi_surface_proxy_unref (picture->recon_proxy);
+    picture->recon_proxy = NULL;
+  }
+  gst_vaapi_picture_destroy (GST_VAAPI_PICTURE (picture));
+}
+
+gboolean
+gst_vaapi_picture_av1_create (GstVaapiPictureAV1 * picture,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  if (!gst_vaapi_picture_create (GST_VAAPI_PICTURE (picture), args))
+    return FALSE;
+
+  picture->recon_proxy = gst_vaapi_surface_proxy_ref (picture->base.proxy);
+  g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy) ==
+      picture->base.surface_id);
+
+  return TRUE;
+}
+
+static inline GstVaapiPictureAV1 *
+gst_vaapi_picture_av1_new (GstVaapiDecoderAV1 * decoder)
+{
+  GstVaapiPictureAV1 *picture;
+
+  picture = (GstVaapiPictureAV1 *)
+      gst_vaapi_codec_object_new (&GstVaapiPictureAV1Class,
+      GST_VAAPI_CODEC_BASE (decoder), NULL,
+      sizeof (VADecPictureParameterBufferAV1), NULL, 0, 0);
+
+  if (picture)
+    picture->cloned = FALSE;
+
+  return picture;
+}
+
+static const gchar *
+av1_obu_name (GstAV1OBUType type)
+{
+  switch (type) {
+    case GST_AV1_OBU_SEQUENCE_HEADER:
+      return "sequence header";
+    case GST_AV1_OBU_TEMPORAL_DELIMITER:
+      return "temporal delimiter";
+    case GST_AV1_OBU_FRAME_HEADER:
+      return "frame header";
+    case GST_AV1_OBU_TILE_GROUP:
+      return "tile group";
+    case GST_AV1_OBU_METADATA:
+      return "metadata";
+    case GST_AV1_OBU_FRAME:
+      return "frame";
+    case GST_AV1_OBU_REDUNDANT_FRAME_HEADER:
+      return "redundant frame header";
+    case GST_AV1_OBU_TILE_LIST:
+      return "tile list";
+    case GST_AV1_OBU_PADDING:
+      return "padding";
+    default:
+      return "unknown";
+  }
+
+  return NULL;
+}
+
+static GstVaapiChromaType
+av1_get_chroma_type (GstVaapiProfile profile,
+    GstAV1SequenceHeaderOBU * seq_header)
+{
+  /* 6.4.1:
+     seq_profile  Bit depth  Monochrome support  Chroma subsampling
+     0            8 or 10    Yes                 YUV 4:2:0
+     1            8 or 10    No                  YUV 4:4:4
+     2            8 or 10    Yes                 YUV 4:2:2
+     2            12         Yes                 YUV 4:2:0,YUV 4:2:2,YUV 4:4:4
+   */
+
+  /* TODO: consider Monochrome case. Just return 4:2:0 for Monochrome now. */
+  switch (profile) {
+    case GST_VAAPI_PROFILE_AV1_0:
+      if (seq_header->bit_depth == 8) {
+        return GST_VAAPI_CHROMA_TYPE_YUV420;
+      } else if (seq_header->bit_depth == 10) {
+        return GST_VAAPI_CHROMA_TYPE_YUV420_10BPP;
+      }
+      break;
+    case GST_VAAPI_PROFILE_AV1_1:
+      if (seq_header->bit_depth == 8) {
+        return GST_VAAPI_CHROMA_TYPE_YUV444;
+      } else if (seq_header->bit_depth == 10) {
+        return GST_VAAPI_CHROMA_TYPE_YUV444_10BPP;
+      }
+      break;
+    default:
+      break;
+  }
+
+  GST_WARNING ("can not decide chrome type.");
+  return 0;
+}
+
+static GstVaapiProfile
+av1_get_profile (guint profile_idc)
+{
+  GstVaapiProfile profile;
+
+  switch (profile_idc) {
+    case GST_AV1_PROFILE_0:
+      profile = GST_VAAPI_PROFILE_AV1_0;
+      break;
+    case GST_AV1_PROFILE_1:
+      profile = GST_VAAPI_PROFILE_AV1_1;
+      break;
+    default:
+      GST_INFO ("unsupported av1 profile_idc value %d", profile_idc);
+      profile = GST_VAAPI_PROFILE_UNKNOWN;
+      break;
+  }
+  return profile;
+}
+
+static GstVaapiDecoderStatus
+av1_decode_seqeunce (GstVaapiDecoderAV1 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderAV1Private *const priv = &decoder->priv;
+  GstVaapiProfile profile;
+  GstVaapiParserInfoAV1 *const pi = unit->parsed_info;
+
+  profile = av1_get_profile (pi->seq_header.seq_profile);
+  if (profile == GST_VAAPI_PROFILE_UNKNOWN)
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
+          profile, GST_VAAPI_ENTRYPOINT_VLD)) {
+    GST_WARNING ("not supported av1 profile %s",
+        gst_vaapi_profile_get_va_name (profile));
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  if (profile != priv->profile) {
+    GST_DEBUG ("new av1 profile %s", gst_vaapi_profile_get_va_name (profile));
+    /* We delay the context creation to when we know the frame resolution */
+    priv->reset_context = TRUE;
+    priv->profile = profile;
+  }
+
+  /* update the sequence */
+  if (priv->seq_header)
+    g_slice_free (GstAV1SequenceHeaderOBU, priv->seq_header);
+  priv->seq_header = g_slice_dup (GstAV1SequenceHeaderOBU, &pi->seq_header);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+av1_decoder_ensure_context (GstVaapiDecoderAV1 * decoder)
+{
+  GstVaapiDecoderAV1Private *const priv = &decoder->priv;
+  GstVaapiContextInfo info;
+
+  if (priv->reset_context) {
+    if (priv->current_picture)
+      gst_vaapi_picture_replace (&priv->current_picture, NULL);
+
+    info.profile = priv->profile;
+    info.entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+    info.width = priv->width;
+    info.height = priv->height;
+    info.chroma_type = av1_get_chroma_type (info.profile, priv->seq_header);
+    if (!info.chroma_type)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
+
+    info.ref_frames = GST_AV1_NUM_REF_FRAMES + 2;
+
+    priv->reset_context = FALSE;
+    if (!gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info)) {
+      GST_WARNING ("can not make av1 decoder context with profile %s,"
+          " width %d, height %d", gst_vaapi_profile_get_va_name (info.profile),
+          info.width, info.height);
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    }
+  }
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+av1_fill_segment_info (VADecPictureParameterBufferAV1 * pic_param,
+    GstAV1FrameHeaderOBU * frame_header)
+{
+  guint i, j;
+  uint8_t feature_mask;
+
+#define COPY_SEG_FIELD(FP, FS) \
+    pic_param->seg_info.segment_info_fields.bits.FP = \
+        (frame_header)->segmentation_params.FS
+
+  COPY_SEG_FIELD (enabled, segmentation_enabled);
+  COPY_SEG_FIELD (update_map, segmentation_update_map);
+  COPY_SEG_FIELD (temporal_update, segmentation_temporal_update);
+  COPY_SEG_FIELD (update_data, segmentation_update_data);
+  for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++)
+    for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++)
+      pic_param->seg_info.feature_data[i][j] =
+          frame_header->segmentation_params.feature_data[i][j];
+
+  for (i = 0; i < GST_AV1_MAX_SEGMENTS; i++) {
+    feature_mask = 0;
+    for (j = 0; j < GST_AV1_SEG_LVL_MAX; j++) {
+      if (frame_header->segmentation_params.feature_enabled[i][j])
+        feature_mask |= 1 << j;
+    }
+    pic_param->seg_info.feature_mask[i] = feature_mask;
+  }
+#undef COPY_SEG_FIELD
+}
+
+static void
+av1_fill_film_grain_info (VADecPictureParameterBufferAV1 * pic_param,
+    GstAV1FrameHeaderOBU * frame_header)
+{
+  guint i;
+
+  if (!frame_header->film_grain_params.apply_grain) {
+    memset (&pic_param->film_grain_info, 0, sizeof (VAFilmGrainStructAV1));
+    return;
+  }
+#define COPY_FILM_GRAIN_FIELD(FP) \
+    pic_param->SUB_FIELD.FP = (frame_header)->film_grain_params.FP
+#define SUB_FIELD film_grain_info.film_grain_info_fields.bits
+
+  COPY_FILM_GRAIN_FIELD (apply_grain);
+  COPY_FILM_GRAIN_FIELD (chroma_scaling_from_luma);
+  COPY_FILM_GRAIN_FIELD (grain_scaling_minus_8);
+  COPY_FILM_GRAIN_FIELD (ar_coeff_lag);
+  COPY_FILM_GRAIN_FIELD (ar_coeff_shift_minus_6);
+  COPY_FILM_GRAIN_FIELD (grain_scale_shift);
+  COPY_FILM_GRAIN_FIELD (overlap_flag);
+  COPY_FILM_GRAIN_FIELD (clip_to_restricted_range);
+#undef SUB_FIELD
+
+  pic_param->film_grain_info.grain_seed =
+      frame_header->film_grain_params.grain_seed;
+
+  pic_param->film_grain_info.num_y_points =
+      frame_header->film_grain_params.num_y_points;
+  for (i = 0; i < frame_header->film_grain_params.num_y_points; i++) {
+    pic_param->film_grain_info.point_y_value[i] =
+        frame_header->film_grain_params.point_y_value[i];
+    pic_param->film_grain_info.point_y_scaling[i] =
+        frame_header->film_grain_params.point_y_scaling[i];
+  }
+
+  pic_param->film_grain_info.num_cb_points =
+      frame_header->film_grain_params.num_cb_points;
+  for (i = 0; i < frame_header->film_grain_params.num_cb_points; i++) {
+    pic_param->film_grain_info.point_cb_value[i] =
+        frame_header->film_grain_params.point_cb_value[i];
+    pic_param->film_grain_info.point_cb_scaling[i] =
+        frame_header->film_grain_params.point_cb_scaling[i];
+  }
+
+  pic_param->film_grain_info.num_cr_points =
+      frame_header->film_grain_params.num_cr_points;
+  for (i = 0; i < frame_header->film_grain_params.num_cr_points; i++) {
+    pic_param->film_grain_info.point_cr_value[i] =
+        frame_header->film_grain_params.point_cr_value[i];
+    pic_param->film_grain_info.point_cr_scaling[i] =
+        frame_header->film_grain_params.point_cr_scaling[i];
+  }
+
+
+  if (pic_param->film_grain_info.num_y_points) {
+    for (i = 0; i < 24; i++) {
+      pic_param->film_grain_info.ar_coeffs_y[i] =
+          frame_header->film_grain_params.ar_coeffs_y_plus_128[i] - 128;
+    }
+  }
+  if (frame_header->film_grain_params.chroma_scaling_from_luma
+      || pic_param->film_grain_info.num_cb_points) {
+    for (i = 0; i < GST_AV1_MAX_NUM_POS_LUMA; i++) {
+      pic_param->film_grain_info.ar_coeffs_cb[i] =
+          frame_header->film_grain_params.ar_coeffs_cb_plus_128[i] - 128;
+    }
+  }
+  if (frame_header->film_grain_params.chroma_scaling_from_luma
+      || pic_param->film_grain_info.num_cr_points) {
+    for (i = 0; i < GST_AV1_MAX_NUM_POS_LUMA; i++) {
+      pic_param->film_grain_info.ar_coeffs_cr[i] =
+          frame_header->film_grain_params.ar_coeffs_cr_plus_128[i] - 128;
+    }
+  }
+#define SUB_FIELD film_grain_info
+  COPY_FILM_GRAIN_FIELD (cb_mult);
+  COPY_FILM_GRAIN_FIELD (cb_luma_mult);
+  COPY_FILM_GRAIN_FIELD (cb_offset);
+  COPY_FILM_GRAIN_FIELD (cr_mult);
+  COPY_FILM_GRAIN_FIELD (cr_luma_mult);
+  COPY_FILM_GRAIN_FIELD (cr_offset);
+#undef SUB_FIELD
+#undef COPY_FILM_GRAIN_FIELD
+}
+
+static void
+av1_fill_loop_filter_info (VADecPictureParameterBufferAV1 * pic_param,
+    GstAV1FrameHeaderOBU * frame_header)
+{
+  guint i;
+
+  pic_param->superres_scale_denominator = frame_header->superres_denom;
+  pic_param->interp_filter = frame_header->interpolation_filter;
+  pic_param->filter_level[0] =
+      frame_header->loop_filter_params.loop_filter_level[0];
+  pic_param->filter_level[1] =
+      frame_header->loop_filter_params.loop_filter_level[1];
+  pic_param->filter_level_u =
+      frame_header->loop_filter_params.loop_filter_level[2];
+  pic_param->filter_level_v =
+      frame_header->loop_filter_params.loop_filter_level[3];
+  pic_param->loop_filter_info_fields.bits.sharpness_level =
+      frame_header->loop_filter_params.loop_filter_sharpness;
+  pic_param->loop_filter_info_fields.bits.mode_ref_delta_enabled =
+      frame_header->loop_filter_params.loop_filter_delta_enabled;
+  pic_param->loop_filter_info_fields.bits.mode_ref_delta_update =
+      frame_header->loop_filter_params.loop_filter_delta_update;
+
+  for (i = 0; i < GST_AV1_TOTAL_REFS_PER_FRAME; i++)
+    pic_param->ref_deltas[i] =
+        frame_header->loop_filter_params.loop_filter_ref_deltas[i];
+  for (i = 0; i < 2; i++)
+    pic_param->mode_deltas[i] =
+        frame_header->loop_filter_params.loop_filter_mode_deltas[i];
+
+  pic_param->mode_control_fields.bits.delta_lf_present_flag =
+      frame_header->loop_filter_params.delta_lf_present;
+  pic_param->mode_control_fields.bits.log2_delta_lf_res =
+      frame_header->loop_filter_params.delta_lf_res;
+  pic_param->mode_control_fields.bits.delta_lf_multi =
+      frame_header->loop_filter_params.delta_lf_multi;
+}
+
+static void
+av1_fill_quantization_info (VADecPictureParameterBufferAV1 * pic_param,
+    GstAV1FrameHeaderOBU * frame_header)
+{
+  pic_param->base_qindex = frame_header->quantization_params.base_q_idx;
+  pic_param->y_dc_delta_q = frame_header->quantization_params.delta_q_y_dc;
+  pic_param->u_dc_delta_q = frame_header->quantization_params.delta_q_u_dc;
+  pic_param->u_ac_delta_q = frame_header->quantization_params.delta_q_u_ac;
+  pic_param->v_dc_delta_q = frame_header->quantization_params.delta_q_v_dc;
+  pic_param->v_ac_delta_q = frame_header->quantization_params.delta_q_v_ac;
+
+  pic_param->qmatrix_fields.bits.using_qmatrix =
+      frame_header->quantization_params.using_qmatrix;
+  if (pic_param->qmatrix_fields.bits.using_qmatrix) {
+    pic_param->qmatrix_fields.bits.qm_y =
+        frame_header->quantization_params.qm_y;
+    pic_param->qmatrix_fields.bits.qm_u =
+        frame_header->quantization_params.qm_u;
+    pic_param->qmatrix_fields.bits.qm_v =
+        frame_header->quantization_params.qm_v;
+  } else {
+    pic_param->qmatrix_fields.bits.qm_y = 0;
+    pic_param->qmatrix_fields.bits.qm_u = 0;
+    pic_param->qmatrix_fields.bits.qm_v = 0;
+  }
+
+  pic_param->mode_control_fields.bits.delta_q_present_flag =
+      frame_header->quantization_params.delta_q_present;
+  pic_param->mode_control_fields.bits.log2_delta_q_res =
+      frame_header->quantization_params.delta_q_res;
+}
+
+static void
+av1_fill_cdef_info (VADecPictureParameterBufferAV1 * pic_param,
+    GstAV1FrameHeaderOBU * frame_header, guint8 num_planes)
+{
+  guint8 sec_strength;
+  guint i;
+
+  pic_param->cdef_damping_minus_3 = frame_header->cdef_params.cdef_damping - 3;
+  pic_param->cdef_bits = frame_header->cdef_params.cdef_bits;
+  for (i = 0; i < GST_AV1_CDEF_MAX; i++) {
+    sec_strength = frame_header->cdef_params.cdef_y_sec_strength[i];
+    g_assert (sec_strength <= 4);
+    /* may need to minus 1 in order to merge with primary value. */
+    if (sec_strength == 4)
+      sec_strength--;
+
+    pic_param->cdef_y_strengths[i] =
+        ((frame_header->cdef_params.cdef_y_pri_strength[i] & 0xf) << 2) |
+        (sec_strength & 0x03);
+  }
+  if (num_planes > 1) {
+    for (i = 0; i < GST_AV1_CDEF_MAX; i++) {
+      sec_strength = frame_header->cdef_params.cdef_uv_sec_strength[i];
+      g_assert (sec_strength <= 4);
+      /* may need to minus 1 in order to merge with primary value. */
+      if (sec_strength == 4)
+        sec_strength--;
+
+      pic_param->cdef_uv_strengths[i] =
+          ((frame_header->cdef_params.cdef_uv_pri_strength[i] & 0xf) << 2) |
+          (sec_strength & 0x03);
+    }
+  } else {
+    for (i = 0; i < GST_AV1_CDEF_MAX; i++) {
+      pic_param->cdef_uv_strengths[i] = 0;
+    }
+  }
+}
+
+static void
+av1_fill_loop_restoration_info (VADecPictureParameterBufferAV1 * pic_param,
+    GstAV1FrameHeaderOBU * frame_header)
+{
+  pic_param->loop_restoration_fields.bits.yframe_restoration_type =
+      frame_header->loop_restoration_params.frame_restoration_type[0];
+  pic_param->loop_restoration_fields.bits.cbframe_restoration_type =
+      frame_header->loop_restoration_params.frame_restoration_type[1];
+  pic_param->loop_restoration_fields.bits.crframe_restoration_type =
+      frame_header->loop_restoration_params.frame_restoration_type[2];
+  pic_param->loop_restoration_fields.bits.lr_unit_shift =
+      frame_header->loop_restoration_params.lr_unit_shift;
+  pic_param->loop_restoration_fields.bits.lr_uv_shift =
+      frame_header->loop_restoration_params.lr_uv_shift;
+}
+
+static void
+av1_fill_global_motion_info (VADecPictureParameterBufferAV1 * pic_param,
+    GstAV1FrameHeaderOBU * frame_header)
+{
+  guint i, j;
+
+  for (i = 0; i < 7; i++) {
+    pic_param->wm[i].wmtype =
+        frame_header->global_motion_params.gm_type[GST_AV1_REF_LAST_FRAME + i];
+
+    for (j = 0; j < 6; j++)
+      pic_param->wm[i].wmmat[j] =
+          frame_header->global_motion_params.gm_params
+          [GST_AV1_REF_LAST_FRAME + i][j];
+
+    pic_param->wm[i].wmmat[6] = 0;
+    pic_param->wm[i].wmmat[7] = 0;
+
+    pic_param->wm[i].invalid =
+        frame_header->global_motion_params.invalid[GST_AV1_REF_LAST_FRAME + i];
+  }
+}
+
+static gboolean
+av1_fill_picture_frame_header (GstVaapiDecoderAV1 * decoder,
+    GstVaapiPictureAV1 * picture, GstAV1FrameHeaderOBU * frame_header)
+{
+  GstVaapiDecoderAV1Private *priv = &decoder->priv;
+  VADecPictureParameterBufferAV1 *pic_param =
+      GST_VAAPI_PICTURE (picture)->param;
+  GstAV1SequenceHeaderOBU *seq_header = priv->seq_header;
+  guint i;
+
+  pic_param->profile = seq_header->seq_profile;
+  pic_param->order_hint_bits_minus_1 = seq_header->order_hint_bits_minus_1;
+
+  if (seq_header->bit_depth == 8)
+    pic_param->bit_depth_idx = 0;
+  else if (seq_header->bit_depth == 10)
+    pic_param->bit_depth_idx = 1;
+  else if (seq_header->bit_depth == 12)
+    pic_param->bit_depth_idx = 2;
+  else
+    g_assert (0);
+
+  pic_param->matrix_coefficients = seq_header->color_config.matrix_coefficients;
+
+#define COPY_SEQ_FIELD(FP, FS) \
+    pic_param->seq_info_fields.fields.FP = (seq_header)->FS
+
+  COPY_SEQ_FIELD (still_picture, still_picture);
+  COPY_SEQ_FIELD (use_128x128_superblock, use_128x128_superblock);
+  COPY_SEQ_FIELD (enable_filter_intra, enable_filter_intra);
+  COPY_SEQ_FIELD (enable_intra_edge_filter, enable_intra_edge_filter);
+  COPY_SEQ_FIELD (enable_interintra_compound, enable_interintra_compound);
+  COPY_SEQ_FIELD (enable_masked_compound, enable_masked_compound);
+  COPY_SEQ_FIELD (enable_dual_filter, enable_dual_filter);
+  COPY_SEQ_FIELD (enable_order_hint, enable_order_hint);
+  COPY_SEQ_FIELD (enable_jnt_comp, enable_jnt_comp);
+  COPY_SEQ_FIELD (enable_cdef, enable_cdef);
+  COPY_SEQ_FIELD (mono_chrome, color_config.mono_chrome);
+  COPY_SEQ_FIELD (color_range, color_config.color_range);
+  COPY_SEQ_FIELD (subsampling_x, color_config.subsampling_x);
+  COPY_SEQ_FIELD (subsampling_y, color_config.subsampling_y);
+  COPY_SEQ_FIELD (film_grain_params_present, film_grain_params_present);
+#undef COPY_SEQ_FIELD
+
+  if (frame_header->film_grain_params.apply_grain) {
+    g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy) !=
+        GST_VAAPI_PICTURE (picture)->surface_id);
+    pic_param->current_frame =
+        GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy);
+    pic_param->current_display_picture =
+        GST_VAAPI_PICTURE (picture)->surface_id;
+  } else {
+    pic_param->current_frame = GST_VAAPI_PICTURE (picture)->surface_id;
+    pic_param->current_display_picture =
+        GST_VAAPI_PICTURE (picture)->surface_id;
+  }
+
+  pic_param->frame_width_minus1 = frame_header->upscaled_width - 1;
+  pic_param->frame_height_minus1 = frame_header->frame_height - 1;
+
+  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
+    if (priv->ref_frames[i])
+      pic_param->ref_frame_map[i] =
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (priv->ref_frames[i]->recon_proxy);
+    else
+      pic_param->ref_frame_map[i] = VA_INVALID_SURFACE;
+  }
+  for (i = 0; i < GST_AV1_REFS_PER_FRAME; i++) {
+    pic_param->ref_frame_idx[i] = frame_header->ref_frame_idx[i];
+  }
+  pic_param->primary_ref_frame = frame_header->primary_ref_frame;
+  pic_param->order_hint = frame_header->order_hint;
+
+  av1_fill_segment_info (pic_param, frame_header);
+  av1_fill_film_grain_info (pic_param, frame_header);
+
+  pic_param->tile_cols = frame_header->tile_info.tile_cols;
+  pic_param->tile_rows = frame_header->tile_info.tile_rows;
+  for (i = 0; i < 63; i++) {
+    pic_param->width_in_sbs_minus_1[i] =
+        frame_header->tile_info.width_in_sbs_minus_1[i];
+    pic_param->height_in_sbs_minus_1[i] =
+        frame_header->tile_info.height_in_sbs_minus_1[i];
+  }
+
+  pic_param->context_update_tile_id =
+      frame_header->tile_info.context_update_tile_id;
+
+#define COPY_PIC_FIELD(FIELD) \
+    pic_param->pic_info_fields.bits.FIELD = (frame_header)->FIELD
+
+  COPY_PIC_FIELD (frame_type);
+  COPY_PIC_FIELD (show_frame);
+  COPY_PIC_FIELD (showable_frame);
+  COPY_PIC_FIELD (error_resilient_mode);
+  COPY_PIC_FIELD (disable_cdf_update);
+  COPY_PIC_FIELD (allow_screen_content_tools);
+  COPY_PIC_FIELD (force_integer_mv);
+  COPY_PIC_FIELD (allow_intrabc);
+  COPY_PIC_FIELD (use_superres);
+  COPY_PIC_FIELD (allow_high_precision_mv);
+  COPY_PIC_FIELD (is_motion_mode_switchable);
+  COPY_PIC_FIELD (use_ref_frame_mvs);
+  COPY_PIC_FIELD (disable_frame_end_update_cdf);
+  pic_param->pic_info_fields.bits.uniform_tile_spacing_flag =
+      frame_header->tile_info.uniform_tile_spacing_flag;
+  COPY_PIC_FIELD (allow_warped_motion);
+#undef COPY_PIC_FIELD
+
+  av1_fill_loop_filter_info (pic_param, frame_header);
+  av1_fill_quantization_info (pic_param, frame_header);
+
+  pic_param->mode_control_fields.bits.tx_mode = frame_header->tx_mode;
+  pic_param->mode_control_fields.bits.reference_select =
+      frame_header->reference_select;
+  pic_param->mode_control_fields.bits.reduced_tx_set_used =
+      frame_header->reduced_tx_set;
+  pic_param->mode_control_fields.bits.skip_mode_present =
+      frame_header->skip_mode_present;
+
+  av1_fill_cdef_info (pic_param, frame_header, seq_header->num_planes);
+  av1_fill_loop_restoration_info (pic_param, frame_header);
+  av1_fill_global_motion_info (pic_param, frame_header);
+
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+av1_decode_frame_header (GstVaapiDecoderAV1 * decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderAV1Private *const priv = &decoder->priv;
+  GstVaapiParserInfoAV1 *const pi = unit->parsed_info;
+  GstAV1FrameHeaderOBU *frame_header = NULL;
+  GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  GstVaapiPictureAV1 *picture = NULL;
+
+  if (pi->obu.obu_type == GST_AV1_OBU_FRAME_HEADER) {
+    frame_header = &pi->frame_header;
+  } else {
+    g_assert (pi->obu.obu_type == GST_AV1_OBU_FRAME);
+    frame_header = &pi->frame.frame_header;
+  }
+
+  if (frame_header->show_existing_frame) {
+    GstVaapiPictureAV1 *to_show_picture = NULL;
+
+    to_show_picture = priv->ref_frames[frame_header->frame_to_show_map_idx];
+    if (to_show_picture == NULL) {
+      GST_ERROR ("frame_to_show_map_idx point to a invalid picture");
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    }
+
+    picture = (GstVaapiPictureAV1 *)
+        gst_vaapi_picture_new_clone (GST_VAAPI_PICTURE_CAST (to_show_picture));
+    if (!picture)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
+    gst_vaapi_surface_proxy_replace (&picture->recon_proxy,
+        to_show_picture->recon_proxy);
+    picture->cloned = TRUE;
+    GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
+
+    picture->frame_header = to_show_picture->frame_header;
+  } else {
+    /* Resolution changed */
+    if (priv->width != priv->seq_header->max_frame_width_minus_1 + 1 ||
+        priv->height != priv->seq_header->max_frame_height_minus_1 + 1) {
+      priv->reset_context = TRUE;
+      priv->width = priv->seq_header->max_frame_width_minus_1 + 1;
+      priv->height = priv->seq_header->max_frame_height_minus_1 + 1;
+      GST_INFO ("change the resolution to %dx%d", priv->width, priv->height);
+    }
+
+    ret = av1_decoder_ensure_context (decoder);
+    if (ret != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return ret;
+
+    picture = gst_vaapi_picture_av1_new (decoder);
+    if (!picture)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
+
+    if (frame_header->upscaled_width != priv->width ||
+        frame_header->frame_height != priv->height) {
+      GstVaapiRectangle crop_rect;
+
+      if (frame_header->upscaled_width > priv->width) {
+        GST_WARNING ("Frame width is %d, bigger than sequence max width %d",
+            frame_header->upscaled_width, priv->width);
+        gst_vaapi_codec_object_unref (picture);
+        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+      }
+      if (frame_header->frame_height > priv->height) {
+        GST_WARNING ("Frame height is %d, bigger than sequence max height %d",
+            frame_header->frame_height, priv->height);
+        gst_vaapi_codec_object_unref (picture);
+        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+      }
+
+      crop_rect.x = 0;
+      crop_rect.y = 0;
+      crop_rect.width = frame_header->upscaled_width;
+      crop_rect.height = frame_header->frame_height;
+      gst_vaapi_picture_set_crop_rect (GST_VAAPI_PICTURE (picture), &crop_rect);
+    }
+
+    if (frame_header->film_grain_params.apply_grain) {
+      GstVaapiSurfaceProxy *recon_proxy = gst_vaapi_context_get_surface_proxy
+          (GST_VAAPI_DECODER (decoder)->context);
+      if (!recon_proxy) {
+        gst_vaapi_codec_object_unref (picture);
+        return GST_VAAPI_DECODER_STATUS_ERROR_NO_SURFACE;
+      }
+      gst_vaapi_surface_proxy_replace (&picture->recon_proxy, recon_proxy);
+    }
+
+    picture->frame_header = *frame_header;
+
+    /* this frame will not show this time */
+    if (!frame_header->show_frame)
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
+
+    GST_VAAPI_PICTURE (picture)->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+    GST_VAAPI_PICTURE (picture)->type =
+        frame_header->frame_is_intra ? GST_VAAPI_PICTURE_TYPE_I :
+        GST_VAAPI_PICTURE_TYPE_P;
+
+    if (!av1_fill_picture_frame_header (decoder, picture, frame_header)) {
+      gst_vaapi_codec_object_unref (picture);
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    }
+  }
+
+  gst_vaapi_picture_replace (&priv->current_picture, picture);
+  gst_vaapi_picture_unref (picture);
+
+  return ret;
+}
+
+static GstVaapiDecoderStatus
+av1_decode_tile_data (GstVaapiDecoderAV1 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderAV1Private *const priv = &decoder->priv;
+  GstVaapiPictureAV1 *picture = priv->current_picture;
+  GstVaapiParserInfoAV1 *const pi = unit->parsed_info;
+  GstAV1TileGroupOBU *tile_group = &pi->tile_group;
+  guint32 i;
+  GstVaapiSlice *slice;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  if (!picture) {
+    GST_WARNING ("Decode the tile date without a picture");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  slice = GST_VAAPI_SLICE_NEW_N_PARAMS (AV1, decoder,
+      map_info.data + pi->data_offset + unit->offset, pi->obu.obu_size,
+      (tile_group->tg_end - tile_group->tg_start + 1));
+  gst_buffer_unmap (buffer, &map_info);
+  if (!slice) {
+    GST_ERROR ("failed to allocate slice");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  for (i = 0; i < tile_group->tg_end - tile_group->tg_start + 1; i++) {
+    VASliceParameterBufferAV1 *const slice_param =
+        slice->param + i * sizeof (VASliceParameterBufferAV1);
+
+    slice_param->slice_data_size =
+        tile_group->entry[tile_group->tg_start + i].tile_size;
+    slice_param->slice_data_offset =
+        tile_group->entry[tile_group->tg_start + i].tile_offset;
+    slice_param->tile_row =
+        tile_group->entry[tile_group->tg_start + i].tile_row;
+    slice_param->tile_column =
+        tile_group->entry[tile_group->tg_start + i].tile_col;
+    slice_param->slice_data_flag = 0;
+  }
+
+  gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+av1_decode_unit (GstVaapiDecoderAV1 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  GstVaapiParserInfoAV1 *const pi = unit->parsed_info;
+
+  GST_DEBUG ("begin to decode the unit of %s", av1_obu_name (pi->obu.obu_type));
+
+  switch (pi->obu.obu_type) {
+    case GST_AV1_OBU_SEQUENCE_HEADER:
+      ret = av1_decode_seqeunce (decoder, unit);
+      break;
+    case GST_AV1_OBU_FRAME_HEADER:
+      ret = av1_decode_frame_header (decoder, unit);
+      break;
+    case GST_AV1_OBU_FRAME:
+      ret = av1_decode_frame_header (decoder, unit);
+      if (ret != GST_VAAPI_DECODER_STATUS_SUCCESS)
+        break;
+      /* fall through */
+    case GST_AV1_OBU_TILE_GROUP:
+      ret = av1_decode_tile_data (decoder, unit);
+      break;
+    case GST_AV1_OBU_METADATA:
+    case GST_AV1_OBU_REDUNDANT_FRAME_HEADER:
+    case GST_AV1_OBU_PADDING:
+      /* Not handled */
+      ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+    default:
+      GST_WARNING ("can not handle obu type %s",
+          av1_obu_name (pi->obu.obu_type));
+      ret = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  return ret;
+}
+
+static GstVaapiDecoderStatus
+av1_decode_current_picture (GstVaapiDecoderAV1 * decoder)
+{
+  GstVaapiDecoderAV1Private *priv = &decoder->priv;
+  GstVaapiPictureAV1 *const picture =
+      (GstVaapiPictureAV1 *) priv->current_picture;
+
+  g_assert (picture);
+
+  if (!gst_vaapi_picture_decode_with_surface_id (GST_VAAPI_PICTURE (picture),
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->recon_proxy)))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+av1_decoder_update_state (GstVaapiDecoderAV1 * decoder,
+    GstVaapiPictureAV1 * picture)
+{
+  GstVaapiDecoderAV1Private *priv = &decoder->priv;
+  GstAV1ParserResult ret;
+  guint i;
+
+  /* This is a show_existing_frame case, only update key frame */
+  if (picture->cloned && picture->frame_header.frame_type != GST_AV1_KEY_FRAME)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  ret = gst_av1_parser_reference_frame_update (priv->parser,
+      &picture->frame_header);
+  if (ret != GST_AV1_PARSER_OK) {
+    GST_ERROR ("failed to update the reference.");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++) {
+    if ((picture->frame_header.refresh_frame_flags >> i) & 1) {
+      GST_LOG ("reference frame %p to ref slot:%d", picture, i);
+      gst_vaapi_picture_replace (&priv->ref_frames[i], picture);
+    }
+  }
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+av1_decoder_reset (GstVaapiDecoderAV1 * decoder)
+{
+  GstVaapiDecoderAV1Private *priv = &decoder->priv;
+  guint i;
+
+  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  priv->width = 0;
+  priv->height = 0;
+  priv->annex_b = FALSE;
+  priv->reset_context = FALSE;
+
+  if (priv->current_picture)
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+
+  if (priv->seq_header) {
+    g_slice_free (GstAV1SequenceHeaderOBU, priv->seq_header);
+    priv->seq_header = NULL;
+  }
+
+  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++)
+    gst_vaapi_picture_replace (&priv->ref_frames[i], NULL);
+}
+
+static gboolean
+av1_is_picture_end (GstVaapiParserInfoAV1 * pi)
+{
+  GstAV1TileGroupOBU *tile_group = NULL;
+
+  if (pi->obu.obu_type == GST_AV1_OBU_FRAME) {
+    tile_group = &pi->frame.tile_group;
+  } else if (pi->obu.obu_type == GST_AV1_OBU_TILE_GROUP) {
+    tile_group = &pi->tile_group;
+  }
+  g_assert (tile_group);
+
+  if (tile_group->tg_end == tile_group->num_tiles - 1)
+    return TRUE;
+
+  return FALSE;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_av1_reset (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
+  GstVaapiDecoderAV1Private *priv = &decoder->priv;
+
+  av1_decoder_reset (decoder);
+  gst_av1_parser_reset (priv->parser, FALSE);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_av1_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
+  GstVaapiDecoderAV1Private *const priv = &decoder->priv;
+  GstVaapiParserInfoAV1 *pi;
+  GstAV1Parser *parser = priv->parser;
+  guchar *buf;
+  guint buf_size, flags;
+  GstAV1OBU obu;
+  GstAV1ParserResult av1_ret;
+  GstVaapiDecoderStatus ret = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  guint32 consumed;
+
+  buf_size = gst_adapter_available (adapter);
+  if (!buf_size)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  /* no need to do unmap here */
+  buf = (guchar *) gst_adapter_map (adapter, buf_size);
+  if (!buf)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  av1_ret =
+      gst_av1_parser_identify_one_obu (parser, buf, buf_size, &obu, &consumed);
+  if (av1_ret == GST_AV1_PARSER_DROP) {
+    GST_LOG ("just discard a %s obu with size %d, consumed %d",
+        av1_obu_name (obu.obu_type), obu.obu_size, consumed);
+    gst_adapter_flush (adapter, consumed);
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  } else if (av1_ret == GST_AV1_PARSER_NO_MORE_DATA) {
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+  } else if (av1_ret == GST_AV1_PARSER_BITSTREAM_ERROR) {
+    GST_WARNING_OBJECT (decoder, "parse error, an invalid bitstream");
+    gst_adapter_flush (adapter, consumed);
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  } else if (av1_ret != GST_AV1_PARSER_OK) {
+    GST_WARNING_OBJECT (decoder, "parse error, unknown error");
+    gst_adapter_flush (adapter, consumed);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  GST_DEBUG ("get one %s obu with size %d, consumed %d",
+      av1_obu_name (obu.obu_type), obu.obu_size, consumed);
+
+  pi = parser_info_av1_new (&obu);
+  if (!pi) {
+    gst_adapter_flush (adapter, consumed);
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, pi,
+      (GDestroyNotify) gst_vaapi_mini_object_unref);
+
+  flags = 0;
+  av1_ret = GST_AV1_PARSER_OK;
+  switch (pi->obu.obu_type) {
+    case GST_AV1_OBU_TEMPORAL_DELIMITER:
+      av1_ret = gst_av1_parser_parse_temporal_delimiter_obu (parser, &pi->obu);
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      break;
+    case GST_AV1_OBU_SEQUENCE_HEADER:
+      av1_ret = gst_av1_parser_parse_sequence_header_obu (parser, &pi->obu,
+          &pi->seq_header);
+      break;
+    case GST_AV1_OBU_REDUNDANT_FRAME_HEADER:
+      av1_ret = gst_av1_parser_parse_frame_header_obu (parser, &pi->obu,
+          &pi->frame_header);
+      break;
+    case GST_AV1_OBU_FRAME_HEADER:
+      av1_ret = gst_av1_parser_parse_frame_header_obu (parser, &pi->obu,
+          &pi->frame_header);
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      if (pi->frame_header.show_existing_frame) {
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      }
+      break;
+    case GST_AV1_OBU_FRAME:
+      av1_ret = gst_av1_parser_parse_frame_obu (parser, &obu, &pi->frame);
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      pi->data_offset = obu.data - buf;
+      if (av1_is_picture_end (pi))
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      break;
+    case GST_AV1_OBU_METADATA:
+      av1_ret = gst_av1_parser_parse_metadata_obu (parser, &obu, &pi->metadata);
+      break;
+    case GST_AV1_OBU_TILE_GROUP:
+      av1_ret = gst_av1_parser_parse_tile_group_obu (parser, &obu,
+          &pi->tile_group);
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      pi->data_offset = obu.data - buf;
+      if (av1_is_picture_end (pi))
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      break;
+    case GST_AV1_OBU_TILE_LIST:
+      av1_ret =
+          gst_av1_parser_parse_tile_list_obu (parser, &obu, &pi->tile_list);
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      break;
+    case GST_AV1_OBU_PADDING:
+      break;
+    default:
+      GST_WARNING_OBJECT (decoder, "an unrecognized obu type %d", obu.obu_type);
+      av1_ret = GST_AV1_PARSER_BITSTREAM_ERROR;
+      break;
+  }
+
+  if (av1_ret != GST_AV1_PARSER_OK) {
+    /* Should not get NO_MORE_DATA, the obu size is already known */
+    GST_WARNING_OBJECT (decoder, "parse %s obu error",
+        av1_obu_name (pi->obu.obu_type));
+    gst_adapter_flush (adapter, consumed);
+    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (pi));
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  unit->size = consumed;
+  unit->offset = pi->obu.data - buf;
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+
+  return ret;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_av1_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
+  GstVaapiDecoderStatus status;
+
+  status = av1_decode_unit (decoder, unit);
+
+  return status;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_av1_start_frame (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * base_unit)
+{
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_av1_end_frame (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
+  GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  GstVaapiDecoderAV1Private *priv = &decoder->priv;
+
+  if (!priv->current_picture->cloned)
+    status = av1_decode_current_picture (decoder);
+
+  /* update state anyway */
+  av1_decoder_update_state (decoder, priv->current_picture);
+
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    goto out;
+
+  if (!gst_vaapi_picture_output (GST_VAAPI_PICTURE (priv->current_picture)))
+    status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+out:
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  return status;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_av1_flush (GstVaapiDecoder * base_decoder)
+{
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+gst_vaapi_decoder_av1_finalize (GObject * object)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
+  GstVaapiDecoderAV1 *const decoder = GST_VAAPI_DECODER_AV1 (base_decoder);
+  GstVaapiDecoderAV1Private *priv = &decoder->priv;
+
+  av1_decoder_reset (decoder);
+  if (decoder->priv.parser)
+    gst_av1_parser_free (decoder->priv.parser);
+  priv->parser = NULL;
+
+  G_OBJECT_CLASS (gst_vaapi_decoder_av1_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_av1_class_init (GstVaapiDecoderAV1Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_decoder_av1_finalize;
+
+  decoder_class->reset = gst_vaapi_decoder_av1_reset;
+  decoder_class->parse = gst_vaapi_decoder_av1_parse;
+  decoder_class->decode = gst_vaapi_decoder_av1_decode;
+  decoder_class->start_frame = gst_vaapi_decoder_av1_start_frame;
+  decoder_class->end_frame = gst_vaapi_decoder_av1_end_frame;
+  decoder_class->flush = gst_vaapi_decoder_av1_flush;
+}
+
+static void
+gst_vaapi_decoder_av1_init (GstVaapiDecoderAV1 * decoder)
+{
+  guint i;
+  GstVaapiDecoderAV1Private *priv = &decoder->priv;
+
+  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  priv->width = 0;
+  priv->height = 0;
+  priv->annex_b = FALSE;
+  priv->reset_context = FALSE;
+  priv->current_picture = NULL;
+  priv->seq_header = NULL;
+
+  for (i = 0; i < GST_AV1_NUM_REF_FRAMES; i++)
+    priv->ref_frames[i] = NULL;
+
+  priv->parser = gst_av1_parser_new ();
+}
+
+/**
+ * gst_vaapi_decoder_av1_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for AV1 decoding. The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_av1_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return g_object_new (GST_TYPE_VAAPI_DECODER_AV1, "display", display,
+      "caps", caps, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_av1.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_av1.h
new file mode 100644 (file)
index 0000000..8604093
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  gstvaapidecoder_av1.h - AV1 decoder
+ *
+ *  Copyright (C) 2019-2020 Intel Corporation
+ *    Author: Junyan He <junyan.he@hotmail.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_AV1_H
+#define GST_VAAPI_DECODER_AV1_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER_AV1 \
+    (gst_vaapi_decoder_av1_get_type ())
+#define GST_VAAPI_DECODER_AV1(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_AV1, GstVaapiDecoderAV1))
+#define GST_VAAPI_IS_DECODER_AV1(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_AV1))
+
+typedef struct _GstVaapiDecoderAV1              GstVaapiDecoderAV1;
+
+GType
+gst_vaapi_decoder_av1_get_type (void) G_GNUC_CONST;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_av1_new (GstVaapiDisplay * display, GstCaps * caps);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_AV1_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_dpb.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_dpb.c
new file mode 100644 (file)
index 0000000..7825c9d
--- /dev/null
@@ -0,0 +1,421 @@
+/*
+ *  gstvaapidecoder_dpb.c - Decoded Picture Buffer
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapidecoder_dpb.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_DPB_CLASS(klass) \
+    ((GstVaapiDpbClass *)(klass))
+
+#define GST_VAAPI_DPB_GET_CLASS(obj) \
+    GST_VAAPI_DPB_CLASS(GST_VAAPI_MINI_OBJECT_GET_CLASS(obj))
+
+/**
+ * GstVaapiDpb:
+ *
+ * A decoded picture buffer (DPB) object.
+ */
+struct _GstVaapiDpb
+{
+  /*< private > */
+  GstVaapiMiniObject parent_instance;
+
+  /*< protected > */
+  GstVaapiPicture **pictures;
+  guint num_pictures;
+  guint max_pictures;
+};
+
+/**
+ * GstVaapiDpbClass:
+ *
+ * The #GstVaapiDpb base class.
+ */
+struct _GstVaapiDpbClass
+{
+  /*< private > */
+  GstVaapiMiniObjectClass parent_class;
+
+  /*< protected > */
+  void (*flush) (GstVaapiDpb * dpb);
+    gboolean (*add) (GstVaapiDpb * dpb, GstVaapiPicture * picture);
+  void (*get_neighbours) (GstVaapiDpb * dpb, GstVaapiPicture * picture,
+      GstVaapiPicture ** prev_picture_ptr, GstVaapiPicture ** next_picture_ptr);
+};
+
+static const GstVaapiMiniObjectClass *gst_vaapi_dpb_class (void);
+
+static const GstVaapiMiniObjectClass *gst_vaapi_dpb2_class (void);
+
+/* ------------------------------------------------------------------------- */
+/* --- Common utilities                                                  --- */
+/* ------------------------------------------------------------------------- */
+
+static inline GstVaapiDpb *
+dpb_new (guint max_pictures)
+{
+  GstVaapiDpb *dpb;
+
+  g_return_val_if_fail (max_pictures > 0, NULL);
+
+  dpb =
+      (GstVaapiDpb *) gst_vaapi_mini_object_new (max_pictures ==
+      2 ? gst_vaapi_dpb2_class () : gst_vaapi_dpb_class ());
+  if (!dpb)
+    return NULL;
+
+  dpb->num_pictures = 0;
+  dpb->max_pictures = max_pictures;
+
+  dpb->pictures = g_new0 (GstVaapiPicture *, max_pictures);
+  if (!dpb->pictures)
+    goto error;
+  return dpb;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_dpb_unref (dpb);
+    return NULL;
+  }
+}
+
+static gint
+dpb_get_oldest (GstVaapiDpb * dpb, gboolean output)
+{
+  gint i, lowest_pts_index;
+
+  for (i = 0; i < dpb->num_pictures; i++) {
+    if ((GST_VAAPI_PICTURE_IS_OUTPUT (dpb->pictures[i]) ^ output) == 0)
+      break;
+  }
+  if (i == dpb->num_pictures)
+    return -1;
+
+  lowest_pts_index = i++;
+  for (; i < dpb->num_pictures; i++) {
+    GstVaapiPicture *const picture = dpb->pictures[i];
+    if ((GST_VAAPI_PICTURE_IS_OUTPUT (picture) ^ output) != 0)
+      continue;
+    if (picture->poc < dpb->pictures[lowest_pts_index]->poc)
+      lowest_pts_index = i;
+  }
+  return lowest_pts_index;
+}
+
+static void
+dpb_remove_index (GstVaapiDpb * dpb, guint index)
+{
+  GstVaapiPicture **const pictures = dpb->pictures;
+  guint num_pictures = --dpb->num_pictures;
+
+  if (index != num_pictures)
+    gst_vaapi_picture_replace (&pictures[index], pictures[num_pictures]);
+  gst_vaapi_picture_replace (&pictures[num_pictures], NULL);
+}
+
+static inline gboolean
+dpb_output (GstVaapiDpb * dpb, GstVaapiPicture * picture)
+{
+  return gst_vaapi_picture_output (picture);
+}
+
+static gboolean
+dpb_bump (GstVaapiDpb * dpb)
+{
+  gint index;
+  gboolean success;
+
+  index = dpb_get_oldest (dpb, FALSE);
+  if (index < 0)
+    return FALSE;
+
+  success = dpb_output (dpb, dpb->pictures[index]);
+  if (!GST_VAAPI_PICTURE_IS_REFERENCE (dpb->pictures[index]))
+    dpb_remove_index (dpb, index);
+  return success;
+}
+
+static void
+dpb_clear (GstVaapiDpb * dpb)
+{
+  guint i;
+
+  for (i = 0; i < dpb->num_pictures; i++)
+    gst_vaapi_picture_replace (&dpb->pictures[i], NULL);
+  dpb->num_pictures = 0;
+}
+
+static void
+dpb_flush (GstVaapiDpb * dpb)
+{
+  while (dpb_bump (dpb));
+  dpb_clear (dpb);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Generic implementation                                            --- */
+/* ------------------------------------------------------------------------- */
+
+static gboolean
+dpb_add (GstVaapiDpb * dpb, GstVaapiPicture * picture)
+{
+  guint i;
+
+  // Remove all unused pictures
+  i = 0;
+  while (i < dpb->num_pictures) {
+    GstVaapiPicture *const picture = dpb->pictures[i];
+    if (GST_VAAPI_PICTURE_IS_OUTPUT (picture) &&
+        !GST_VAAPI_PICTURE_IS_REFERENCE (picture))
+      dpb_remove_index (dpb, i);
+    else
+      i++;
+  }
+
+  // Store reference decoded picture into the DPB
+  if (GST_VAAPI_PICTURE_IS_REFERENCE (picture)) {
+    while (dpb->num_pictures == dpb->max_pictures) {
+      if (!dpb_bump (dpb))
+        return FALSE;
+    }
+  }
+  // Store non-reference decoded picture into the DPB
+  else {
+    if (GST_VAAPI_PICTURE_IS_SKIPPED (picture))
+      return TRUE;
+    while (dpb->num_pictures == dpb->max_pictures) {
+      for (i = 0; i < dpb->num_pictures; i++) {
+        if (!GST_VAAPI_PICTURE_IS_OUTPUT (picture) &&
+            dpb->pictures[i]->poc < picture->poc)
+          break;
+      }
+      if (i == dpb->num_pictures)
+        return dpb_output (dpb, picture);
+      if (!dpb_bump (dpb))
+        return FALSE;
+    }
+  }
+  gst_vaapi_picture_replace (&dpb->pictures[dpb->num_pictures++], picture);
+  return TRUE;
+}
+
+static void
+dpb_get_neighbours (GstVaapiDpb * dpb, GstVaapiPicture * picture,
+    GstVaapiPicture ** prev_picture_ptr, GstVaapiPicture ** next_picture_ptr)
+{
+  GstVaapiPicture *prev_picture = NULL;
+  GstVaapiPicture *next_picture = NULL;
+  guint i;
+
+  /* Find the first picture with POC > specified picture POC */
+  for (i = 0; i < dpb->num_pictures; i++) {
+    GstVaapiPicture *const ref_picture = dpb->pictures[i];
+    if (ref_picture->poc == picture->poc) {
+      if (i > 0)
+        prev_picture = dpb->pictures[i - 1];
+      if (i + 1 < dpb->num_pictures)
+        next_picture = dpb->pictures[i + 1];
+      break;
+    } else if (ref_picture->poc > picture->poc) {
+      next_picture = ref_picture;
+      if (i > 0)
+        prev_picture = dpb->pictures[i - 1];
+      break;
+    }
+  }
+
+  g_assert (next_picture ? next_picture->poc > picture->poc : TRUE);
+  g_assert (prev_picture ? prev_picture->poc < picture->poc : TRUE);
+
+  if (prev_picture_ptr)
+    *prev_picture_ptr = prev_picture;
+  if (next_picture_ptr)
+    *next_picture_ptr = next_picture;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Optimized implementation for 2 reference pictures                 --- */
+/* ------------------------------------------------------------------------- */
+
+static gboolean
+dpb2_add (GstVaapiDpb * dpb, GstVaapiPicture * picture)
+{
+  GstVaapiPicture *ref_picture;
+  gint index = -1;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DPB (dpb), FALSE);
+  g_return_val_if_fail (dpb->max_pictures == 2, FALSE);
+
+  /*
+   * Purpose: only store reference decoded pictures into the DPB
+   *
+   * This means:
+   * - non-reference decoded pictures are output immediately
+   * - ... thus causing older reference pictures to be output, if not already
+   * - the oldest reference picture is replaced with the new reference picture
+   */
+  if (G_LIKELY (dpb->num_pictures == 2)) {
+    index = (dpb->pictures[0]->poc > dpb->pictures[1]->poc);
+    ref_picture = dpb->pictures[index];
+    if (!GST_VAAPI_PICTURE_IS_OUTPUT (ref_picture)) {
+      if (!dpb_output (dpb, ref_picture))
+        return FALSE;
+    }
+  }
+
+  if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture))
+    return dpb_output (dpb, picture);
+
+  if (index < 0)
+    index = dpb->num_pictures++;
+  gst_vaapi_picture_replace (&dpb->pictures[index], picture);
+  return TRUE;
+}
+
+static void
+dpb2_get_neighbours (GstVaapiDpb * dpb, GstVaapiPicture * picture,
+    GstVaapiPicture ** prev_picture_ptr, GstVaapiPicture ** next_picture_ptr)
+{
+  GstVaapiPicture *ref_picture, *ref_pictures[2];
+  GstVaapiPicture **picture_ptr;
+  guint i, index;
+
+  g_return_if_fail (GST_VAAPI_IS_DPB (dpb));
+  g_return_if_fail (dpb->max_pictures == 2);
+  g_return_if_fail (GST_VAAPI_IS_PICTURE (picture));
+
+  ref_pictures[0] = NULL;
+  ref_pictures[1] = NULL;
+  for (i = 0; i < dpb->num_pictures; i++) {
+    ref_picture = dpb->pictures[i];
+    index = ref_picture->poc > picture->poc;
+    picture_ptr = &ref_pictures[index];
+    if (!*picture_ptr || ((*picture_ptr)->poc > ref_picture->poc) == index)
+      *picture_ptr = ref_picture;
+  }
+
+  if (prev_picture_ptr)
+    *prev_picture_ptr = ref_pictures[0];
+  if (next_picture_ptr)
+    *next_picture_ptr = ref_pictures[1];
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Interface                                                         --- */
+/* ------------------------------------------------------------------------- */
+
+static void
+gst_vaapi_dpb_finalize (GstVaapiDpb * dpb)
+{
+  dpb_clear (dpb);
+  g_free (dpb->pictures);
+}
+
+static const GstVaapiMiniObjectClass *
+gst_vaapi_dpb_class (void)
+{
+  static const GstVaapiDpbClass GstVaapiDpbClass = {
+    {sizeof (GstVaapiDpb),
+        (GDestroyNotify) gst_vaapi_dpb_finalize}
+    ,
+
+    dpb_flush,
+    dpb_add,
+    dpb_get_neighbours
+  };
+  return &GstVaapiDpbClass.parent_class;
+}
+
+static const GstVaapiMiniObjectClass *
+gst_vaapi_dpb2_class (void)
+{
+  static const GstVaapiDpbClass GstVaapiDpb2Class = {
+    {sizeof (GstVaapiDpb),
+        (GDestroyNotify) gst_vaapi_dpb_finalize}
+    ,
+
+    dpb_flush,
+    dpb2_add,
+    dpb2_get_neighbours
+  };
+  return &GstVaapiDpb2Class.parent_class;
+}
+
+GstVaapiDpb *
+gst_vaapi_dpb_new (guint max_pictures)
+{
+  return dpb_new (max_pictures);
+}
+
+void
+gst_vaapi_dpb_flush (GstVaapiDpb * dpb)
+{
+  const GstVaapiDpbClass *klass;
+
+  g_return_if_fail (GST_VAAPI_IS_DPB (dpb));
+
+  klass = GST_VAAPI_DPB_GET_CLASS (dpb);
+  if (G_UNLIKELY (!klass || !klass->add))
+    return;
+  klass->flush (dpb);
+}
+
+gboolean
+gst_vaapi_dpb_add (GstVaapiDpb * dpb, GstVaapiPicture * picture)
+{
+  const GstVaapiDpbClass *klass;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DPB (dpb), FALSE);
+  g_return_val_if_fail (GST_VAAPI_IS_PICTURE (picture), FALSE);
+
+  klass = GST_VAAPI_DPB_GET_CLASS (dpb);
+  if (G_UNLIKELY (!klass || !klass->add))
+    return FALSE;
+  return klass->add (dpb, picture);
+}
+
+guint
+gst_vaapi_dpb_size (GstVaapiDpb * dpb)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DPB (dpb), 0);
+
+  return dpb->num_pictures;
+}
+
+void
+gst_vaapi_dpb_get_neighbours (GstVaapiDpb * dpb, GstVaapiPicture * picture,
+    GstVaapiPicture ** prev_picture_ptr, GstVaapiPicture ** next_picture_ptr)
+{
+  const GstVaapiDpbClass *klass;
+
+  g_return_if_fail (GST_VAAPI_IS_DPB (dpb));
+  g_return_if_fail (GST_VAAPI_IS_PICTURE (picture));
+
+  klass = GST_VAAPI_DPB_GET_CLASS (dpb);
+  if (G_UNLIKELY (!klass || !klass->get_neighbours))
+    return;
+  klass->get_neighbours (dpb, picture, prev_picture_ptr, next_picture_ptr);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_dpb.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_dpb.h
new file mode 100644 (file)
index 0000000..fa52d41
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  gstvaapidecoder_dpb.h - Decoded Picture Buffer
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_DPB_H
+#define GST_VAAPI_DECODER_DPB_H
+
+#include <gst/vaapi/gstvaapidecoder_objects.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiDpb             GstVaapiDpb;
+typedef struct _GstVaapiDpbClass        GstVaapiDpbClass;
+
+/* ------------------------------------------------------------------------- */
+/* --- Decoded Picture Buffer                                            --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_DPB(obj) \
+    ((GstVaapiDpb *)(obj))
+
+#define GST_VAAPI_IS_DPB(obj) \
+    (GST_VAAPI_DPB(obj) != NULL)
+
+G_GNUC_INTERNAL
+GstVaapiDpb *
+gst_vaapi_dpb_new(guint max_pictures);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_dpb_flush(GstVaapiDpb *dpb);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_dpb_add(GstVaapiDpb *dpb, GstVaapiPicture *picture);
+
+G_GNUC_INTERNAL
+guint
+gst_vaapi_dpb_size(GstVaapiDpb *dpb);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_dpb_get_neighbours(
+    GstVaapiDpb        *dpb,
+    GstVaapiPicture    *picture,
+    GstVaapiPicture   **prev_picture_ptr,
+    GstVaapiPicture   **next_picture_ptr
+);
+
+#define gst_vaapi_dpb_ref(dpb) \
+    gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(dpb))
+
+#define gst_vaapi_dpb_unref(dpb) \
+    gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(dpb))
+
+#define gst_vaapi_dpb_replace(old_dpb_ptr, new_dpb) \
+    gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_dpb_ptr), \
+        (GstVaapiMiniObject *)(new_dpb))
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_DPB */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h264.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h264.c
new file mode 100644 (file)
index 0000000..e19c184
--- /dev/null
@@ -0,0 +1,5018 @@
+/*
+ *  gstvaapidecoder_h264.c - H.264 decoder
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_h264
+ * @short_description: H.264 decoder
+ */
+
+#include "sysdeps.h"
+#include <gst/base/gstadapter.h>
+#include <gst/codecparsers/gsth264parser.h>
+#include "gstvaapidecoder_h264.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapiutils_h264_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/* Defined to 1 if strict ordering of DPB is needed. Only useful for debug */
+#define USE_STRICT_DPB_ORDERING 0
+
+typedef struct _GstVaapiDecoderH264Private GstVaapiDecoderH264Private;
+typedef struct _GstVaapiDecoderH264Class GstVaapiDecoderH264Class;
+typedef struct _GstVaapiFrameStore GstVaapiFrameStore;
+typedef struct _GstVaapiFrameStoreClass GstVaapiFrameStoreClass;
+typedef struct _GstVaapiParserInfoH264 GstVaapiParserInfoH264;
+typedef struct _GstVaapiPictureH264 GstVaapiPictureH264;
+typedef struct _GstVaapiStereo3DInfo GstVaapiStereo3DInfo;
+
+// Used for field_poc[]
+#define TOP_FIELD       0
+#define BOTTOM_FIELD    1
+
+/* ------------------------------------------------------------------------- */
+/* --- H.264 Parser Info                                                 --- */
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Extended decoder unit flags:
+ *
+ * @GST_VAAPI_DECODER_UNIT_AU_START: marks the start of an access unit.
+ * @GST_VAAPI_DECODER_UNIT_AU_END: marks the end of an access unit.
+ */
+enum
+{
+  /* This flag does not strictly follow the definitions (7.4.1.2.3)
+     for detecting the start of an access unit as we are only
+     interested in knowing if the current slice is the first one or
+     the last one in the current access unit */
+  GST_VAAPI_DECODER_UNIT_FLAG_AU_START =
+      (GST_VAAPI_DECODER_UNIT_FLAG_LAST << 0),
+  GST_VAAPI_DECODER_UNIT_FLAG_AU_END = (GST_VAAPI_DECODER_UNIT_FLAG_LAST << 1),
+
+  GST_VAAPI_DECODER_UNIT_FLAGS_AU = (GST_VAAPI_DECODER_UNIT_FLAG_AU_START |
+      GST_VAAPI_DECODER_UNIT_FLAG_AU_END),
+};
+
+#define GST_VAAPI_PARSER_INFO_H264(obj) \
+    ((GstVaapiParserInfoH264 *)(obj))
+
+struct _GstVaapiParserInfoH264
+{
+  GstVaapiMiniObject parent_instance;
+  GstH264NalUnit nalu;
+  union
+  {
+    GstH264SPS sps;
+    GstH264PPS pps;
+    GArray *sei;
+    GstH264SliceHdr slice_hdr;
+  } data;
+  guint state;
+  guint flags;                  // Same as decoder unit flags (persistent)
+  guint view_id;                // View ID of slice
+  guint voc;                    // View order index (VOIdx) of slice
+};
+
+static void
+gst_vaapi_parser_info_h264_finalize (GstVaapiParserInfoH264 * pi)
+{
+  if (!pi->nalu.valid)
+    return;
+
+  switch (pi->nalu.type) {
+    case GST_H264_NAL_SPS:
+    case GST_H264_NAL_SUBSET_SPS:
+      gst_h264_sps_clear (&pi->data.sps);
+      break;
+    case GST_H264_NAL_PPS:
+      gst_h264_pps_clear (&pi->data.pps);
+      break;
+    case GST_H264_NAL_SEI:
+      if (pi->data.sei) {
+        g_array_unref (pi->data.sei);
+        pi->data.sei = NULL;
+      }
+      break;
+  }
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_parser_info_h264_class (void)
+{
+  static const GstVaapiMiniObjectClass GstVaapiParserInfoH264Class = {
+    .size = sizeof (GstVaapiParserInfoH264),
+    .finalize = (GDestroyNotify) gst_vaapi_parser_info_h264_finalize
+  };
+  return &GstVaapiParserInfoH264Class;
+}
+
+static inline GstVaapiParserInfoH264 *
+gst_vaapi_parser_info_h264_new (void)
+{
+  return (GstVaapiParserInfoH264 *)
+      gst_vaapi_mini_object_new (gst_vaapi_parser_info_h264_class ());
+}
+
+#define gst_vaapi_parser_info_h264_ref(pi) \
+    gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(pi))
+
+#define gst_vaapi_parser_info_h264_unref(pi) \
+    gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(pi))
+
+#define gst_vaapi_parser_info_h264_replace(old_pi_ptr, new_pi)          \
+    gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_pi_ptr),  \
+        (GstVaapiMiniObject *)(new_pi))
+
+/* ------------------------------------------------------------------------- */
+/* --- H.264 Pictures                                                    --- */
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Extended picture flags:
+ *
+ * @GST_VAAPI_PICTURE_FLAG_IDR: flag that specifies an IDR picture
+ * @GST_VAAPI_PICTURE_FLAG_INTER_VIEW: flag that indicates the picture
+ *   may be used for inter-view prediction
+ * @GST_VAAPI_PICTURE_FLAG_ANCHOR: flag that specifies an anchor picture,
+ *   i.e. a picture that is decoded with only inter-view prediction,
+ *   and not inter prediction
+ * @GST_VAAPI_PICTURE_FLAG_AU_START: flag that marks the start of an
+ *   access unit (AU)
+ * @GST_VAAPI_PICTURE_FLAG_AU_END: flag that marks the end of an
+ *   access unit (AU)
+ * @GST_VAAPI_PICTURE_FLAG_GHOST: flag that specifies a "non-existing"
+ *   picture, without any viable GstVideoCodecFrame associated to it.
+ *   i.e. a dummy picture with some valid contents
+ * @GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE: flag that specifies
+ *     "used for short-term reference"
+ * @GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE: flag that specifies
+ *     "used for long-term reference"
+ * @GST_VAAPI_PICTURE_FLAGS_REFERENCE: mask covering any kind of
+ *     reference picture (short-term reference or long-term reference)
+ */
+enum
+{
+  GST_VAAPI_PICTURE_FLAG_IDR = (GST_VAAPI_PICTURE_FLAG_LAST << 0),
+  GST_VAAPI_PICTURE_FLAG_REFERENCE2 = (GST_VAAPI_PICTURE_FLAG_LAST << 1),
+  GST_VAAPI_PICTURE_FLAG_INTER_VIEW = (GST_VAAPI_PICTURE_FLAG_LAST << 2),
+  GST_VAAPI_PICTURE_FLAG_ANCHOR = (GST_VAAPI_PICTURE_FLAG_LAST << 3),
+  GST_VAAPI_PICTURE_FLAG_AU_START = (GST_VAAPI_PICTURE_FLAG_LAST << 4),
+  GST_VAAPI_PICTURE_FLAG_AU_END = (GST_VAAPI_PICTURE_FLAG_LAST << 5),
+  GST_VAAPI_PICTURE_FLAG_GHOST = (GST_VAAPI_PICTURE_FLAG_LAST << 6),
+
+  GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE =
+      (GST_VAAPI_PICTURE_FLAG_REFERENCE),
+  GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE =
+      (GST_VAAPI_PICTURE_FLAG_REFERENCE | GST_VAAPI_PICTURE_FLAG_REFERENCE2),
+  GST_VAAPI_PICTURE_FLAGS_REFERENCE =
+      (GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE |
+      GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE),
+};
+
+#define GST_VAAPI_PICTURE_IS_IDR(picture) \
+    (GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_IDR))
+
+#define GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE(picture)      \
+    ((GST_VAAPI_PICTURE_FLAGS(picture) &                        \
+      GST_VAAPI_PICTURE_FLAGS_REFERENCE) ==                     \
+     GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE)
+
+#define GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE(picture)       \
+    ((GST_VAAPI_PICTURE_FLAGS(picture) &                        \
+      GST_VAAPI_PICTURE_FLAGS_REFERENCE) ==                     \
+     GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE)
+
+#define GST_VAAPI_PICTURE_IS_INTER_VIEW(picture) \
+    (GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_INTER_VIEW))
+
+#define GST_VAAPI_PICTURE_IS_ANCHOR(picture) \
+    (GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_ANCHOR))
+
+#define GST_VAAPI_PICTURE_H264(picture) \
+    ((GstVaapiPictureH264 *)(picture))
+
+struct _GstVaapiPictureH264
+{
+  GstVaapiPicture base;
+  GstH264SliceHdr *last_slice_hdr;
+  guint structure;
+  gint32 field_poc[2];
+  gint32 frame_num;             // Original frame_num from slice_header()
+  gint32 frame_num_wrap;        // Temporary for ref pic marking: FrameNumWrap
+  gint32 long_term_frame_idx;   // Temporary for ref pic marking: LongTermFrameIdx
+  gint32 pic_num;               // Temporary for ref pic marking: PicNum
+  gint32 long_term_pic_num;     // Temporary for ref pic marking: LongTermPicNum
+  GstVaapiPictureH264 *other_field;     // Temporary for ref pic marking: other field in the same frame store
+  guint output_flag:1;
+  guint output_needed:1;
+};
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiPictureH264, gst_vaapi_picture_h264);
+
+void
+gst_vaapi_picture_h264_destroy (GstVaapiPictureH264 * picture)
+{
+  gst_vaapi_picture_destroy (GST_VAAPI_PICTURE (picture));
+}
+
+gboolean
+gst_vaapi_picture_h264_create (GstVaapiPictureH264 * picture,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  if (!gst_vaapi_picture_create (GST_VAAPI_PICTURE (picture), args))
+    return FALSE;
+
+  picture->structure = picture->base.structure;
+  picture->field_poc[0] = G_MAXINT32;
+  picture->field_poc[1] = G_MAXINT32;
+  picture->output_needed = FALSE;
+  return TRUE;
+}
+
+static inline GstVaapiPictureH264 *
+gst_vaapi_picture_h264_new (GstVaapiDecoderH264 * decoder)
+{
+  return (GstVaapiPictureH264 *)
+      gst_vaapi_codec_object_new (&GstVaapiPictureH264Class,
+      GST_VAAPI_CODEC_BASE (decoder), NULL,
+      sizeof (VAPictureParameterBufferH264), NULL, 0, 0);
+}
+
+static inline void
+gst_vaapi_picture_h264_set_reference (GstVaapiPictureH264 * picture,
+    guint reference_flags, gboolean other_field)
+{
+  if (!picture)
+    return;
+  GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAGS_REFERENCE);
+  GST_VAAPI_PICTURE_FLAG_SET (picture, reference_flags);
+
+  if (!other_field || !(picture = picture->other_field))
+    return;
+  GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAGS_REFERENCE);
+  GST_VAAPI_PICTURE_FLAG_SET (picture, reference_flags);
+}
+
+static inline GstVaapiPictureH264 *
+gst_vaapi_picture_h264_new_field (GstVaapiPictureH264 * picture)
+{
+  g_return_val_if_fail (picture, NULL);
+
+  return (GstVaapiPictureH264 *) gst_vaapi_picture_new_field (&picture->base);
+}
+
+static inline GstVaapiPictureH264 *
+gst_vaapi_picture_h264_new_clone (GstVaapiPictureH264 * picture)
+{
+  g_return_val_if_fail (picture, NULL);
+
+  return (GstVaapiPictureH264 *) gst_vaapi_picture_new_clone (&picture->base);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Frame Buffers (DPB)                                               --- */
+/* ------------------------------------------------------------------------- */
+
+struct _GstVaapiFrameStore
+{
+  /*< private > */
+  GstVaapiMiniObject parent_instance;
+
+  guint view_id;
+  guint structure;
+  GstVaapiPictureH264 *buffers[2];
+  guint num_buffers;
+  guint output_needed;
+  guint output_called;
+};
+
+static void
+gst_vaapi_frame_store_finalize (gpointer object)
+{
+  GstVaapiFrameStore *const fs = object;
+  guint i;
+
+  for (i = 0; i < fs->num_buffers; i++)
+    gst_vaapi_picture_replace (&fs->buffers[i], NULL);
+}
+
+static GstVaapiFrameStore *
+gst_vaapi_frame_store_new (GstVaapiPictureH264 * picture)
+{
+  GstVaapiFrameStore *fs;
+
+  static const GstVaapiMiniObjectClass GstVaapiFrameStoreClass = {
+    sizeof (GstVaapiFrameStore),
+    gst_vaapi_frame_store_finalize
+  };
+
+  fs = (GstVaapiFrameStore *)
+      gst_vaapi_mini_object_new (&GstVaapiFrameStoreClass);
+  if (!fs)
+    return NULL;
+
+  fs->view_id = picture->base.view_id;
+  fs->structure = picture->structure;
+  fs->buffers[0] = gst_vaapi_picture_ref (picture);
+  fs->buffers[1] = NULL;
+  fs->num_buffers = 1;
+  fs->output_needed = 0;
+  fs->output_called = 0;
+
+  if (picture->output_flag) {
+    picture->output_needed = TRUE;
+    fs->output_needed++;
+  }
+  return fs;
+}
+
+static gboolean
+gst_vaapi_frame_store_add (GstVaapiFrameStore * fs,
+    GstVaapiPictureH264 * picture)
+{
+  guint field;
+
+  g_return_val_if_fail (fs->num_buffers == 1, FALSE);
+  g_return_val_if_fail (!GST_VAAPI_PICTURE_IS_FRAME (picture), FALSE);
+  g_return_val_if_fail (!GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture), FALSE);
+
+  gst_vaapi_picture_replace (&fs->buffers[fs->num_buffers++], picture);
+  if (picture->output_flag) {
+    picture->output_needed = TRUE;
+    fs->output_needed++;
+  }
+
+  fs->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+
+  field = picture->structure == GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD ?
+      TOP_FIELD : BOTTOM_FIELD;
+
+  if (fs->buffers[0]->field_poc[field] != G_MAXINT32)
+    return FALSE;
+  fs->buffers[0]->field_poc[field] = picture->field_poc[field];
+
+  if (picture->field_poc[!field] != G_MAXINT32)
+    return FALSE;
+  picture->field_poc[!field] = fs->buffers[0]->field_poc[!field];
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_frame_store_split_fields (GstVaapiFrameStore * fs, gboolean tff)
+{
+  GstVaapiPictureH264 *const first_field = fs->buffers[0];
+  GstVaapiPictureH264 *second_field;
+
+  g_return_val_if_fail (fs->num_buffers == 1, FALSE);
+
+  first_field->base.structure = tff ?
+      GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD :
+      GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
+  GST_VAAPI_PICTURE_FLAG_SET (first_field, GST_VAAPI_PICTURE_FLAG_INTERLACED);
+
+  second_field = gst_vaapi_picture_h264_new_field (first_field);
+  if (!second_field)
+    return FALSE;
+  gst_vaapi_picture_h264_set_reference (second_field,
+      GST_VAAPI_PICTURE_FLAGS (first_field) & GST_VAAPI_PICTURE_FLAGS_REFERENCE,
+      FALSE);
+  gst_vaapi_picture_replace (&fs->buffers[fs->num_buffers++], second_field);
+  gst_vaapi_picture_unref (second_field);
+
+  second_field->frame_num = first_field->frame_num;
+  second_field->field_poc[0] = first_field->field_poc[0];
+  second_field->field_poc[1] = first_field->field_poc[1];
+  second_field->output_flag = first_field->output_flag;
+  if (second_field->output_flag) {
+    second_field->output_needed = TRUE;
+    fs->output_needed++;
+  }
+  return TRUE;
+}
+
+static inline gboolean
+gst_vaapi_frame_store_has_frame (GstVaapiFrameStore * fs)
+{
+  return fs->structure == GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+}
+
+static inline gboolean
+gst_vaapi_frame_store_is_complete (GstVaapiFrameStore * fs)
+{
+  return gst_vaapi_frame_store_has_frame (fs) ||
+      GST_VAAPI_PICTURE_IS_ONEFIELD (fs->buffers[0]);
+}
+
+static inline gboolean
+gst_vaapi_frame_store_has_reference (GstVaapiFrameStore * fs)
+{
+  guint i;
+
+  for (i = 0; i < fs->num_buffers; i++) {
+    if (GST_VAAPI_PICTURE_IS_REFERENCE (fs->buffers[i]))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean
+gst_vaapi_frame_store_has_inter_view (GstVaapiFrameStore * fs)
+{
+  guint i;
+
+  for (i = 0; i < fs->num_buffers; i++) {
+    if (GST_VAAPI_PICTURE_IS_INTER_VIEW (fs->buffers[i]))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+#define gst_vaapi_frame_store_ref(fs) \
+    gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(fs))
+
+#define gst_vaapi_frame_store_unref(fs) \
+    gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(fs))
+
+#define gst_vaapi_frame_store_replace(old_fs_p, new_fs)                 \
+    gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_fs_p),    \
+        (GstVaapiMiniObject *)(new_fs))
+
+/* ------------------------------------------------------------------------- */
+/* --- H.264 3D Info                                                     --- */
+/* ------------------------------------------------------------------------- */
+/**
+ * GstVaapiStereo3DInfo:
+ * @mode: the #GstVideoMultiviewMode.
+ * @flags: the #GstVideoMultiviewFlags.
+ * @id: the id number.
+ * @repetition_period: 0 means once, 1 means always, >1 compare with poc.
+ */
+struct _GstVaapiStereo3DInfo
+{
+  GstVideoMultiviewMode mode;
+  GstVideoMultiviewFlags flags;
+  guint id;
+  guint repetition_period;
+};
+
+/* ------------------------------------------------------------------------- */
+/* --- H.264 Decoder                                                     --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_DECODER_H264_CAST(decoder) \
+    ((GstVaapiDecoderH264 *)(decoder))
+
+typedef enum
+{
+  GST_H264_VIDEO_STATE_GOT_SPS = 1 << 0,
+  GST_H264_VIDEO_STATE_GOT_PPS = 1 << 1,
+  GST_H264_VIDEO_STATE_GOT_SLICE = 1 << 2,
+  GST_H264_VIDEO_STATE_GOT_I_FRAME = 1 << 3,    // persistent across SPS
+  GST_H264_VIDEO_STATE_GOT_P_SLICE = 1 << 4,    // predictive (all non-intra)
+
+  GST_H264_VIDEO_STATE_VALID_PICTURE_HEADERS = (GST_H264_VIDEO_STATE_GOT_SPS |
+      GST_H264_VIDEO_STATE_GOT_PPS),
+  GST_H264_VIDEO_STATE_VALID_PICTURE =
+      (GST_H264_VIDEO_STATE_VALID_PICTURE_HEADERS |
+      GST_H264_VIDEO_STATE_GOT_SLICE)
+} GstH264VideoState;
+
+struct _GstVaapiDecoderH264Private
+{
+  GstH264NalParser *parser;
+  guint parser_state;
+  guint decoder_state;
+  GstVaapiStreamAlignH264 stream_alignment;
+  GstVaapiPictureH264 *current_picture;
+  GstVaapiParserInfoH264 *sps[GST_H264_MAX_SPS_COUNT];
+  GstVaapiParserInfoH264 *active_sps;
+  GstVaapiParserInfoH264 *pps[GST_H264_MAX_PPS_COUNT];
+  GstVaapiParserInfoH264 *active_pps;
+  GstVaapiParserInfoH264 *prev_pi;
+  GstVaapiParserInfoH264 *prev_slice_pi;
+  GstVaapiFrameStore **prev_ref_frames;
+  GstVaapiFrameStore **prev_frames;
+  guint prev_frames_alloc;
+  GstVaapiFrameStore **dpb;
+  guint dpb_count;
+  guint dpb_size;
+  guint dpb_size_max;
+  guint max_views;
+  GstVaapiProfile profile;
+  GstVaapiEntrypoint entrypoint;
+  GstVaapiChromaType chroma_type;
+  GPtrArray *inter_views;
+  GstVaapiPictureH264 *short_ref[32];
+  guint short_ref_count;
+  GstVaapiPictureH264 *long_ref[32];
+  guint long_ref_count;
+  GstVaapiPictureH264 *RefPicList0[32];
+  guint RefPicList0_count;
+  GstVaapiPictureH264 *RefPicList1[32];
+  guint RefPicList1_count;
+  guint nal_length_size;
+  guint mb_width;
+  guint mb_height;
+  guint pic_structure;          // pic_struct (from SEI pic_timing() or inferred)
+  gint32 field_poc[2];          // 0:TopFieldOrderCnt / 1:BottomFieldOrderCnt
+  gint32 poc_msb;               // PicOrderCntMsb
+  gint32 poc_lsb;               // pic_order_cnt_lsb (from slice_header())
+  gint32 prev_poc_msb;          // prevPicOrderCntMsb
+  gint32 prev_poc_lsb;          // prevPicOrderCntLsb
+  gint32 frame_num_offset;      // FrameNumOffset
+  gint32 frame_num;             // frame_num (from slice_header())
+  gint32 prev_frame_num;        // prevFrameNum
+  gint32 prev_ref_frame_num;    // prevRefFrameNum
+  gboolean prev_pic_has_mmco5;  // prevMmco5Pic
+  gboolean prev_pic_reference;  // previous picture is a reference
+  guint prev_pic_structure;     // previous picture structure
+  guint is_opened:1;
+  guint is_avcC:1;
+  guint has_context:1;
+  guint progressive_sequence:1;
+  guint top_field_first:1;
+
+  gboolean force_low_latency;
+  gboolean base_only;
+
+  GstVaapiStereo3DInfo stereo_info;
+};
+
+/**
+ * GstVaapiDecoderH264:
+ *
+ * A decoder based on H264.
+ */
+struct _GstVaapiDecoderH264
+{
+  /*< private > */
+  GstVaapiDecoder parent_instance;
+  GstVaapiDecoderH264Private priv;
+};
+
+/**
+ * GstVaapiDecoderH264Class:
+ *
+ * A decoder class based on H264.
+ */
+struct _GstVaapiDecoderH264Class
+{
+  /*< private > */
+  GstVaapiDecoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiDecoderH264, gst_vaapi_decoder_h264,
+    GST_TYPE_VAAPI_DECODER);
+
+static gboolean
+exec_ref_pic_marking (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture);
+
+static gboolean
+exec_ref_pic_marking_sliding_window (GstVaapiDecoderH264 * decoder);
+
+static gboolean
+is_inter_view_reference_for_next_pictures (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture);
+
+static inline gboolean
+is_inter_view_reference_for_next_frames (GstVaapiDecoderH264 * decoder,
+    GstVaapiFrameStore * fs)
+{
+  return is_inter_view_reference_for_next_pictures (decoder, fs->buffers[0]);
+}
+
+/* Determines if the supplied profile is one of the MVC set */
+static gboolean
+is_mvc_profile (GstH264Profile profile)
+{
+  return profile == GST_H264_PROFILE_MULTIVIEW_HIGH ||
+      profile == GST_H264_PROFILE_STEREO_HIGH;
+}
+
+/* Determines the view_id from the supplied NAL unit */
+static inline guint
+get_view_id (GstH264NalUnit * nalu)
+{
+  return GST_H264_IS_MVC_NALU (nalu) ? nalu->extension.mvc.view_id : 0;
+}
+
+/* Determines the view order index (VOIdx) from the supplied view_id */
+static gint
+get_view_order_index (GstH264SPS * sps, guint16 view_id)
+{
+  GstH264SPSExtMVC *mvc;
+  gint i;
+
+  if (!sps || sps->extension_type != GST_H264_NAL_EXTENSION_MVC)
+    return 0;
+
+  mvc = &sps->extension.mvc;
+  for (i = 0; i <= mvc->num_views_minus1; i++) {
+    if (mvc->view[i].view_id == view_id)
+      return i;
+  }
+  GST_ERROR ("failed to find VOIdx from view_id (%d)", view_id);
+  return -1;
+}
+
+/* Determines NumViews */
+static guint
+get_num_views (GstH264SPS * sps)
+{
+  return 1 + (sps->extension_type == GST_H264_NAL_EXTENSION_MVC ?
+      sps->extension.mvc.num_views_minus1 : 0);
+}
+
+/* Get number of reference frames to use */
+static guint
+get_max_dec_frame_buffering (GstH264SPS * sps)
+{
+  guint num_views, max_dpb_frames;
+  guint max_dec_frame_buffering, PicSizeMbs;
+  GstVaapiLevelH264 level;
+  const GstVaapiH264LevelLimits *level_limits;
+
+  /* Table A-1 - Level limits */
+  if (G_UNLIKELY (sps->level_idc == 11 && sps->constraint_set3_flag))
+    level = GST_VAAPI_LEVEL_H264_L1b;
+  else
+    level = gst_vaapi_utils_h264_get_level (sps->level_idc);
+  level_limits = gst_vaapi_utils_h264_get_level_limits (level);
+  if (G_UNLIKELY (!level_limits)) {
+    GST_FIXME ("unsupported level_idc value (%d)", sps->level_idc);
+    max_dec_frame_buffering = 16;
+  } else {
+    PicSizeMbs = ((sps->pic_width_in_mbs_minus1 + 1) *
+        (sps->pic_height_in_map_units_minus1 + 1) *
+        (sps->frame_mbs_only_flag ? 1 : 2));
+    max_dec_frame_buffering = level_limits->MaxDpbMbs / PicSizeMbs;
+  }
+  if (is_mvc_profile (sps->profile_idc))
+    max_dec_frame_buffering <<= 1;
+
+  /* VUI parameters */
+  if (sps->vui_parameters_present_flag) {
+    GstH264VUIParams *const vui_params = &sps->vui_parameters;
+    if (vui_params->bitstream_restriction_flag)
+      max_dec_frame_buffering = vui_params->max_dec_frame_buffering;
+    else {
+      switch (sps->profile_idc) {
+        case 44:               // CAVLC 4:4:4 Intra profile
+        case GST_H264_PROFILE_SCALABLE_HIGH:
+        case GST_H264_PROFILE_HIGH:
+        case GST_H264_PROFILE_HIGH10:
+        case GST_H264_PROFILE_HIGH_422:
+        case GST_H264_PROFILE_HIGH_444:
+          if (sps->constraint_set3_flag)
+            max_dec_frame_buffering = 0;
+          break;
+      }
+    }
+  }
+
+  num_views = get_num_views (sps);
+  max_dpb_frames = 16 * (num_views > 1 ? g_bit_storage (num_views - 1) : 1);
+  if (max_dec_frame_buffering > max_dpb_frames)
+    max_dec_frame_buffering = max_dpb_frames;
+  else if (max_dec_frame_buffering < sps->num_ref_frames)
+    max_dec_frame_buffering = sps->num_ref_frames;
+  return MAX (1, max_dec_frame_buffering);
+}
+
+static void
+array_remove_index_fast (void *array, guint * array_length_ptr, guint index)
+{
+  gpointer *const entries = array;
+  guint num_entries = *array_length_ptr;
+
+  g_return_if_fail (index < num_entries);
+
+  if (index != --num_entries)
+    entries[index] = entries[num_entries];
+  entries[num_entries] = NULL;
+  *array_length_ptr = num_entries;
+}
+
+#if 1
+static inline void
+array_remove_index (void *array, guint * array_length_ptr, guint index)
+{
+  array_remove_index_fast (array, array_length_ptr, index);
+}
+#else
+static void
+array_remove_index (void *array, guint * array_length_ptr, guint index)
+{
+  gpointer *const entries = array;
+  const guint num_entries = *array_length_ptr - 1;
+  guint i;
+
+  g_return_if_fail (index <= num_entries);
+
+  for (i = index; i < num_entries; i++)
+    entries[i] = entries[i + 1];
+  entries[num_entries] = NULL;
+  *array_length_ptr = num_entries;
+}
+#endif
+
+#define ARRAY_REMOVE_INDEX(array, index) \
+    array_remove_index(array, &array##_count, index)
+
+static void
+dpb_remove_index (GstVaapiDecoderH264 * decoder, guint index)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  guint i, num_frames = --priv->dpb_count;
+
+  if (USE_STRICT_DPB_ORDERING) {
+    for (i = index; i < num_frames; i++)
+      gst_vaapi_frame_store_replace (&priv->dpb[i], priv->dpb[i + 1]);
+  } else if (index != num_frames)
+    gst_vaapi_frame_store_replace (&priv->dpb[index], priv->dpb[num_frames]);
+  gst_vaapi_frame_store_replace (&priv->dpb[num_frames], NULL);
+}
+
+static gboolean
+dpb_output (GstVaapiDecoderH264 * decoder, GstVaapiFrameStore * fs)
+{
+  GstVaapiPictureH264 *picture = NULL;
+  guint i;
+
+  g_return_val_if_fail (fs != NULL, FALSE);
+
+  fs->output_called++;
+  if (!gst_vaapi_frame_store_is_complete (fs))
+    return TRUE;
+
+  for (i = 0; i < fs->num_buffers; i++) {
+    GstVaapiPictureH264 *const pic = fs->buffers[i];
+    if (pic == NULL)
+      return FALSE;
+    pic->output_needed = FALSE;
+    if (!GST_VAAPI_PICTURE_FLAG_IS_SET (pic, GST_VAAPI_PICTURE_FLAG_GHOST))
+      picture = pic;
+  }
+
+  fs->output_needed = 0;
+  fs->output_called = 0;
+  if (!picture)
+    return TRUE;
+  return gst_vaapi_picture_output (GST_VAAPI_PICTURE_CAST (picture));
+}
+
+static inline void
+dpb_evict (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture,
+    guint i)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiFrameStore *const fs = priv->dpb[i];
+
+  if (!fs->output_needed && !gst_vaapi_frame_store_has_reference (fs))
+    dpb_remove_index (decoder, i);
+}
+
+/* Finds the picture with the nearest previous POC and same structure */
+static gint
+dpb_find_nearest_prev_poc (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, guint picture_structure,
+    GstVaapiPictureH264 ** found_picture_ptr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 *found_picture = NULL;
+  guint i, j, found_index = -1;
+
+  g_return_val_if_fail (picture != NULL, -1);
+
+  if (!picture_structure)
+    picture_structure = picture->base.structure;
+
+  for (i = 0; i < priv->dpb_count; i++) {
+    GstVaapiFrameStore *const fs = priv->dpb[i];
+    if (picture->base.view_id != fs->view_id)
+      continue;
+    for (j = 0; j < fs->num_buffers; j++) {
+      GstVaapiPictureH264 *const pic = fs->buffers[j];
+      if (pic->base.structure != picture_structure)
+        continue;
+      if (pic->base.poc >= picture->base.poc)
+        continue;
+      if (!found_picture || found_picture->base.poc < pic->base.poc)
+        found_picture = pic, found_index = i;
+    }
+  }
+
+  if (found_picture_ptr)
+    *found_picture_ptr = found_picture;
+  return found_index;
+}
+
+/* Finds the picture with the lowest POC that needs to be output */
+static gint
+dpb_find_lowest_poc_for_output (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstVaapiPictureH264 ** found_picture_ptr,
+    gboolean * can_be_output)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 *found_picture = NULL;
+  guint i, j, found_index = -1, found_poc = -1;
+  gboolean is_first = TRUE;
+  gint last_output_poc = -1;
+
+  for (i = 0; i < priv->dpb_count; i++) {
+    GstVaapiFrameStore *const fs = priv->dpb[i];
+    if (!fs->output_needed) {
+      /* find the maximum poc of any previously output frames that are
+       * still held in the DPB. */
+      if (can_be_output != NULL) {
+        for (j = 0; j < fs->num_buffers; j++) {
+          if (is_first || fs->buffers[j]->base.poc > last_output_poc) {
+            is_first = FALSE;
+            last_output_poc = fs->buffers[j]->base.poc;
+          }
+        }
+      }
+      continue;
+    }
+    if (picture && picture->base.view_id != fs->view_id)
+      continue;
+    for (j = 0; j < fs->num_buffers; j++) {
+      GstVaapiPictureH264 *const pic = fs->buffers[j];
+      if (!pic->output_needed)
+        continue;
+      if (!found_picture || found_picture->base.poc > pic->base.poc ||
+          (found_picture->base.poc == pic->base.poc &&
+              found_picture->base.voc > pic->base.voc))
+        found_picture = pic, found_index = i, found_poc = pic->base.poc;
+    }
+  }
+
+  if (can_be_output != NULL) {
+    /* found_picture can be output if it's the first frame in the DPB,
+     * or if there's no gap between it and the most recently output
+     * frame. */
+    *can_be_output = FALSE;
+    if (found_picture &&
+        gst_vaapi_frame_store_is_complete (priv->dpb[found_index])) {
+      if (is_first) {
+        *can_be_output = TRUE;
+      } else if (((int) (found_poc)) > ((int) (last_output_poc))) {
+        *can_be_output = (found_poc - last_output_poc) <= 2;
+      } else {
+        /* A frame with a higher poc has already been sent.  No choice
+         * now but to drop this frame */
+        GST_WARNING ("dropping out-of-sequence frame");
+        priv->dpb[found_index]->output_needed = FALSE;
+      }
+    }
+  }
+
+  if (found_picture_ptr)
+    *found_picture_ptr = found_picture;
+  return found_index;
+}
+
+/* Finds the picture with the lowest POC that needs to be output */
+static gint
+dpb_find_lowest_poc (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstVaapiPictureH264 ** found_picture_ptr)
+{
+  return dpb_find_lowest_poc_for_output (decoder, picture, found_picture_ptr,
+      NULL);
+}
+
+
+/* Finds the picture with the lowest VOC that needs to be output */
+static gint
+dpb_find_lowest_voc (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstVaapiPictureH264 ** found_picture_ptr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 *found_picture = NULL;
+  guint i, j, found_index = -1;
+
+  for (i = 0; i < priv->dpb_count; i++) {
+    GstVaapiFrameStore *const fs = priv->dpb[i];
+    if (!fs->output_needed || fs->view_id == picture->base.view_id)
+      continue;
+    for (j = 0; j < fs->num_buffers; j++) {
+      GstVaapiPictureH264 *const pic = fs->buffers[j];
+      if (!pic->output_needed || pic->base.poc != picture->base.poc)
+        continue;
+      if (!found_picture || found_picture->base.voc > pic->base.voc)
+        found_picture = pic, found_index = i;
+    }
+  }
+
+  if (found_picture_ptr)
+    *found_picture_ptr = found_picture;
+  return found_index;
+}
+
+static gboolean
+dpb_output_other_views (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, guint voc)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 *found_picture;
+  gint found_index;
+  gboolean success;
+
+  if (priv->max_views == 1)
+    return TRUE;
+
+  /* Emit all other view components that were in the same access
+     unit than the picture we have just found */
+  found_picture = picture;
+  for (;;) {
+    found_index = dpb_find_lowest_voc (decoder, found_picture, &found_picture);
+    if (found_index < 0 || found_picture->base.voc >= voc)
+      break;
+    success = dpb_output (decoder, priv->dpb[found_index]);
+    dpb_evict (decoder, found_picture, found_index);
+    if (!success)
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static gboolean
+dpb_bump (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 *found_picture;
+  gint found_index;
+  gboolean success;
+
+  found_index = dpb_find_lowest_poc (decoder, picture, &found_picture);
+  if (found_index < 0)
+    return FALSE;
+
+  gst_vaapi_picture_ref (found_picture);
+
+  if (picture && picture->base.poc != found_picture->base.poc)
+    dpb_output_other_views (decoder, found_picture, found_picture->base.voc);
+
+  success = dpb_output (decoder, priv->dpb[found_index]);
+
+  dpb_evict (decoder, found_picture, found_index);
+  if (priv->max_views == 1)
+    goto done;
+
+  if (picture && picture->base.poc != found_picture->base.poc)
+    dpb_output_other_views (decoder, found_picture, G_MAXUINT32);
+
+done:
+  gst_vaapi_picture_unref (found_picture);
+  return success;
+}
+
+static void
+dpb_output_ready_frames (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  gboolean can_output = FALSE;
+  gint found_index;
+
+  while (TRUE) {
+    found_index = dpb_find_lowest_poc_for_output (decoder,
+        priv->current_picture, NULL, &can_output);
+    if (found_index < 0 || !can_output)
+      break;
+    dpb_output (decoder, priv->dpb[found_index]);
+  }
+}
+
+static void
+dpb_clear (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  guint i, n;
+
+  for (i = 0; i < priv->dpb_count; i++) {
+    if (picture && picture->base.view_id != priv->dpb[i]->view_id)
+      continue;
+    gst_vaapi_frame_store_replace (&priv->dpb[i], NULL);
+  }
+
+  /* Compact the resulting DPB, i.e. remove holes */
+  for (i = 0, n = 0; i < priv->dpb_count; i++) {
+    if (priv->dpb[i]) {
+      if (i != n) {
+        priv->dpb[n] = priv->dpb[i];
+        priv->dpb[i] = NULL;
+      }
+      n++;
+    }
+  }
+  priv->dpb_count = n;
+
+  /* Clear previous frame buffers only if this is a "flush-all" operation,
+     or if the picture is the first one in the access unit */
+  if (priv->prev_frames && (!picture ||
+          GST_VAAPI_PICTURE_FLAG_IS_SET (picture,
+              GST_VAAPI_PICTURE_FLAG_AU_START))) {
+    for (i = 0; i < priv->max_views; i++)
+      gst_vaapi_frame_store_replace (&priv->prev_frames[i], NULL);
+  }
+
+  /* Clear previous reference frame buffers only if this is a "flush-all"
+     operation, or if the picture is part of an IDR NAL */
+  if (priv->prev_ref_frames && (!picture ||
+          GST_VAAPI_PICTURE_FLAG_IS_SET (picture,
+              GST_VAAPI_PICTURE_FLAG_IDR))) {
+    for (i = 0; i < priv->max_views; i++)
+      gst_vaapi_frame_store_replace (&priv->prev_ref_frames[i], NULL);
+  }
+}
+
+static void
+dpb_flush (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  guint i;
+
+  /* Detect broken frames and mark them as having a single field if
+     needed */
+  for (i = 0; i < priv->dpb_count; i++) {
+    GstVaapiFrameStore *const fs = priv->dpb[i];
+    if (!fs->output_needed || gst_vaapi_frame_store_is_complete (fs))
+      continue;
+    GST_VAAPI_PICTURE_FLAG_SET (fs->buffers[0],
+        GST_VAAPI_PICTURE_FLAG_ONEFIELD);
+  }
+
+  /* Output any frame remaining in DPB */
+  while (dpb_bump (decoder, picture));
+  dpb_clear (decoder, picture);
+}
+
+static void
+dpb_prune_mvc (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  const gboolean is_last_picture =      /* in the access unit */
+      GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_END);
+  guint i;
+
+  // Remove all unused inter-view only reference components of the current AU
+  i = 0;
+  while (i < priv->dpb_count) {
+    GstVaapiFrameStore *const fs = priv->dpb[i];
+    if (fs->view_id != picture->base.view_id &&
+        !fs->output_needed && !gst_vaapi_frame_store_has_reference (fs) &&
+        (is_last_picture ||
+            !is_inter_view_reference_for_next_frames (decoder, fs)))
+      dpb_remove_index (decoder, i);
+    else
+      i++;
+  }
+}
+
+static gboolean
+dpb_add (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiFrameStore *fs;
+  guint i;
+
+  if (priv->max_views > 1)
+    dpb_prune_mvc (decoder, picture);
+
+  // Remove all unused pictures
+  if (!GST_VAAPI_PICTURE_IS_IDR (picture)) {
+    i = 0;
+    while (i < priv->dpb_count) {
+      GstVaapiFrameStore *const fs = priv->dpb[i];
+      if (fs->view_id == picture->base.view_id &&
+          !fs->output_needed && !gst_vaapi_frame_store_has_reference (fs))
+        dpb_remove_index (decoder, i);
+      else
+        i++;
+    }
+  }
+  // Check if picture is the second field and the first field is still in DPB
+  if (GST_VAAPI_PICTURE_IS_INTERLACED (picture) &&
+      !GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture)) {
+    fs = priv->prev_frames[picture->base.voc];
+    if (!fs || &fs->buffers[0]->base != picture->base.parent_picture)
+      return FALSE;
+    if (!gst_vaapi_frame_store_add (fs, picture))
+      return FALSE;
+
+    if (fs->output_called)
+      return dpb_output (decoder, fs);
+    return TRUE;
+  }
+  // Try to output the previous frame again if it was not submitted yet
+  // e.g. delayed while waiting for the next field, or a field gap was closed
+  fs = priv->prev_frames[picture->base.voc];
+  if (fs && fs->output_called)
+    dpb_output (decoder, fs);
+
+  // Create new frame store, and split fields if necessary
+  fs = gst_vaapi_frame_store_new (picture);
+  if (!fs)
+    return FALSE;
+  gst_vaapi_frame_store_replace (&priv->prev_frames[picture->base.voc], fs);
+  gst_vaapi_frame_store_unref (fs);
+
+  if (!priv->progressive_sequence && gst_vaapi_frame_store_has_frame (fs)) {
+    if (!gst_vaapi_frame_store_split_fields (fs, priv->top_field_first))
+      return FALSE;
+  }
+  // C.4.5.1 - Storage and marking of a reference decoded picture into the DPB
+  if (GST_VAAPI_PICTURE_IS_REFERENCE (picture)) {
+    while (priv->dpb_count == priv->dpb_size) {
+      if (!dpb_bump (decoder, picture))
+        return FALSE;
+    }
+    gst_vaapi_frame_store_replace (&priv->prev_ref_frames[picture->base.voc],
+        fs);
+  }
+  // C.4.5.2 - Storage and marking of a non-reference decoded picture into the DPB
+  else {
+    const gboolean StoreInterViewOnlyRefFlag =
+        !GST_VAAPI_PICTURE_FLAG_IS_SET (picture,
+        GST_VAAPI_PICTURE_FLAG_AU_END) &&
+        GST_VAAPI_PICTURE_FLAG_IS_SET (picture,
+        GST_VAAPI_PICTURE_FLAG_INTER_VIEW);
+    if (!picture->output_flag && !StoreInterViewOnlyRefFlag)
+      return TRUE;
+    while (priv->dpb_count == priv->dpb_size) {
+      GstVaapiPictureH264 *found_picture;
+      if (!StoreInterViewOnlyRefFlag) {
+        if (dpb_find_lowest_poc (decoder, picture, &found_picture) < 0 ||
+            found_picture->base.poc > picture->base.poc)
+          return dpb_output (decoder, fs);
+      }
+      if (!dpb_bump (decoder, picture))
+        return FALSE;
+    }
+  }
+  gst_vaapi_frame_store_replace (&priv->dpb[priv->dpb_count++], fs);
+  return TRUE;
+}
+
+static gboolean
+dpb_reset (GstVaapiDecoderH264 * decoder, guint dpb_size)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+
+  if (dpb_size > priv->dpb_size_max) {
+    priv->dpb = g_try_realloc_n (priv->dpb, dpb_size, sizeof (*priv->dpb));
+    if (!priv->dpb)
+      return FALSE;
+    memset (&priv->dpb[priv->dpb_size_max], 0,
+        (dpb_size - priv->dpb_size_max) * sizeof (*priv->dpb));
+    priv->dpb_size_max = dpb_size;
+  }
+  priv->dpb_size = dpb_size;
+
+  GST_DEBUG ("DPB size %u", priv->dpb_size);
+  return TRUE;
+}
+
+static void
+unref_inter_view (GstVaapiPictureH264 * picture)
+{
+  if (!picture)
+    return;
+  GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAG_INTER_VIEW);
+  gst_vaapi_picture_unref (picture);
+}
+
+/* Resets MVC resources */
+static gboolean
+mvc_reset (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  guint i;
+
+  // Resize array of inter-view references
+  if (!priv->inter_views) {
+    priv->inter_views = g_ptr_array_new_full (priv->max_views,
+        (GDestroyNotify) unref_inter_view);
+    if (!priv->inter_views)
+      return FALSE;
+  }
+  // Resize array of previous frame buffers
+  for (i = priv->max_views; i < priv->prev_frames_alloc; i++) {
+    gst_vaapi_frame_store_replace (&priv->prev_ref_frames[i], NULL);
+    gst_vaapi_frame_store_replace (&priv->prev_frames[i], NULL);
+  }
+
+  priv->prev_ref_frames = g_try_realloc_n (priv->prev_ref_frames,
+      priv->max_views, sizeof (*priv->prev_ref_frames));
+  if (!priv->prev_ref_frames)
+    goto error_allocate;
+
+  priv->prev_frames = g_try_realloc_n (priv->prev_frames, priv->max_views,
+      sizeof (*priv->prev_frames));
+  if (!priv->prev_frames)
+    goto error_allocate;
+
+  for (i = priv->prev_frames_alloc; i < priv->max_views; i++) {
+    priv->prev_ref_frames[i] = NULL;
+    priv->prev_frames[i] = NULL;
+  }
+  priv->prev_frames_alloc = priv->max_views;
+  return TRUE;
+
+  /* ERRORS */
+error_allocate:
+  {
+    g_free (priv->prev_ref_frames);
+    priv->prev_ref_frames = NULL;
+    g_free (priv->prev_frames);
+    priv->prev_frames = NULL;
+    priv->prev_frames_alloc = 0;
+    return FALSE;
+  }
+}
+
+static GstVaapiDecoderStatus
+get_status (GstH264ParserResult result)
+{
+  GstVaapiDecoderStatus status;
+
+  switch (result) {
+    case GST_H264_PARSER_OK:
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+    case GST_H264_PARSER_NO_NAL_END:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+      break;
+    case GST_H264_PARSER_ERROR:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+      break;
+    default:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+      break;
+  }
+  return status;
+}
+
+static void
+gst_vaapi_decoder_h264_close (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  gst_vaapi_parser_info_h264_replace (&priv->prev_slice_pi, NULL);
+  gst_vaapi_parser_info_h264_replace (&priv->prev_pi, NULL);
+
+  dpb_clear (decoder, NULL);
+
+  if (priv->inter_views) {
+    g_ptr_array_unref (priv->inter_views);
+    priv->inter_views = NULL;
+  }
+
+  if (priv->parser) {
+    gst_h264_nal_parser_free (priv->parser);
+    priv->parser = NULL;
+  }
+}
+
+static gboolean
+gst_vaapi_decoder_h264_open (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_h264_close (decoder);
+
+  priv->parser = gst_h264_nal_parser_new ();
+  if (!priv->parser)
+    return FALSE;
+  return TRUE;
+}
+
+static void
+gst_vaapi_decoder_h264_destroy (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderH264 *const decoder =
+      GST_VAAPI_DECODER_H264_CAST (base_decoder);
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  guint i;
+
+  gst_vaapi_decoder_h264_close (decoder);
+  priv->is_opened = FALSE;
+
+  g_clear_pointer (&priv->dpb, g_free);
+  priv->dpb_size_max = priv->dpb_size = 0;
+
+  g_clear_pointer (&priv->prev_ref_frames, g_free);
+  g_clear_pointer (&priv->prev_frames, g_free);
+  priv->prev_frames_alloc = 0;
+
+  for (i = 0; i < G_N_ELEMENTS (priv->pps); i++)
+    gst_vaapi_parser_info_h264_replace (&priv->pps[i], NULL);
+  gst_vaapi_parser_info_h264_replace (&priv->active_pps, NULL);
+
+  for (i = 0; i < G_N_ELEMENTS (priv->sps); i++)
+    gst_vaapi_parser_info_h264_replace (&priv->sps[i], NULL);
+  gst_vaapi_parser_info_h264_replace (&priv->active_sps, NULL);
+}
+
+static gboolean
+gst_vaapi_decoder_h264_create (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderH264 *const decoder =
+      GST_VAAPI_DECODER_H264_CAST (base_decoder);
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+
+  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  priv->entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+  priv->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+  priv->prev_pic_structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+  priv->progressive_sequence = TRUE;
+  priv->top_field_first = FALSE;
+  priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_MONO;
+  priv->stereo_info.flags = GST_VIDEO_MULTIVIEW_FLAGS_NONE;
+  return TRUE;
+}
+
+/* Limited reset can just needs to get the decoder
+ * ready to process fresh data after a flush.
+ * Preserves the existing DPB allocation and any SPS/PPS */
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h264_reset (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderH264 *const decoder =
+      GST_VAAPI_DECODER_H264_CAST (base_decoder);
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_h264_close (decoder);
+  priv->is_opened = FALSE;
+
+  priv->dpb_size = 0;
+
+  g_clear_pointer (&priv->prev_ref_frames, g_free);
+  g_clear_pointer (&priv->prev_frames, g_free);
+  priv->prev_frames_alloc = 0;
+  gst_vaapi_parser_info_h264_replace (&priv->active_pps, NULL);
+  gst_vaapi_parser_info_h264_replace (&priv->active_sps, NULL);
+
+  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  priv->entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+  priv->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+  priv->prev_pic_structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+  priv->progressive_sequence = TRUE;
+  priv->top_field_first = FALSE;
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+/* Activates the supplied PPS */
+static GstH264PPS *
+ensure_pps (GstVaapiDecoderH264 * decoder, GstH264PPS * pps)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = priv->pps[pps->id];
+
+  gst_vaapi_parser_info_h264_replace (&priv->active_pps, pi);
+  return pi ? &pi->data.pps : NULL;
+}
+
+/* Returns the active PPS */
+static inline GstH264PPS *
+get_pps (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiParserInfoH264 *const pi = decoder->priv.active_pps;
+
+  return pi ? &pi->data.pps : NULL;
+}
+
+/* Activate the supplied SPS */
+static GstH264SPS *
+ensure_sps (GstVaapiDecoderH264 * decoder, GstH264SPS * sps)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = priv->sps[sps->id];
+
+  /* Propagate "got I-frame" state to the next SPS unit if the
+     current sequence was not ended */
+  if (pi && priv->active_sps)
+    pi->state |= (priv->active_sps->state & GST_H264_VIDEO_STATE_GOT_I_FRAME);
+
+  gst_vaapi_parser_info_h264_replace (&priv->active_sps, pi);
+  return pi ? &pi->data.sps : NULL;
+}
+
+/* Returns the active SPS */
+static inline GstH264SPS *
+get_sps (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiParserInfoH264 *const pi = decoder->priv.active_sps;
+
+  return pi ? &pi->data.sps : NULL;
+}
+
+static void
+fill_profiles (GstVaapiProfile profiles[], guint * n_profiles_ptr,
+    GstVaapiProfile profile)
+{
+  guint n_profiles = *n_profiles_ptr;
+
+  profiles[n_profiles++] = profile;
+  switch (profile) {
+    case GST_VAAPI_PROFILE_H264_MAIN:
+      profiles[n_profiles++] = GST_VAAPI_PROFILE_H264_HIGH;
+      break;
+    default:
+      break;
+  }
+  *n_profiles_ptr = n_profiles;
+}
+
+/* Fills in compatible profiles for MVC decoding */
+static void
+fill_profiles_mvc (GstVaapiDecoderH264 * decoder, GstVaapiProfile profiles[],
+    guint * n_profiles_ptr, guint dpb_size)
+{
+  const gchar *const vendor_string =
+      gst_vaapi_display_get_vendor_string (GST_VAAPI_DECODER_DISPLAY (decoder));
+
+  gboolean add_high_profile = FALSE;
+  struct map
+  {
+    const gchar *str;
+    guint str_len;
+  };
+  const struct map *m;
+
+  // Drivers that support slice level decoding
+  if (vendor_string && dpb_size <= 16) {
+    static const struct map drv_names[] = {
+      {"Intel i965 driver", 17},
+      {NULL, 0}
+    };
+    for (m = drv_names; m->str != NULL && !add_high_profile; m++) {
+      if (g_ascii_strncasecmp (vendor_string, m->str, m->str_len) == 0)
+        add_high_profile = TRUE;
+    }
+  }
+
+  if (add_high_profile)
+    fill_profiles (profiles, n_profiles_ptr, GST_VAAPI_PROFILE_H264_HIGH);
+}
+
+static GstVaapiProfile
+get_profile (GstVaapiDecoderH264 * decoder, GstH264SPS * sps, guint dpb_size)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiDisplay *const display = GST_VAAPI_DECODER_DISPLAY (decoder);
+  GstVaapiProfile profile, profiles[4];
+  guint i, n_profiles = 0;
+
+  profile = gst_vaapi_utils_h264_get_profile (sps->profile_idc);
+  if (!profile)
+    return GST_VAAPI_PROFILE_UNKNOWN;
+
+  fill_profiles (profiles, &n_profiles, profile);
+  switch (profile) {
+    case GST_VAAPI_PROFILE_H264_BASELINE:
+      GST_INFO ("Baseline stream to be processed as Constrained-Baseline or "
+          "Main");
+      fill_profiles (profiles, &n_profiles,
+          GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE);
+      fill_profiles (profiles, &n_profiles, GST_VAAPI_PROFILE_H264_MAIN);
+      break;
+    case GST_VAAPI_PROFILE_H264_EXTENDED:
+      if (sps->constraint_set1_flag) {  // A.2.2 (main profile)
+        fill_profiles (profiles, &n_profiles, GST_VAAPI_PROFILE_H264_MAIN);
+      }
+      break;
+    case GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH:
+      if (priv->max_views == 2) {
+        fill_profiles (profiles, &n_profiles,
+            GST_VAAPI_PROFILE_H264_STEREO_HIGH);
+      }
+      fill_profiles_mvc (decoder, profiles, &n_profiles, dpb_size);
+      break;
+    case GST_VAAPI_PROFILE_H264_STEREO_HIGH:
+      if (sps->frame_mbs_only_flag) {
+        fill_profiles (profiles, &n_profiles,
+            GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH);
+      }
+      fill_profiles_mvc (decoder, profiles, &n_profiles, dpb_size);
+      break;
+    default:
+      break;
+  }
+
+  /* If the preferred profile (profiles[0]) matches one that we already
+     found, then just return it now instead of searching for it again */
+  if (profiles[0] == priv->profile)
+    return priv->profile;
+
+  for (i = 0; i < n_profiles; i++) {
+    if (gst_vaapi_display_has_decoder (display, profiles[i], priv->entrypoint))
+      return profiles[i];
+  }
+  return GST_VAAPI_PROFILE_UNKNOWN;
+}
+
+static GstVaapiDecoderStatus
+ensure_context (GstVaapiDecoderH264 * decoder, GstH264SPS * sps)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER_CAST (decoder);
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiContextInfo info;
+  GstVaapiProfile profile;
+  GstVaapiChromaType chroma_type;
+  gboolean reset_context = FALSE;
+  guint mb_width, mb_height, dpb_size, num_views;
+
+  num_views = get_num_views (sps);
+  if (priv->max_views < num_views) {
+    priv->max_views = num_views;
+    reset_context = TRUE;
+    GST_DEBUG ("maximum number of views changed to %u", num_views);
+  }
+
+  dpb_size = get_max_dec_frame_buffering (sps);
+  if (priv->dpb_size < dpb_size) {
+    GST_DEBUG ("DPB size increased");
+    reset_context = TRUE;
+  }
+
+  profile = get_profile (decoder, sps, dpb_size);
+  if (!profile) {
+    GST_ERROR ("unsupported profile_idc %u", sps->profile_idc);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  if (!priv->profile || (priv->profile != profile && priv->max_views == 1)) {
+    GST_DEBUG ("profile changed to %x", profile);
+    reset_context = TRUE;
+    priv->profile = profile;
+  }
+
+  if (reset_context) {
+    switch (num_views) {
+      case 1:
+        /* Frame-packed mode details should be used if we got */
+        if (priv->stereo_info.mode != GST_VIDEO_MULTIVIEW_MODE_NONE) {
+          gst_vaapi_decoder_set_multiview_mode (base_decoder,
+              2, priv->stereo_info.mode, priv->stereo_info.flags);
+        } else {
+          gst_vaapi_decoder_set_multiview_mode (base_decoder,
+              num_views, GST_VIDEO_MULTIVIEW_MODE_NONE,
+              GST_VIDEO_MULTIVIEW_FLAGS_NONE);
+        }
+        break;
+      case 2:                  /* Assume stereo */
+        if (profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) {
+          GST_DEBUG ("Stereo profile - frame-by-frame output, %d views",
+              num_views);
+          gst_vaapi_decoder_set_multiview_mode (base_decoder, num_views,
+              GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME,
+              GST_VIDEO_MULTIVIEW_FLAGS_NONE);
+          break;
+        }
+        /* non-stereo 2 views. Fall through */
+      default:
+        GST_DEBUG ("Multiview profile - frame-by-frame output, %d views",
+            num_views);
+        gst_vaapi_decoder_set_multiview_mode (base_decoder, num_views,
+            GST_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME,
+            GST_VIDEO_MULTIVIEW_FLAGS_NONE);
+        break;
+    }
+  }
+
+  chroma_type = gst_vaapi_utils_h264_get_chroma_type (sps->chroma_format_idc);
+  if (!chroma_type) {
+    GST_ERROR ("unsupported chroma_format_idc %u", sps->chroma_format_idc);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
+  }
+
+  if (priv->chroma_type != chroma_type) {
+    GST_DEBUG ("chroma format changed");
+    reset_context = TRUE;
+    priv->chroma_type = chroma_type;
+  }
+
+  mb_width = sps->pic_width_in_mbs_minus1 + 1;
+  mb_height =
+      (sps->pic_height_in_map_units_minus1 + 1) << !sps->frame_mbs_only_flag;
+  if (priv->mb_width != mb_width || priv->mb_height != mb_height) {
+    GST_DEBUG ("size changed");
+    reset_context = TRUE;
+    priv->mb_width = mb_width;
+    priv->mb_height = mb_height;
+  }
+
+  if (priv->progressive_sequence != sps->frame_mbs_only_flag) {
+    GST_DEBUG ("interlacing-mode changed");
+    priv->progressive_sequence = sps->frame_mbs_only_flag;
+    gst_vaapi_decoder_set_interlaced (base_decoder,
+        !priv->progressive_sequence);
+    priv->top_field_first = FALSE;
+  }
+
+  gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder,
+      sps->vui_parameters.par_n, sps->vui_parameters.par_d);
+
+  if (!reset_context && priv->has_context)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* XXX: fix surface size when cropping is implemented */
+  info.profile = priv->profile;
+  info.entrypoint = priv->entrypoint;
+  info.chroma_type = priv->chroma_type;
+  info.width = sps->width;
+  info.height = sps->height;
+  info.ref_frames = dpb_size;
+
+  if (!gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  priv->has_context = TRUE;
+
+  /* Reset DPB */
+  if (!dpb_reset (decoder, dpb_size))
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+
+  /* Reset MVC data */
+  if (!mvc_reset (decoder))
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+fill_iq_matrix_4x4 (VAIQMatrixBufferH264 * iq_matrix, const GstH264PPS * pps,
+    const GstH264SPS * sps)
+{
+  guint i;
+
+  /* There are always 6 4x4 scaling lists */
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList4x4) == 6);
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList4x4[0]) == 16);
+
+  for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList4x4); i++)
+    gst_h264_quant_matrix_4x4_get_raster_from_zigzag (iq_matrix->ScalingList4x4
+        [i], pps->scaling_lists_4x4[i]);
+}
+
+static void
+fill_iq_matrix_8x8 (VAIQMatrixBufferH264 * iq_matrix, const GstH264PPS * pps,
+    const GstH264SPS * sps)
+{
+  guint i, n;
+
+  /* If chroma_format_idc != 3, there are up to 2 8x8 scaling lists */
+  if (!pps->transform_8x8_mode_flag)
+    return;
+
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList8x8) >= 2);
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList8x8[0]) == 64);
+
+  n = (sps->chroma_format_idc != 3) ? 2 : 6;
+  for (i = 0; i < n; i++) {
+    gst_h264_quant_matrix_8x8_get_raster_from_zigzag (iq_matrix->ScalingList8x8
+        [i], pps->scaling_lists_8x8[i]);
+  }
+}
+
+static GstVaapiDecoderStatus
+ensure_quant_matrix (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture)
+{
+  GstVaapiPicture *const base_picture = &picture->base;
+  GstH264PPS *const pps = get_pps (decoder);
+  GstH264SPS *const sps = get_sps (decoder);
+  VAIQMatrixBufferH264 *iq_matrix;
+
+  base_picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (H264, decoder);
+  if (!base_picture->iq_matrix) {
+    GST_ERROR ("failed to allocate IQ matrix");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  iq_matrix = base_picture->iq_matrix->param;
+
+  /* XXX: we can only support 4:2:0 or 4:2:2 since ScalingLists8x8[]
+     is not large enough to hold lists for 4:4:4 */
+  if (sps->chroma_format_idc == 3)
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
+
+  fill_iq_matrix_4x4 (iq_matrix, pps, sps);
+  fill_iq_matrix_8x8 (iq_matrix, pps, sps);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline gboolean
+is_valid_state (guint state, guint ref_state)
+{
+  return (state & ref_state) == ref_state;
+}
+
+static GstVaapiDecoderStatus
+decode_current_picture (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const sps_pi = decoder->priv.active_sps;
+  GstVaapiPictureH264 *const picture = priv->current_picture;
+
+  if (!is_valid_state (priv->decoder_state, GST_H264_VIDEO_STATE_VALID_PICTURE))
+    goto drop_frame;
+
+  priv->decoder_state |= sps_pi->state;
+  if (!(priv->decoder_state & GST_H264_VIDEO_STATE_GOT_I_FRAME)) {
+    if (priv->decoder_state & GST_H264_VIDEO_STATE_GOT_P_SLICE)
+      goto drop_frame;
+    sps_pi->state |= GST_H264_VIDEO_STATE_GOT_I_FRAME;
+  }
+
+  priv->decoder_state = 0;
+  priv->pic_structure = GST_H264_SEI_PIC_STRUCT_FRAME;
+
+  if (!picture)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_vaapi_picture_decode (GST_VAAPI_PICTURE_CAST (picture)))
+    goto error;
+  if (!exec_ref_pic_marking (decoder, picture))
+    goto error;
+  if (!dpb_add (decoder, picture))
+    goto error;
+
+  if (priv->force_low_latency)
+    dpb_output_ready_frames (decoder);
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    /* XXX: fix for cases where first field failed to be decoded */
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+drop_frame:
+  {
+    priv->decoder_state = 0;
+    priv->pic_structure = GST_H264_SEI_PIC_STRUCT_FRAME;
+    return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME;
+  }
+}
+
+static GstVaapiDecoderStatus
+parse_sps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstH264SPS *const sps = &pi->data.sps;
+  GstH264ParserResult result;
+
+  GST_DEBUG ("parse SPS");
+
+  priv->parser_state = 0;
+
+  /* Variables that don't have inferred values per the H.264
+     standard but that should get a default value anyway */
+  sps->log2_max_pic_order_cnt_lsb_minus4 = 0;
+
+  result = gst_h264_parser_parse_sps (priv->parser, &pi->nalu, sps);
+  if (result != GST_H264_PARSER_OK)
+    return get_status (result);
+
+  priv->parser_state |= GST_H264_VIDEO_STATE_GOT_SPS;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_subset_sps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstH264SPS *const sps = &pi->data.sps;
+  GstH264ParserResult result;
+
+  GST_DEBUG ("parse subset SPS");
+
+  /* Variables that don't have inferred values per the H.264
+     standard but that should get a default value anyway */
+  sps->log2_max_pic_order_cnt_lsb_minus4 = 0;
+
+  result = gst_h264_parser_parse_subset_sps (priv->parser, &pi->nalu, sps);
+  if (result != GST_H264_PARSER_OK)
+    return get_status (result);
+
+  priv->parser_state |= GST_H264_VIDEO_STATE_GOT_SPS;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_pps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstH264PPS *const pps = &pi->data.pps;
+  GstH264ParserResult result;
+
+  GST_DEBUG ("parse PPS");
+
+  /* Variables that don't have inferred values per the H.264
+     standard but that should get a default value anyway */
+  pps->slice_group_map_type = 0;
+  pps->slice_group_change_rate_minus1 = 0;
+  pps->slice_group_id = NULL;
+
+  result = gst_h264_parser_parse_pps (priv->parser, &pi->nalu, pps);
+
+  /* PPS's sps id might be an ignored subset sps in SVC streams */
+  if (priv->base_only && result == GST_H264_PARSER_BROKEN_LINK) {
+    pi->nalu.valid = FALSE;
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  }
+
+  priv->parser_state &= GST_H264_VIDEO_STATE_GOT_SPS;
+
+  if (result != GST_H264_PARSER_OK)
+    return get_status (result);
+
+  priv->parser_state |= GST_H264_VIDEO_STATE_GOT_PPS;
+
+  if (pps->num_slice_groups_minus1 > 0) {
+    GST_FIXME ("FMO is not supported");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_sei (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GArray **const sei_ptr = &pi->data.sei;
+  GstH264ParserResult result;
+
+  GST_DEBUG ("parse SEI");
+
+  result = gst_h264_parser_parse_sei (priv->parser, &pi->nalu, sei_ptr);
+  if (result != GST_H264_PARSER_OK) {
+    GST_WARNING ("failed to parse SEI messages");
+    return get_status (result);
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_slice (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstH264NalUnit *const nalu = &pi->nalu;
+  GstH264SPS *sps;
+  GstH264ParserResult result;
+
+  GST_DEBUG ("parse slice");
+
+  priv->parser_state &= (GST_H264_VIDEO_STATE_GOT_SPS |
+      GST_H264_VIDEO_STATE_GOT_PPS);
+
+  /* Propagate Prefix NAL unit info, if necessary */
+  switch (nalu->type) {
+    case GST_H264_NAL_SLICE:
+    case GST_H264_NAL_SLICE_IDR:{
+      GstVaapiParserInfoH264 *const prev_pi = priv->prev_pi;
+      if (prev_pi && prev_pi->nalu.type == GST_H264_NAL_PREFIX_UNIT) {
+        /* MVC sequences shall have a Prefix NAL unit immediately
+           preceding this NAL unit */
+        pi->nalu.extension_type = prev_pi->nalu.extension_type;
+        pi->nalu.extension = prev_pi->nalu.extension;
+      } else {
+        /* In the very unlikely case there is no Prefix NAL unit
+           immediately preceding this NAL unit, try to infer some
+           defaults (H.7.4.1.1) */
+        GstH264NalUnitExtensionMVC *const mvc = &pi->nalu.extension.mvc;
+        mvc->non_idr_flag = !(nalu->type == GST_H264_NAL_SLICE_IDR);
+        nalu->idr_pic_flag = !mvc->non_idr_flag;
+        mvc->priority_id = 0;
+        mvc->view_id = 0;
+        mvc->temporal_id = 0;
+        mvc->anchor_pic_flag = 0;
+        mvc->inter_view_flag = 1;
+      }
+      break;
+    }
+  }
+
+  /* Variables that don't have inferred values per the H.264
+     standard but that should get a default value anyway */
+  slice_hdr->cabac_init_idc = 0;
+  slice_hdr->direct_spatial_mv_pred_flag = 0;
+
+  result = gst_h264_parser_parse_slice_hdr (priv->parser, &pi->nalu,
+      slice_hdr, TRUE, TRUE);
+  if (result != GST_H264_PARSER_OK)
+    return get_status (result);
+
+  sps = slice_hdr->pps->sequence;
+
+  /* Update MVC data */
+  pi->view_id = get_view_id (&pi->nalu);
+  pi->voc = get_view_order_index (sps, pi->view_id);
+
+  priv->parser_state |= GST_H264_VIDEO_STATE_GOT_SLICE;
+  if (!GST_H264_IS_I_SLICE (slice_hdr))
+    priv->parser_state |= GST_H264_VIDEO_STATE_GOT_P_SLICE;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstH264SPS *const sps = &pi->data.sps;
+
+  GST_DEBUG ("decode SPS");
+
+  gst_vaapi_parser_info_h264_replace (&priv->sps[sps->id], pi);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_subset_sps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstH264SPS *const sps = &pi->data.sps;
+
+  GST_DEBUG ("decode subset SPS");
+
+  gst_vaapi_parser_info_h264_replace (&priv->sps[sps->id], pi);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_pps (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstH264PPS *const pps = &pi->data.pps;
+
+  GST_DEBUG ("decode PPS");
+
+  gst_vaapi_parser_info_h264_replace (&priv->pps[pps->id], pi);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static gboolean
+decode_sei_frame_packing (GstVaapiDecoderH264 * decoder,
+    const GstH264FramePacking * frame_packing)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVideoMultiviewMode saved_mode = priv->stereo_info.mode;
+  GstVideoMultiviewFlags saved_flags = priv->stereo_info.flags;
+  gboolean left = TRUE;
+  gboolean frame_revert = FALSE;
+
+  /* Only IDs from 0->255 and 512->2^31-1 are valid. Ignore others */
+  if ((frame_packing->frame_packing_id >= 256 &&
+          frame_packing->frame_packing_id < 512) ||
+      (frame_packing->frame_packing_id >= (1U << 31)))
+    return FALSE;
+
+  if (frame_packing->frame_packing_cancel_flag) {
+    if (priv->stereo_info.id == frame_packing->frame_packing_id)
+      priv->stereo_info = (GstVaapiStereo3DInfo) {
+      GST_VIDEO_MULTIVIEW_MODE_MONO, GST_VIDEO_MULTIVIEW_FLAGS_NONE, 256, 0};
+    return TRUE;
+  }
+
+  if (frame_packing->frame_packing_repetition_period != 1) {
+    GST_WARNING ("SEI: repetition_period != 1 is not unsupported");
+    return FALSE;
+  }
+
+  if (frame_packing->frame_packing_type > GST_H264_FRAME_PACKING_NONE) {
+    GST_WARNING ("SEI: unsupported frame_packing_type %d",
+        frame_packing->frame_packing_type);
+    return FALSE;
+  }
+
+  if (frame_packing->content_interpretation_type >= 3) {
+    GST_WARNING ("SEI: unsupported content_interpretation_type %d",
+        frame_packing->frame_packing_type);
+    return FALSE;
+  }
+
+  /* TODO: frame frame0/1_grid_position_x/y are ignored now. */
+
+  priv->stereo_info = (GstVaapiStereo3DInfo) {
+  GST_VIDEO_MULTIVIEW_MODE_MONO, GST_VIDEO_MULTIVIEW_FLAGS_NONE, 256, 0};
+
+  switch (frame_packing->frame_packing_type) {
+    case GST_H264_FRAME_PACKING_CHECKERBOARD_INTERLEAVING:
+      priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_CHECKERBOARD;
+      break;
+    case GST_H264_FRAME_PACKING_COLUMN_INTERLEAVING:
+      priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_COLUMN_INTERLEAVED;
+      break;
+    case GST_H264_FRAME_PACKING_ROW_INTERLEAVING:
+      priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_ROW_INTERLEAVED;
+      break;
+    case GST_H264_FRAME_PACKING_SIDE_BY_SIDE:
+      if (frame_packing->quincunx_sampling_flag) {
+        priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE_QUINCUNX;
+      } else {
+        priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_SIDE_BY_SIDE;
+      }
+      break;
+    case GST_H264_FRAME_PACKING_TOP_BOTTOM:
+      priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_TOP_BOTTOM;
+      break;
+    case GST_H264_FRAME_PACKING_TEMPORAL_INTERLEAVING:
+      priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME;
+      break;
+    default:
+      priv->stereo_info.mode = GST_VIDEO_MULTIVIEW_MODE_MONO;
+      break;
+  }
+
+  /* Spec does not describe multi-IDs case, we just keep one valid */
+  priv->stereo_info.id = frame_packing->frame_packing_id;
+  priv->stereo_info.repetition_period =
+      frame_packing->frame_packing_repetition_period;
+
+  if (frame_packing->content_interpretation_type == 2)
+    frame_revert = TRUE;
+
+  if (frame_packing->frame_packing_type ==
+      GST_H264_FRAME_PACKING_TEMPORAL_INTERLEAVING) {
+    if (frame_packing->current_frame_is_frame0_flag) {
+      left = TRUE;
+    } else {
+      left = FALSE;
+    }
+
+    if (frame_revert)
+      left = !left;
+  }
+
+  if (!left)
+    priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST;
+
+  if (frame_packing->frame_packing_type == GST_H264_FRAME_PACKING_SIDE_BY_SIDE
+      && frame_packing->spatial_flipping_flag) {
+    if (frame_packing->frame0_flipped_flag !=
+        ((priv->stereo_info.flags &
+                GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST) != 0)) {
+      priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLOPPED;
+    } else {
+      priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLOPPED;
+    }
+  }
+  if (frame_packing->frame_packing_type == GST_H264_FRAME_PACKING_TOP_BOTTOM
+      && frame_packing->spatial_flipping_flag !=
+      ((priv->stereo_info.flags &
+              GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_VIEW_FIRST) != 0)) {
+    if (frame_packing->frame0_flipped_flag) {
+      priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_LEFT_FLIPPED;
+    } else {
+      priv->stereo_info.flags |= GST_VIDEO_MULTIVIEW_FLAGS_RIGHT_FLIPPED;
+    }
+  }
+
+  if (saved_mode != priv->stereo_info.mode
+      || saved_flags != priv->stereo_info.flags) {
+    gst_vaapi_decoder_set_multiview_mode (GST_VAAPI_DECODER_CAST (decoder),
+        2, priv->stereo_info.mode, priv->stereo_info.flags);
+  }
+
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_sei (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  guint i;
+
+  GST_DEBUG ("decode SEI messages");
+
+  for (i = 0; i < pi->data.sei->len; i++) {
+    const GstH264SEIMessage *const sei =
+        &g_array_index (pi->data.sei, GstH264SEIMessage, i);
+
+    switch (sei->payloadType) {
+      case GST_H264_SEI_PIC_TIMING:{
+        const GstH264PicTiming *const pic_timing = &sei->payload.pic_timing;
+        if (pic_timing->pic_struct_present_flag)
+          priv->pic_structure = pic_timing->pic_struct;
+        break;
+      }
+      case GST_H264_SEI_FRAME_PACKING:
+        decode_sei_frame_packing (decoder, &sei->payload.frame_packing);
+        break;
+      default:
+        break;
+    }
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_end (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const sps_pi = decoder->priv.active_sps;
+
+  GST_DEBUG ("decode sequence-end");
+
+  /* Sequence ended, don't try to propagate "got I-frame" state
+     beyond this point */
+  if (sps_pi)
+    sps_pi->state &= ~GST_H264_VIDEO_STATE_GOT_I_FRAME;
+
+  dpb_flush (decoder, NULL);
+
+  /* Reset defaults, should there be a new sequence available next */
+  priv->max_views = 1;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+/* 8.2.1.1 - Decoding process for picture order count type 0 */
+static void
+init_picture_poc_0 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstH264SPS *const sps = get_sps (decoder);
+  const gint32 MaxPicOrderCntLsb =
+      1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
+  gint32 temp_poc;
+
+  GST_DEBUG ("decode picture order count type 0");
+
+  if (GST_VAAPI_PICTURE_IS_IDR (picture)) {
+    priv->prev_poc_msb = 0;
+    priv->prev_poc_lsb = 0;
+  } else if (priv->prev_pic_has_mmco5) {
+    priv->prev_poc_msb = 0;
+    priv->prev_poc_lsb =
+        (priv->prev_pic_structure == GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD ?
+        0 : priv->field_poc[TOP_FIELD]);
+  } else {
+    priv->prev_poc_msb = priv->poc_msb;
+    priv->prev_poc_lsb = priv->poc_lsb;
+  }
+
+  // (8-3)
+  priv->poc_lsb = slice_hdr->pic_order_cnt_lsb;
+  if (priv->poc_lsb < priv->prev_poc_lsb &&
+      (priv->prev_poc_lsb - priv->poc_lsb) >= (MaxPicOrderCntLsb / 2))
+    priv->poc_msb = priv->prev_poc_msb + MaxPicOrderCntLsb;
+  else if (priv->poc_lsb > priv->prev_poc_lsb &&
+      (priv->poc_lsb - priv->prev_poc_lsb) > (MaxPicOrderCntLsb / 2))
+    priv->poc_msb = priv->prev_poc_msb - MaxPicOrderCntLsb;
+  else
+    priv->poc_msb = priv->prev_poc_msb;
+
+  temp_poc = priv->poc_msb + priv->poc_lsb;
+  switch (picture->structure) {
+    case GST_VAAPI_PICTURE_STRUCTURE_FRAME:
+      // (8-4, 8-5)
+      priv->field_poc[TOP_FIELD] = temp_poc;
+      priv->field_poc[BOTTOM_FIELD] = temp_poc +
+          slice_hdr->delta_pic_order_cnt_bottom;
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
+      // (8-4)
+      priv->field_poc[TOP_FIELD] = temp_poc;
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
+      // (8-5)
+      priv->field_poc[BOTTOM_FIELD] = temp_poc;
+      break;
+  }
+}
+
+/* 8.2.1.2 - Decoding process for picture order count type 1 */
+static void
+init_picture_poc_1 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstH264SPS *const sps = get_sps (decoder);
+  const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4);
+  gint32 prev_frame_num_offset, abs_frame_num, expected_poc;
+  guint i;
+
+  GST_DEBUG ("decode picture order count type 1");
+
+  if (priv->prev_pic_has_mmco5)
+    prev_frame_num_offset = 0;
+  else
+    prev_frame_num_offset = priv->frame_num_offset;
+
+  // (8-6)
+  if (GST_VAAPI_PICTURE_IS_IDR (picture))
+    priv->frame_num_offset = 0;
+  else if (priv->prev_frame_num > priv->frame_num)
+    priv->frame_num_offset = prev_frame_num_offset + MaxFrameNum;
+  else
+    priv->frame_num_offset = prev_frame_num_offset;
+
+  // (8-7)
+  if (sps->num_ref_frames_in_pic_order_cnt_cycle != 0)
+    abs_frame_num = priv->frame_num_offset + priv->frame_num;
+  else
+    abs_frame_num = 0;
+  if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture) && abs_frame_num > 0)
+    abs_frame_num = abs_frame_num - 1;
+
+  if (abs_frame_num > 0) {
+    gint32 expected_delta_per_poc_cycle;
+    gint32 poc_cycle_cnt, frame_num_in_poc_cycle;
+
+    expected_delta_per_poc_cycle = 0;
+    for (i = 0; i < sps->num_ref_frames_in_pic_order_cnt_cycle; i++)
+      expected_delta_per_poc_cycle += sps->offset_for_ref_frame[i];
+
+    // (8-8)
+    poc_cycle_cnt = (abs_frame_num - 1) /
+        sps->num_ref_frames_in_pic_order_cnt_cycle;
+    frame_num_in_poc_cycle = (abs_frame_num - 1) %
+        sps->num_ref_frames_in_pic_order_cnt_cycle;
+
+    // (8-9)
+    expected_poc = poc_cycle_cnt * expected_delta_per_poc_cycle;
+    for (i = 0; i <= frame_num_in_poc_cycle; i++)
+      expected_poc += sps->offset_for_ref_frame[i];
+  } else
+    expected_poc = 0;
+  if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture))
+    expected_poc += sps->offset_for_non_ref_pic;
+
+  // (8-10)
+  switch (picture->structure) {
+    case GST_VAAPI_PICTURE_STRUCTURE_FRAME:
+      priv->field_poc[TOP_FIELD] = expected_poc +
+          slice_hdr->delta_pic_order_cnt[0];
+      priv->field_poc[BOTTOM_FIELD] = priv->field_poc[TOP_FIELD] +
+          sps->offset_for_top_to_bottom_field +
+          slice_hdr->delta_pic_order_cnt[1];
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
+      priv->field_poc[TOP_FIELD] = expected_poc +
+          slice_hdr->delta_pic_order_cnt[0];
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
+      priv->field_poc[BOTTOM_FIELD] = expected_poc +
+          sps->offset_for_top_to_bottom_field +
+          slice_hdr->delta_pic_order_cnt[0];
+      break;
+  }
+}
+
+/* 8.2.1.3 - Decoding process for picture order count type 2 */
+static void
+init_picture_poc_2 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstH264SPS *const sps = get_sps (decoder);
+  const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4);
+  gint32 prev_frame_num_offset, temp_poc;
+
+  GST_DEBUG ("decode picture order count type 2");
+
+  if (priv->prev_pic_has_mmco5)
+    prev_frame_num_offset = 0;
+  else
+    prev_frame_num_offset = priv->frame_num_offset;
+
+  // (8-11)
+  if (GST_VAAPI_PICTURE_IS_IDR (picture))
+    priv->frame_num_offset = 0;
+  else if (priv->prev_frame_num > priv->frame_num)
+    priv->frame_num_offset = prev_frame_num_offset + MaxFrameNum;
+  else
+    priv->frame_num_offset = prev_frame_num_offset;
+
+  // (8-12)
+  if (GST_VAAPI_PICTURE_IS_IDR (picture))
+    temp_poc = 0;
+  else if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture))
+    temp_poc = 2 * (priv->frame_num_offset + priv->frame_num) - 1;
+  else
+    temp_poc = 2 * (priv->frame_num_offset + priv->frame_num);
+
+  // (8-13)
+  if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD)
+    priv->field_poc[TOP_FIELD] = temp_poc;
+  if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD)
+    priv->field_poc[BOTTOM_FIELD] = temp_poc;
+}
+
+/* 8.2.1 - Decoding process for picture order count */
+static void
+init_picture_poc (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstH264SPS *const sps = get_sps (decoder);
+
+  switch (sps->pic_order_cnt_type) {
+    case 0:
+      init_picture_poc_0 (decoder, picture, slice_hdr);
+      break;
+    case 1:
+      init_picture_poc_1 (decoder, picture, slice_hdr);
+      break;
+    case 2:
+      init_picture_poc_2 (decoder, picture, slice_hdr);
+      break;
+  }
+
+  if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD)
+    picture->field_poc[TOP_FIELD] = priv->field_poc[TOP_FIELD];
+  if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD)
+    picture->field_poc[BOTTOM_FIELD] = priv->field_poc[BOTTOM_FIELD];
+  picture->base.poc = MIN (picture->field_poc[0], picture->field_poc[1]);
+}
+
+static int
+compare_picture_pic_num_dec (const void *a, const void *b)
+{
+  const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a;
+  const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b;
+
+  return picB->pic_num - picA->pic_num;
+}
+
+static int
+compare_picture_long_term_pic_num_inc (const void *a, const void *b)
+{
+  const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a;
+  const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b;
+
+  return picA->long_term_pic_num - picB->long_term_pic_num;
+}
+
+static int
+compare_picture_poc_dec (const void *a, const void *b)
+{
+  const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a;
+  const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b;
+
+  return picB->base.poc - picA->base.poc;
+}
+
+static int
+compare_picture_poc_inc (const void *a, const void *b)
+{
+  const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a;
+  const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b;
+
+  return picA->base.poc - picB->base.poc;
+}
+
+static int
+compare_picture_frame_num_wrap_dec (const void *a, const void *b)
+{
+  const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a;
+  const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b;
+
+  return picB->frame_num_wrap - picA->frame_num_wrap;
+}
+
+static int
+compare_picture_long_term_frame_idx_inc (const void *a, const void *b)
+{
+  const GstVaapiPictureH264 *const picA = *(GstVaapiPictureH264 **) a;
+  const GstVaapiPictureH264 *const picB = *(GstVaapiPictureH264 **) b;
+
+  return picA->long_term_frame_idx - picB->long_term_frame_idx;
+}
+
+/* 8.2.4.1 - Decoding process for picture numbers */
+static void
+init_picture_refs_pic_num (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstH264SPS *const sps = get_sps (decoder);
+  const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4);
+  guint i;
+
+  GST_DEBUG ("decode picture numbers");
+
+  for (i = 0; i < priv->short_ref_count; i++) {
+    GstVaapiPictureH264 *const pic = priv->short_ref[i];
+
+    // (H.8.2)
+    if (pic->base.view_id != picture->base.view_id)
+      continue;
+
+    // (8-27)
+    if (pic->frame_num > priv->frame_num)
+      pic->frame_num_wrap = pic->frame_num - MaxFrameNum;
+    else
+      pic->frame_num_wrap = pic->frame_num;
+
+    // (8-28, 8-30, 8-31)
+    if (GST_VAAPI_PICTURE_IS_FRAME (picture))
+      pic->pic_num = pic->frame_num_wrap;
+    else {
+      if (pic->structure == picture->structure)
+        pic->pic_num = 2 * pic->frame_num_wrap + 1;
+      else
+        pic->pic_num = 2 * pic->frame_num_wrap;
+    }
+  }
+
+  for (i = 0; i < priv->long_ref_count; i++) {
+    GstVaapiPictureH264 *const pic = priv->long_ref[i];
+
+    // (H.8.2)
+    if (pic->base.view_id != picture->base.view_id)
+      continue;
+
+    // (8-29, 8-32, 8-33)
+    if (GST_VAAPI_PICTURE_IS_FRAME (picture))
+      pic->long_term_pic_num = pic->long_term_frame_idx;
+    else {
+      if (pic->structure == picture->structure)
+        pic->long_term_pic_num = 2 * pic->long_term_frame_idx + 1;
+      else
+        pic->long_term_pic_num = 2 * pic->long_term_frame_idx;
+    }
+  }
+}
+
+#define SORT_REF_LIST(list, n, compare_func) \
+    qsort(list, n, sizeof(*(list)), compare_picture_##compare_func)
+
+static void
+init_picture_refs_fields_1 (guint picture_structure,
+    GstVaapiPictureH264 * RefPicList[32],
+    guint * RefPicList_count,
+    GstVaapiPictureH264 * ref_list[32], guint ref_list_count)
+{
+  guint i, j, n;
+
+  i = 0;
+  j = 0;
+  n = *RefPicList_count;
+  do {
+    g_assert (n < 32);
+    for (; i < ref_list_count; i++) {
+      if (ref_list[i]->structure == picture_structure) {
+        RefPicList[n++] = ref_list[i++];
+        break;
+      }
+    }
+    for (; j < ref_list_count; j++) {
+      if (ref_list[j]->structure != picture_structure) {
+        RefPicList[n++] = ref_list[j++];
+        break;
+      }
+    }
+  } while (i < ref_list_count || j < ref_list_count);
+  *RefPicList_count = n;
+}
+
+static inline void
+init_picture_refs_fields (GstVaapiPictureH264 * picture,
+    GstVaapiPictureH264 * RefPicList[32],
+    guint * RefPicList_count,
+    GstVaapiPictureH264 * short_ref[32],
+    guint short_ref_count,
+    GstVaapiPictureH264 * long_ref[32], guint long_ref_count)
+{
+  guint n = 0;
+
+  /* 8.2.4.2.5 - reference picture lists in fields */
+  init_picture_refs_fields_1 (picture->structure, RefPicList, &n,
+      short_ref, short_ref_count);
+  init_picture_refs_fields_1 (picture->structure, RefPicList, &n,
+      long_ref, long_ref_count);
+  *RefPicList_count = n;
+}
+
+/* Finds the inter-view reference picture with the supplied view id */
+static GstVaapiPictureH264 *
+find_inter_view_reference (GstVaapiDecoderH264 * decoder, guint16 view_id)
+{
+  GPtrArray *const inter_views = decoder->priv.inter_views;
+  guint i;
+
+  for (i = 0; i < inter_views->len; i++) {
+    GstVaapiPictureH264 *const picture = g_ptr_array_index (inter_views, i);
+    if (picture->base.view_id == view_id)
+      return picture;
+  }
+
+  GST_WARNING ("failed to find inter-view reference picture for view_id: %d",
+      view_id);
+  return NULL;
+}
+
+/* Checks whether the view id exists in the supplied list of view ids */
+static gboolean
+find_view_id (guint16 view_id, const guint16 * view_ids, guint num_view_ids)
+{
+  guint i;
+
+  for (i = 0; i < num_view_ids; i++) {
+    if (view_ids[i] == view_id)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean
+find_view_id_in_view (guint16 view_id, const GstH264SPSExtMVCView * view,
+    gboolean is_anchor)
+{
+  if (is_anchor)
+    return (find_view_id (view_id, view->anchor_ref_l0,
+            view->num_anchor_refs_l0) ||
+        find_view_id (view_id, view->anchor_ref_l1, view->num_anchor_refs_l1));
+
+  return (find_view_id (view_id, view->non_anchor_ref_l0,
+          view->num_non_anchor_refs_l0) ||
+      find_view_id (view_id, view->non_anchor_ref_l1,
+          view->num_non_anchor_refs_l1));
+}
+
+/* Checks whether the inter-view reference picture with the supplied
+   view id is used for decoding the current view component picture */
+static gboolean
+is_inter_view_reference_for_picture (GstVaapiDecoderH264 * decoder,
+    guint16 view_id, GstVaapiPictureH264 * picture)
+{
+  const GstH264SPS *const sps = get_sps (decoder);
+  gboolean is_anchor;
+
+  if (!GST_VAAPI_PICTURE_IS_MVC (picture) ||
+      sps->extension_type != GST_H264_NAL_EXTENSION_MVC)
+    return FALSE;
+
+  is_anchor = GST_VAAPI_PICTURE_IS_ANCHOR (picture);
+  return find_view_id_in_view (view_id,
+      &sps->extension.mvc.view[picture->base.voc], is_anchor);
+}
+
+/* Checks whether the supplied inter-view reference picture is used
+   for decoding the next view component pictures */
+static gboolean
+is_inter_view_reference_for_next_pictures (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture)
+{
+  const GstH264SPS *const sps = get_sps (decoder);
+  gboolean is_anchor;
+  guint i, num_views;
+
+  if (!GST_VAAPI_PICTURE_IS_MVC (picture) ||
+      sps->extension_type != GST_H264_NAL_EXTENSION_MVC)
+    return FALSE;
+
+  is_anchor = GST_VAAPI_PICTURE_IS_ANCHOR (picture);
+  num_views = sps->extension.mvc.num_views_minus1 + 1;
+  for (i = picture->base.voc + 1; i < num_views; i++) {
+    const GstH264SPSExtMVCView *const view = &sps->extension.mvc.view[i];
+    if (find_view_id_in_view (picture->base.view_id, view, is_anchor))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+/* H.8.2.1 - Initialization process for inter-view prediction references */
+static gboolean
+init_picture_refs_mvc_1 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 ** ref_list, guint * ref_list_count_ptr, guint num_refs,
+    const guint16 * view_ids, guint num_view_ids)
+{
+  guint j, n;
+
+  n = *ref_list_count_ptr;
+  for (j = 0; j < num_view_ids && n < num_refs; j++) {
+    GstVaapiPictureH264 *pic;
+
+    if (!(pic = find_inter_view_reference (decoder, view_ids[j])))
+      return FALSE;
+
+    ref_list[n++] = pic;
+  }
+
+  *ref_list_count_ptr = n;
+
+  return TRUE;
+}
+
+static inline gboolean
+init_picture_refs_mvc (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr, guint list)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  const GstH264SPS *const sps = get_sps (decoder);
+  const GstH264SPSExtMVCView *view;
+  gboolean ret = TRUE;
+
+  GST_DEBUG ("initialize reference picture list for inter-view prediction");
+
+  if (sps->extension_type != GST_H264_NAL_EXTENSION_MVC)
+    return TRUE;
+  view = &sps->extension.mvc.view[picture->base.voc];
+
+#define INVOKE_INIT_PICTURE_REFS_MVC(ref_list, view_list) do {          \
+        ret = init_picture_refs_mvc_1(decoder,                          \
+            priv->RefPicList##ref_list,                                 \
+            &priv->RefPicList##ref_list##_count,                        \
+            slice_hdr->num_ref_idx_l##ref_list##_active_minus1 + 1,     \
+            view->view_list##_l##ref_list,                              \
+            view->num_##view_list##s_l##ref_list);                      \
+    } while (0)
+
+  if (list == 0) {
+    if (GST_VAAPI_PICTURE_IS_ANCHOR (picture))
+      INVOKE_INIT_PICTURE_REFS_MVC (0, anchor_ref);
+    else
+      INVOKE_INIT_PICTURE_REFS_MVC (0, non_anchor_ref);
+  } else {
+    if (GST_VAAPI_PICTURE_IS_ANCHOR (picture))
+      INVOKE_INIT_PICTURE_REFS_MVC (1, anchor_ref);
+    else
+      INVOKE_INIT_PICTURE_REFS_MVC (1, non_anchor_ref);
+  }
+
+  return ret;
+
+#undef INVOKE_INIT_PICTURE_REFS_MVC
+}
+
+static gboolean
+init_picture_refs_p_slice (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 **ref_list;
+  guint i;
+  gboolean ret = TRUE;
+
+  GST_DEBUG ("decode reference picture list for P and SP slices");
+
+  if (GST_VAAPI_PICTURE_IS_FRAME (picture)) {
+    /* 8.2.4.2.1 - P and SP slices in frames */
+    if (priv->short_ref_count > 0) {
+      ref_list = priv->RefPicList0;
+      for (i = 0; i < priv->short_ref_count; i++)
+        ref_list[i] = priv->short_ref[i];
+      SORT_REF_LIST (ref_list, i, pic_num_dec);
+      priv->RefPicList0_count += i;
+    }
+
+    if (priv->long_ref_count > 0) {
+      ref_list = &priv->RefPicList0[priv->RefPicList0_count];
+      for (i = 0; i < priv->long_ref_count; i++)
+        ref_list[i] = priv->long_ref[i];
+      SORT_REF_LIST (ref_list, i, long_term_pic_num_inc);
+      priv->RefPicList0_count += i;
+    }
+  } else {
+    /* 8.2.4.2.2 - P and SP slices in fields */
+    GstVaapiPictureH264 *short_ref[32];
+    guint short_ref_count = 0;
+    GstVaapiPictureH264 *long_ref[32];
+    guint long_ref_count = 0;
+
+    if (priv->short_ref_count > 0) {
+      for (i = 0; i < priv->short_ref_count; i++)
+        short_ref[i] = priv->short_ref[i];
+      SORT_REF_LIST (short_ref, i, frame_num_wrap_dec);
+      short_ref_count = i;
+    }
+
+    if (priv->long_ref_count > 0) {
+      for (i = 0; i < priv->long_ref_count; i++)
+        long_ref[i] = priv->long_ref[i];
+      SORT_REF_LIST (long_ref, i, long_term_frame_idx_inc);
+      long_ref_count = i;
+    }
+
+    init_picture_refs_fields (picture,
+        priv->RefPicList0, &priv->RefPicList0_count,
+        short_ref, short_ref_count, long_ref, long_ref_count);
+  }
+
+  if (GST_VAAPI_PICTURE_IS_MVC (picture)) {
+    /* RefPicList0 */
+    ret = init_picture_refs_mvc (decoder, picture, slice_hdr, 0);
+  }
+
+  return ret;
+}
+
+static gboolean
+init_picture_refs_b_slice (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 **ref_list;
+  guint i, n;
+  gboolean ret = TRUE;
+
+  GST_DEBUG ("decode reference picture list for B slices");
+
+  if (GST_VAAPI_PICTURE_IS_FRAME (picture)) {
+    /* 8.2.4.2.3 - B slices in frames */
+
+    /* RefPicList0 */
+    if (priv->short_ref_count > 0) {
+      // 1. Short-term references
+      ref_list = priv->RefPicList0;
+      for (n = 0, i = 0; i < priv->short_ref_count; i++) {
+        if (priv->short_ref[i]->base.poc < picture->base.poc)
+          ref_list[n++] = priv->short_ref[i];
+      }
+      SORT_REF_LIST (ref_list, n, poc_dec);
+      priv->RefPicList0_count += n;
+
+      ref_list = &priv->RefPicList0[priv->RefPicList0_count];
+      for (n = 0, i = 0; i < priv->short_ref_count; i++) {
+        if (priv->short_ref[i]->base.poc >= picture->base.poc)
+          ref_list[n++] = priv->short_ref[i];
+      }
+      SORT_REF_LIST (ref_list, n, poc_inc);
+      priv->RefPicList0_count += n;
+    }
+
+    if (priv->long_ref_count > 0) {
+      // 2. Long-term references
+      ref_list = &priv->RefPicList0[priv->RefPicList0_count];
+      for (n = 0, i = 0; i < priv->long_ref_count; i++)
+        ref_list[n++] = priv->long_ref[i];
+      SORT_REF_LIST (ref_list, n, long_term_pic_num_inc);
+      priv->RefPicList0_count += n;
+    }
+
+    /* RefPicList1 */
+    if (priv->short_ref_count > 0) {
+      // 1. Short-term references
+      ref_list = priv->RefPicList1;
+      for (n = 0, i = 0; i < priv->short_ref_count; i++) {
+        if (priv->short_ref[i]->base.poc > picture->base.poc)
+          ref_list[n++] = priv->short_ref[i];
+      }
+      SORT_REF_LIST (ref_list, n, poc_inc);
+      priv->RefPicList1_count += n;
+
+      ref_list = &priv->RefPicList1[priv->RefPicList1_count];
+      for (n = 0, i = 0; i < priv->short_ref_count; i++) {
+        if (priv->short_ref[i]->base.poc <= picture->base.poc)
+          ref_list[n++] = priv->short_ref[i];
+      }
+      SORT_REF_LIST (ref_list, n, poc_dec);
+      priv->RefPicList1_count += n;
+    }
+
+    if (priv->long_ref_count > 0) {
+      // 2. Long-term references
+      ref_list = &priv->RefPicList1[priv->RefPicList1_count];
+      for (n = 0, i = 0; i < priv->long_ref_count; i++)
+        ref_list[n++] = priv->long_ref[i];
+      SORT_REF_LIST (ref_list, n, long_term_pic_num_inc);
+      priv->RefPicList1_count += n;
+    }
+  } else {
+    /* 8.2.4.2.4 - B slices in fields */
+    GstVaapiPictureH264 *short_ref0[32];
+    guint short_ref0_count = 0;
+    GstVaapiPictureH264 *short_ref1[32];
+    guint short_ref1_count = 0;
+    GstVaapiPictureH264 *long_ref[32];
+    guint long_ref_count = 0;
+
+    /* refFrameList0ShortTerm */
+    if (priv->short_ref_count > 0) {
+      ref_list = short_ref0;
+      for (n = 0, i = 0; i < priv->short_ref_count; i++) {
+        if (priv->short_ref[i]->base.poc <= picture->base.poc)
+          ref_list[n++] = priv->short_ref[i];
+      }
+      SORT_REF_LIST (ref_list, n, poc_dec);
+      short_ref0_count += n;
+
+      ref_list = &short_ref0[short_ref0_count];
+      for (n = 0, i = 0; i < priv->short_ref_count; i++) {
+        if (priv->short_ref[i]->base.poc > picture->base.poc)
+          ref_list[n++] = priv->short_ref[i];
+      }
+      SORT_REF_LIST (ref_list, n, poc_inc);
+      short_ref0_count += n;
+    }
+
+    /* refFrameList1ShortTerm */
+    if (priv->short_ref_count > 0) {
+      ref_list = short_ref1;
+      for (n = 0, i = 0; i < priv->short_ref_count; i++) {
+        if (priv->short_ref[i]->base.poc > picture->base.poc)
+          ref_list[n++] = priv->short_ref[i];
+      }
+      SORT_REF_LIST (ref_list, n, poc_inc);
+      short_ref1_count += n;
+
+      ref_list = &short_ref1[short_ref1_count];
+      for (n = 0, i = 0; i < priv->short_ref_count; i++) {
+        if (priv->short_ref[i]->base.poc <= picture->base.poc)
+          ref_list[n++] = priv->short_ref[i];
+      }
+      SORT_REF_LIST (ref_list, n, poc_dec);
+      short_ref1_count += n;
+    }
+
+    /* refFrameListLongTerm */
+    if (priv->long_ref_count > 0) {
+      for (i = 0; i < priv->long_ref_count; i++)
+        long_ref[i] = priv->long_ref[i];
+      SORT_REF_LIST (long_ref, i, long_term_frame_idx_inc);
+      long_ref_count = i;
+    }
+
+    init_picture_refs_fields (picture,
+        priv->RefPicList0, &priv->RefPicList0_count,
+        short_ref0, short_ref0_count, long_ref, long_ref_count);
+
+    init_picture_refs_fields (picture,
+        priv->RefPicList1, &priv->RefPicList1_count,
+        short_ref1, short_ref1_count, long_ref, long_ref_count);
+  }
+
+  /* Check whether RefPicList1 is identical to RefPicList0, then
+     swap if necessary */
+  if (priv->RefPicList1_count > 1 &&
+      priv->RefPicList1_count == priv->RefPicList0_count &&
+      memcmp (priv->RefPicList0, priv->RefPicList1,
+          priv->RefPicList0_count * sizeof (priv->RefPicList0[0])) == 0) {
+    GstVaapiPictureH264 *const tmp = priv->RefPicList1[0];
+    priv->RefPicList1[0] = priv->RefPicList1[1];
+    priv->RefPicList1[1] = tmp;
+  }
+
+  if (GST_VAAPI_PICTURE_IS_MVC (picture)) {
+    /* RefPicList0 */
+    ret = init_picture_refs_mvc (decoder, picture, slice_hdr, 0);
+
+    /* RefPicList1 */
+    ret = init_picture_refs_mvc (decoder, picture, slice_hdr, 1);
+  }
+
+  return ret;
+}
+
+#undef SORT_REF_LIST
+
+static gint
+find_short_term_reference (GstVaapiDecoderH264 * decoder, gint32 pic_num)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  guint i;
+
+  for (i = 0; i < priv->short_ref_count; i++) {
+    if (priv->short_ref[i]->pic_num == pic_num)
+      return i;
+  }
+  GST_ERROR ("found no short-term reference picture with PicNum = %d", pic_num);
+  return -1;
+}
+
+static gint
+find_long_term_reference (GstVaapiDecoderH264 * decoder,
+    gint32 long_term_pic_num)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  guint i;
+
+  for (i = 0; i < priv->long_ref_count; i++) {
+    if (priv->long_ref[i]->long_term_pic_num == long_term_pic_num)
+      return i;
+  }
+  GST_ERROR ("found no long-term reference picture with LongTermPicNum = %d",
+      long_term_pic_num);
+  return -1;
+}
+
+static gboolean
+exec_picture_refs_modification_1 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr, guint list)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstH264SPS *const sps = get_sps (decoder);
+  GstH264RefPicListModification *ref_pic_list_modification;
+  guint num_ref_pic_list_modifications;
+  GstVaapiPictureH264 **ref_list;
+  guint *ref_list_count_ptr, ref_list_idx = 0;
+  const guint16 *view_ids = NULL;
+  guint i, j, n, num_refs, num_view_ids = 0;
+  gint found_ref_idx;
+  gint32 MaxPicNum, CurrPicNum, picNumPred, picViewIdxPred;
+  gboolean ret = TRUE;
+
+  GST_DEBUG ("modification process of reference picture list %u", list);
+
+  if (list == 0) {
+    ref_pic_list_modification = slice_hdr->ref_pic_list_modification_l0;
+    num_ref_pic_list_modifications = slice_hdr->n_ref_pic_list_modification_l0;
+    ref_list = priv->RefPicList0;
+    ref_list_count_ptr = &priv->RefPicList0_count;
+    num_refs = slice_hdr->num_ref_idx_l0_active_minus1 + 1;
+
+    if (GST_VAAPI_PICTURE_IS_MVC (picture) &&
+        sps->extension_type == GST_H264_NAL_EXTENSION_MVC) {
+      const GstH264SPSExtMVCView *const view =
+          &sps->extension.mvc.view[picture->base.voc];
+      if (GST_VAAPI_PICTURE_IS_ANCHOR (picture)) {
+        view_ids = view->anchor_ref_l0;
+        num_view_ids = view->num_anchor_refs_l0;
+      } else {
+        view_ids = view->non_anchor_ref_l0;
+        num_view_ids = view->num_non_anchor_refs_l0;
+      }
+    }
+  } else {
+    ref_pic_list_modification = slice_hdr->ref_pic_list_modification_l1;
+    num_ref_pic_list_modifications = slice_hdr->n_ref_pic_list_modification_l1;
+    ref_list = priv->RefPicList1;
+    ref_list_count_ptr = &priv->RefPicList1_count;
+    num_refs = slice_hdr->num_ref_idx_l1_active_minus1 + 1;
+
+    if (GST_VAAPI_PICTURE_IS_MVC (picture) &&
+        sps->extension_type == GST_H264_NAL_EXTENSION_MVC) {
+      const GstH264SPSExtMVCView *const view =
+          &sps->extension.mvc.view[picture->base.voc];
+      if (GST_VAAPI_PICTURE_IS_ANCHOR (picture)) {
+        view_ids = view->anchor_ref_l1;
+        num_view_ids = view->num_anchor_refs_l1;
+      } else {
+        view_ids = view->non_anchor_ref_l1;
+        num_view_ids = view->num_non_anchor_refs_l1;
+      }
+    }
+  }
+
+  if (!GST_VAAPI_PICTURE_IS_FRAME (picture)) {
+    MaxPicNum = 1 << (sps->log2_max_frame_num_minus4 + 5);      // 2 * MaxFrameNum
+    CurrPicNum = 2 * slice_hdr->frame_num + 1;  // 2 * frame_num + 1
+  } else {
+    MaxPicNum = 1 << (sps->log2_max_frame_num_minus4 + 4);      // MaxFrameNum
+    CurrPicNum = slice_hdr->frame_num;  // frame_num
+  }
+
+  picNumPred = CurrPicNum;
+  picViewIdxPred = -1;
+
+  for (i = 0; i < num_ref_pic_list_modifications; i++) {
+    GstH264RefPicListModification *const l = &ref_pic_list_modification[i];
+    if (l->modification_of_pic_nums_idc == 3)
+      break;
+
+    /* 8.2.4.3.1 - Short-term reference pictures */
+    if (l->modification_of_pic_nums_idc == 0
+        || l->modification_of_pic_nums_idc == 1) {
+      gint32 abs_diff_pic_num = l->value.abs_diff_pic_num_minus1 + 1;
+      gint32 picNum, picNumNoWrap;
+
+      // (8-34)
+      if (l->modification_of_pic_nums_idc == 0) {
+        picNumNoWrap = picNumPred - abs_diff_pic_num;
+        if (picNumNoWrap < 0)
+          picNumNoWrap += MaxPicNum;
+      }
+      // (8-35)
+      else {
+        picNumNoWrap = picNumPred + abs_diff_pic_num;
+        if (picNumNoWrap >= MaxPicNum)
+          picNumNoWrap -= MaxPicNum;
+      }
+      picNumPred = picNumNoWrap;
+
+      // (8-36)
+      picNum = picNumNoWrap;
+      if (picNum > CurrPicNum)
+        picNum -= MaxPicNum;
+
+      // (8-37)
+      for (j = num_refs; j > ref_list_idx; j--)
+        ref_list[j] = ref_list[j - 1];
+      found_ref_idx = find_short_term_reference (decoder, picNum);
+      ref_list[ref_list_idx++] =
+          found_ref_idx >= 0 ? priv->short_ref[found_ref_idx] : NULL;
+      n = ref_list_idx;
+      for (j = ref_list_idx; j <= num_refs; j++) {
+        gint32 PicNumF;
+        if (!ref_list[j])
+          continue;
+        PicNumF =
+            GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (ref_list[j]) ?
+            ref_list[j]->pic_num : MaxPicNum;
+        if (PicNumF != picNum ||
+            ref_list[j]->base.view_id != picture->base.view_id)
+          ref_list[n++] = ref_list[j];
+      }
+    }
+
+    /* 8.2.4.3.2 - Long-term reference pictures */
+    else if (l->modification_of_pic_nums_idc == 2) {
+
+      for (j = num_refs; j > ref_list_idx; j--)
+        ref_list[j] = ref_list[j - 1];
+      found_ref_idx =
+          find_long_term_reference (decoder, l->value.long_term_pic_num);
+      ref_list[ref_list_idx++] =
+          found_ref_idx >= 0 ? priv->long_ref[found_ref_idx] : NULL;
+      n = ref_list_idx;
+      for (j = ref_list_idx; j <= num_refs; j++) {
+        gint32 LongTermPicNumF;
+        if (!ref_list[j])
+          continue;
+        LongTermPicNumF =
+            GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (ref_list[j]) ?
+            ref_list[j]->long_term_pic_num : INT_MAX;
+        if (LongTermPicNumF != l->value.long_term_pic_num ||
+            ref_list[j]->base.view_id != picture->base.view_id)
+          ref_list[n++] = ref_list[j];
+      }
+    }
+
+    /* H.8.2.2.3 - Inter-view prediction reference pictures */
+    else if ((GST_VAAPI_PICTURE_IS_MVC (picture) &&
+            sps->extension_type == GST_H264_NAL_EXTENSION_MVC) &&
+        (l->modification_of_pic_nums_idc == 4 ||
+            l->modification_of_pic_nums_idc == 5)) {
+      gint32 abs_diff_view_idx = l->value.abs_diff_view_idx_minus1 + 1;
+      gint32 picViewIdx, targetViewId;
+
+      // (H-6)
+      if (l->modification_of_pic_nums_idc == 4) {
+        picViewIdx = picViewIdxPred - abs_diff_view_idx;
+        if (picViewIdx < 0)
+          picViewIdx += num_view_ids;
+      }
+      // (H-7)
+      else {
+        picViewIdx = picViewIdxPred + abs_diff_view_idx;
+        if (picViewIdx >= num_view_ids)
+          picViewIdx -= num_view_ids;
+      }
+      picViewIdxPred = picViewIdx;
+
+      // (H-8, H-9)
+      targetViewId = view_ids[picViewIdx];
+
+      // (H-10)
+      for (j = num_refs; j > ref_list_idx; j--)
+        ref_list[j] = ref_list[j - 1];
+      ref_list[ref_list_idx++] =
+          find_inter_view_reference (decoder, targetViewId);
+      n = ref_list_idx;
+      for (j = ref_list_idx; j <= num_refs; j++) {
+        if (!ref_list[j])
+          continue;
+        if (ref_list[j]->base.view_id != targetViewId ||
+            ref_list[j]->base.poc != picture->base.poc)
+          ref_list[n++] = ref_list[j];
+      }
+    }
+  }
+
+  for (i = 0; i < num_refs; i++) {
+    if (!ref_list[i]) {
+      ret = FALSE;
+      GST_ERROR ("list %u entry %u is empty", list, i);
+    }
+  }
+
+  *ref_list_count_ptr = num_refs;
+
+  return ret;
+}
+
+/* 8.2.4.3 - Modification process for reference picture lists */
+static gboolean
+exec_picture_refs_modification (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr)
+{
+  gboolean ret = TRUE;
+
+  GST_DEBUG ("execute ref_pic_list_modification()");
+
+  /* RefPicList0 */
+  if (!GST_H264_IS_I_SLICE (slice_hdr) && !GST_H264_IS_SI_SLICE (slice_hdr) &&
+      slice_hdr->ref_pic_list_modification_flag_l0)
+    ret = exec_picture_refs_modification_1 (decoder, picture, slice_hdr, 0);
+
+  /* RefPicList1 */
+  if (GST_H264_IS_B_SLICE (slice_hdr) &&
+      slice_hdr->ref_pic_list_modification_flag_l1)
+    ret = exec_picture_refs_modification_1 (decoder, picture, slice_hdr, 1);
+
+  return ret;
+}
+
+static gboolean
+check_picture_ref_corruption (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * RefPicList[32], guint RefPicList_count)
+{
+  const guint corrupted_flags =
+      GST_VAAPI_PICTURE_FLAG_CORRUPTED | GST_VAAPI_PICTURE_FLAG_GHOST;
+  guint i;
+
+  for (i = 0; i < RefPicList_count; i++) {
+    GstVaapiPictureH264 *const picture = RefPicList[i];
+    if (picture && (GST_VAAPI_PICTURE_FLAGS (picture) & corrupted_flags))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+static void
+mark_picture_refs (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+
+  if (GST_VAAPI_PICTURE_IS_CORRUPTED (picture))
+    return;
+
+  if (check_picture_ref_corruption (decoder,
+          priv->RefPicList0, priv->RefPicList0_count) ||
+      check_picture_ref_corruption (decoder,
+          priv->RefPicList1, priv->RefPicList1_count))
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_CORRUPTED);
+}
+
+static void
+init_picture_ref_lists (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  guint i, j, short_ref_count, long_ref_count;
+
+  short_ref_count = 0;
+  long_ref_count = 0;
+  if (GST_VAAPI_PICTURE_IS_FRAME (picture)) {
+    for (i = 0; i < priv->dpb_count; i++) {
+      GstVaapiFrameStore *const fs = priv->dpb[i];
+      GstVaapiPictureH264 *pic;
+      if (!gst_vaapi_frame_store_has_frame (fs))
+        continue;
+      pic = fs->buffers[0];
+      if (pic->base.view_id != picture->base.view_id)
+        continue;
+      if (GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (pic))
+        priv->short_ref[short_ref_count++] = pic;
+      else if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (pic))
+        priv->long_ref[long_ref_count++] = pic;
+      pic->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+      pic->other_field = fs->buffers[1];
+    }
+  } else {
+    for (i = 0; i < priv->dpb_count; i++) {
+      GstVaapiFrameStore *const fs = priv->dpb[i];
+      for (j = 0; j < fs->num_buffers; j++) {
+        GstVaapiPictureH264 *const pic = fs->buffers[j];
+        if (pic->base.view_id != picture->base.view_id)
+          continue;
+        if (GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (pic))
+          priv->short_ref[short_ref_count++] = pic;
+        else if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (pic))
+          priv->long_ref[long_ref_count++] = pic;
+        pic->structure = pic->base.structure;
+        pic->other_field = fs->buffers[j ^ 1];
+      }
+    }
+  }
+
+  for (i = short_ref_count; i < priv->short_ref_count; i++)
+    priv->short_ref[i] = NULL;
+  priv->short_ref_count = short_ref_count;
+
+  for (i = long_ref_count; i < priv->long_ref_count; i++)
+    priv->long_ref[i] = NULL;
+  priv->long_ref_count = long_ref_count;
+}
+
+static gboolean
+init_picture_refs (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  guint i, num_refs;
+  gboolean ret = TRUE;
+
+  init_picture_ref_lists (decoder, picture);
+  init_picture_refs_pic_num (decoder, picture, slice_hdr);
+
+  priv->RefPicList0_count = 0;
+  priv->RefPicList1_count = 0;
+
+  switch (slice_hdr->type % 5) {
+    case GST_H264_P_SLICE:
+    case GST_H264_SP_SLICE:
+      ret = init_picture_refs_p_slice (decoder, picture, slice_hdr);
+      break;
+    case GST_H264_B_SLICE:
+      ret = init_picture_refs_b_slice (decoder, picture, slice_hdr);
+      break;
+    default:
+      break;
+  }
+
+  switch (slice_hdr->type % 5) {
+    case GST_H264_B_SLICE:
+      num_refs = 1 + slice_hdr->num_ref_idx_l1_active_minus1;
+      for (i = priv->RefPicList1_count; i < num_refs; i++)
+        priv->RefPicList1[i] = NULL;
+      priv->RefPicList1_count = num_refs;
+
+      // fall-through
+    case GST_H264_P_SLICE:
+    case GST_H264_SP_SLICE:
+      num_refs = 1 + slice_hdr->num_ref_idx_l0_active_minus1;
+      for (i = priv->RefPicList0_count; i < num_refs; i++)
+        priv->RefPicList0[i] = NULL;
+      priv->RefPicList0_count = num_refs;
+      break;
+    default:
+      break;
+  }
+
+  ret = ret && exec_picture_refs_modification (decoder, picture, slice_hdr);
+
+  mark_picture_refs (decoder, picture);
+
+  return ret;
+}
+
+static GstVaapiPictureH264 *
+fill_picture_other_field_gap (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * f0)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 *prev_picture, *f1;
+  gint prev_frame_index;
+  guint picture_structure;
+
+  picture_structure = f0->base.structure;
+  switch (picture_structure) {
+    case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
+      picture_structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
+      picture_structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
+      break;
+    default:
+      g_assert (0 && "unexpected picture structure");
+      return NULL;
+  }
+  GST_VAAPI_PICTURE_FLAG_SET (f0, GST_VAAPI_PICTURE_FLAG_ONEFIELD);
+
+  prev_frame_index = dpb_find_nearest_prev_poc (decoder, f0,
+      picture_structure, &prev_picture);
+  if (prev_frame_index < 0)
+    goto error_find_field;
+
+  f1 = gst_vaapi_picture_h264_new_field (f0);
+  if (!f1)
+    goto error_allocate_field;
+
+  gst_vaapi_surface_proxy_replace (&f1->base.proxy, prev_picture->base.proxy);
+  f1->base.surface = GST_VAAPI_SURFACE_PROXY_SURFACE (f1->base.proxy);
+  f1->base.surface_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (f1->base.proxy);
+  f1->base.poc++;
+  f1->structure = f1->base.structure;
+
+  /* XXX: clone other H.264 picture specific flags */
+  GST_VAAPI_PICTURE_FLAG_SET (f1,
+      (GST_VAAPI_PICTURE_FLAG_SKIPPED | GST_VAAPI_PICTURE_FLAG_GHOST));
+
+  gst_vaapi_picture_h264_set_reference (f1, 0, FALSE);
+  gst_vaapi_picture_replace (&priv->current_picture, f1);
+  gst_vaapi_picture_unref (f1);
+
+  init_picture_ref_lists (decoder, f1);
+  init_picture_refs_pic_num (decoder, f1, NULL);
+  if (!exec_ref_pic_marking_sliding_window (decoder))
+    goto error_exec_ref_pic_marking;
+  if (!dpb_add (decoder, f1))
+    goto error_append_field;
+  return f1;
+
+  /* ERRORS */
+error_find_field:
+  {
+    GST_ERROR ("failed to find field with POC nearest to %d", f0->base.poc);
+    return NULL;
+  }
+error_allocate_field:
+  {
+    GST_ERROR ("failed to allocate missing field for previous frame store");
+    return NULL;
+  }
+error_exec_ref_pic_marking:
+  {
+    GST_ERROR ("failed to execute reference picture marking process");
+    return NULL;
+  }
+error_append_field:
+  {
+    GST_ERROR ("failed to add missing field into previous frame store");
+    return NULL;
+  }
+}
+
+static gboolean
+fill_picture_gaps (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture,
+    GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstH264SPS *const sps = get_sps (decoder);
+  const gint32 MaxFrameNum = 1 << (sps->log2_max_frame_num_minus4 + 4);
+  gint32 prev_frame_num;
+  GstVaapiFrameStore *prev_frame;
+  GstVaapiPicture *base_picture;
+  GstVaapiPictureH264 *lost_picture, *prev_picture;
+  GstH264SliceHdr lost_slice_hdr;
+  gboolean success = FALSE;
+
+  if (priv->prev_ref_frame_num == priv->frame_num)
+    return TRUE;
+  if ((priv->prev_ref_frame_num + 1) % MaxFrameNum == priv->frame_num)
+    return TRUE;
+  if (priv->dpb_count == 0)
+    return TRUE;
+
+  prev_frame = priv->prev_ref_frames[picture->base.voc];
+  g_assert (prev_frame != NULL && prev_frame->buffers[0] != NULL);
+  prev_picture = gst_vaapi_picture_ref (prev_frame->buffers[0]);
+  gst_vaapi_picture_ref (picture);
+
+  lost_slice_hdr = *slice_hdr;
+  lost_slice_hdr.field_pic_flag = 0;
+  if (sps->pic_order_cnt_type == 1) {
+    lost_slice_hdr.delta_pic_order_cnt[0] = 0;
+    lost_slice_hdr.delta_pic_order_cnt[1] = 0;
+  }
+  lost_slice_hdr.dec_ref_pic_marking.adaptive_ref_pic_marking_mode_flag = 0;
+
+  /* XXX: this process is incorrect for MVC */
+  /* Reduce frame num gaps so we don't have to create unnecessary
+   * dummy pictures */
+  prev_frame_num = priv->prev_ref_frame_num;
+  if (prev_frame_num > slice_hdr->frame_num)
+    prev_frame_num -= MaxFrameNum;
+
+  if ((slice_hdr->frame_num - prev_frame_num) - 1 > sps->num_ref_frames) {
+    prev_frame_num = (slice_hdr->frame_num - sps->num_ref_frames) - 1;
+
+    if (prev_frame_num < 0)
+      prev_frame_num += MaxFrameNum;
+  }
+  priv->frame_num = prev_frame_num;
+
+  for (;;) {
+    priv->prev_ref_frame_num = priv->frame_num;
+    priv->frame_num = (priv->prev_ref_frame_num + 1) % MaxFrameNum;
+    if (priv->frame_num == slice_hdr->frame_num)
+      break;
+
+    /* Create new picture */
+    lost_picture = gst_vaapi_picture_h264_new_clone (prev_picture);
+    if (!lost_picture)
+      goto error_allocate_picture;
+
+    base_picture = &lost_picture->base;
+    base_picture->type = GST_VAAPI_PICTURE_TYPE_NONE;
+    base_picture->pts = GST_CLOCK_TIME_NONE;
+    base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+    lost_picture->frame_num = priv->frame_num;
+    lost_picture->frame_num_wrap = priv->frame_num;
+    lost_picture->structure = base_picture->structure;
+
+    GST_VAAPI_PICTURE_FLAG_SET (lost_picture,
+        (GST_VAAPI_PICTURE_FLAG_SKIPPED |
+            GST_VAAPI_PICTURE_FLAG_GHOST |
+            GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE));
+
+    if (sps->pic_order_cnt_type != 0)
+      init_picture_poc (decoder, lost_picture, &lost_slice_hdr);
+    else {
+      base_picture->poc = prev_picture->base.poc + 2;
+      if (prev_picture->field_poc[0] != G_MAXINT32)
+        lost_picture->field_poc[0] = prev_picture->field_poc[0] + 2;
+      if (prev_picture->field_poc[1] != G_MAXINT32)
+        lost_picture->field_poc[1] = prev_picture->field_poc[1] + 2;
+    }
+
+    gst_vaapi_picture_replace (&prev_picture, lost_picture);
+    gst_vaapi_picture_replace (&priv->current_picture, lost_picture);
+    gst_vaapi_picture_unref (lost_picture);
+
+    init_picture_ref_lists (decoder, lost_picture);
+    init_picture_refs_pic_num (decoder, lost_picture, &lost_slice_hdr);
+    if (!exec_ref_pic_marking_sliding_window (decoder))
+      goto error_exec_ref_pic_marking;
+    if (!dpb_add (decoder, lost_picture))
+      goto error_dpb_add;
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  }
+  success = TRUE;
+
+cleanup:
+  priv->frame_num = slice_hdr->frame_num;
+  priv->prev_ref_frame_num = (priv->frame_num + MaxFrameNum - 1) % MaxFrameNum;
+  gst_vaapi_picture_replace (&prev_picture, NULL);
+  gst_vaapi_picture_replace (&priv->current_picture, picture);
+  gst_vaapi_picture_unref (picture);
+  return success;
+
+  /* ERRORS */
+error_allocate_picture:
+  {
+    GST_ERROR ("failed to allocate lost picture");
+    goto cleanup;
+  }
+error_exec_ref_pic_marking:
+  {
+    GST_ERROR ("failed to execute reference picture marking process");
+    goto cleanup;
+  }
+error_dpb_add:
+  {
+    GST_ERROR ("failed to store lost picture into the DPB");
+    goto cleanup;
+  }
+}
+
+static gboolean
+init_picture (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstVaapiParserInfoH264 * pi)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPicture *const base_picture = &picture->base;
+  GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+
+  if (priv->prev_pic_reference)
+    priv->prev_ref_frame_num = priv->frame_num;
+  priv->prev_frame_num = priv->frame_num;
+  priv->frame_num = slice_hdr->frame_num;
+  picture->frame_num = priv->frame_num;
+  picture->frame_num_wrap = priv->frame_num;
+  picture->output_flag = TRUE;  /* XXX: conformant to Annex A only */
+
+  /* If it's a cloned picture, it has some assignments from parent
+   * picture already.  In addition, base decoder doesn't set valid pts
+   * to the frame corresponding to cloned picture.
+   */
+  if (G_LIKELY (!base_picture->parent_picture)) {
+    base_picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
+    base_picture->type = GST_VAAPI_PICTURE_TYPE_NONE;
+    base_picture->view_id = pi->view_id;
+    base_picture->voc = pi->voc;
+  }
+
+  /* Initialize extensions */
+  switch (pi->nalu.extension_type) {
+    case GST_H264_NAL_EXTENSION_MVC:{
+      GstH264NalUnitExtensionMVC *const mvc = &pi->nalu.extension.mvc;
+
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_MVC);
+      if (mvc->inter_view_flag)
+        GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_INTER_VIEW);
+      if (mvc->anchor_pic_flag)
+        GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_ANCHOR);
+      break;
+    }
+  }
+
+  /* Reset decoder state for IDR pictures */
+  if (pi->nalu.idr_pic_flag) {
+    GST_DEBUG ("<IDR>");
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_IDR);
+    dpb_flush (decoder, picture);
+  } else if (!fill_picture_gaps (decoder, picture, slice_hdr))
+    return FALSE;
+
+  /* Initialize picture structure */
+  if (slice_hdr->field_pic_flag) {
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_INTERLACED);
+    priv->pic_structure = slice_hdr->bottom_field_flag ?
+        GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD :
+        GST_H264_SEI_PIC_STRUCT_TOP_FIELD;
+  }
+
+  base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+  switch (priv->pic_structure) {
+    case GST_H264_SEI_PIC_STRUCT_TOP_FIELD:
+      base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
+      if (GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture))
+        priv->top_field_first = TRUE;
+      break;
+    case GST_H264_SEI_PIC_STRUCT_BOTTOM_FIELD:
+      base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
+      break;
+    case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM_TOP:
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_RFF);
+      // fall-through
+    case GST_H264_SEI_PIC_STRUCT_TOP_BOTTOM:
+      if (GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture))
+        priv->top_field_first = TRUE;
+      break;
+    case GST_H264_SEI_PIC_STRUCT_BOTTOM_TOP_BOTTOM:
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_RFF);
+      break;
+    case GST_H264_SEI_PIC_STRUCT_FRAME:
+      if (!priv->progressive_sequence && priv->dpb_count == 0)
+        priv->top_field_first = TRUE;
+      break;
+  }
+  picture->structure = base_picture->structure;
+  if (priv->top_field_first)
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_TFF);
+
+  /* Initialize reference flags */
+  if (pi->nalu.ref_idc) {
+    GstH264DecRefPicMarking *const dec_ref_pic_marking =
+        &slice_hdr->dec_ref_pic_marking;
+
+    if (GST_VAAPI_PICTURE_IS_IDR (picture) &&
+        dec_ref_pic_marking->long_term_reference_flag)
+      GST_VAAPI_PICTURE_FLAG_SET (picture,
+          GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE);
+    else
+      GST_VAAPI_PICTURE_FLAG_SET (picture,
+          GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE);
+  }
+
+  init_picture_poc (decoder, picture, slice_hdr);
+  return TRUE;
+}
+
+/* 8.2.5.3 - Sliding window decoded reference picture marking process */
+static gboolean
+exec_ref_pic_marking_sliding_window (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstH264SPS *const sps = get_sps (decoder);
+  GstVaapiPictureH264 *ref_picture;
+  guint i, m, max_num_ref_frames;
+
+  GST_DEBUG ("reference picture marking process (sliding window)");
+
+  if (!GST_VAAPI_PICTURE_IS_FIRST_FIELD (priv->current_picture))
+    return TRUE;
+
+  max_num_ref_frames = sps->num_ref_frames;
+  if (max_num_ref_frames == 0)
+    max_num_ref_frames = 1;
+  if (!GST_VAAPI_PICTURE_IS_FRAME (priv->current_picture))
+    max_num_ref_frames <<= 1;
+
+  if (priv->short_ref_count + priv->long_ref_count < max_num_ref_frames)
+    return TRUE;
+  if (priv->short_ref_count < 1)
+    return FALSE;
+
+  for (m = 0, i = 1; i < priv->short_ref_count; i++) {
+    GstVaapiPictureH264 *const picture = priv->short_ref[i];
+    if (picture->frame_num_wrap < priv->short_ref[m]->frame_num_wrap)
+      m = i;
+  }
+
+  ref_picture = priv->short_ref[m];
+  gst_vaapi_picture_h264_set_reference (ref_picture, 0, TRUE);
+  ARRAY_REMOVE_INDEX (priv->short_ref, m);
+
+  /* Both fields need to be marked as "unused for reference", so
+     remove the other field from the short_ref[] list as well */
+  if (!GST_VAAPI_PICTURE_IS_FRAME (priv->current_picture)
+      && ref_picture->other_field) {
+    for (i = 0; i < priv->short_ref_count; i++) {
+      if (priv->short_ref[i] == ref_picture->other_field) {
+        ARRAY_REMOVE_INDEX (priv->short_ref, i);
+        break;
+      }
+    }
+  }
+  return TRUE;
+}
+
+static inline gint32
+get_picNumX (GstVaapiPictureH264 * picture,
+    GstH264RefPicMarking * ref_pic_marking)
+{
+  gint32 pic_num;
+
+  if (GST_VAAPI_PICTURE_IS_FRAME (picture))
+    pic_num = picture->frame_num_wrap;
+  else
+    pic_num = 2 * picture->frame_num_wrap + 1;
+  pic_num -= ref_pic_marking->difference_of_pic_nums_minus1 + 1;
+  return pic_num;
+}
+
+/* 8.2.5.4.1. Mark short-term reference picture as "unused for reference" */
+static void
+exec_ref_pic_marking_adaptive_mmco_1 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  gint32 i, picNumX;
+
+  picNumX = get_picNumX (picture, ref_pic_marking);
+  i = find_short_term_reference (decoder, picNumX);
+  if (i < 0)
+    return;
+
+  gst_vaapi_picture_h264_set_reference (priv->short_ref[i], 0,
+      GST_VAAPI_PICTURE_IS_FRAME (picture));
+  ARRAY_REMOVE_INDEX (priv->short_ref, i);
+}
+
+/* 8.2.5.4.2. Mark long-term reference picture as "unused for reference" */
+static void
+exec_ref_pic_marking_adaptive_mmco_2 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  gint32 i;
+
+  i = find_long_term_reference (decoder, ref_pic_marking->long_term_pic_num);
+  if (i < 0)
+    return;
+
+  gst_vaapi_picture_h264_set_reference (priv->long_ref[i], 0,
+      GST_VAAPI_PICTURE_IS_FRAME (picture));
+  ARRAY_REMOVE_INDEX (priv->long_ref, i);
+}
+
+/* 8.2.5.4.3. Assign LongTermFrameIdx to a short-term reference picture */
+static void
+exec_ref_pic_marking_adaptive_mmco_3 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 *ref_picture, *other_field;
+  gint32 i, picNumX;
+
+  for (i = 0; i < priv->long_ref_count; i++) {
+    if (priv->long_ref[i]->long_term_frame_idx ==
+        ref_pic_marking->long_term_frame_idx)
+      break;
+  }
+  if (i != priv->long_ref_count) {
+    gst_vaapi_picture_h264_set_reference (priv->long_ref[i], 0, TRUE);
+    ARRAY_REMOVE_INDEX (priv->long_ref, i);
+  }
+
+  picNumX = get_picNumX (picture, ref_pic_marking);
+  i = find_short_term_reference (decoder, picNumX);
+  if (i < 0)
+    return;
+
+  ref_picture = priv->short_ref[i];
+  ARRAY_REMOVE_INDEX (priv->short_ref, i);
+  priv->long_ref[priv->long_ref_count++] = ref_picture;
+
+  ref_picture->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
+  gst_vaapi_picture_h264_set_reference (ref_picture,
+      GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE,
+      GST_VAAPI_PICTURE_IS_COMPLETE (picture));
+
+  /* Assign LongTermFrameIdx to the other field if it was also
+     marked as "used for long-term reference */
+  other_field = ref_picture->other_field;
+  if (other_field && GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (other_field))
+    other_field->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
+}
+
+/* 8.2.5.4.4. Mark pictures with LongTermFramIdx > max_long_term_frame_idx
+ * as "unused for reference" */
+static void
+exec_ref_pic_marking_adaptive_mmco_4 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  gint32 i, long_term_frame_idx;
+
+  long_term_frame_idx = ref_pic_marking->max_long_term_frame_idx_plus1 - 1;
+
+  for (i = 0; i < priv->long_ref_count; i++) {
+    if (priv->long_ref[i]->long_term_frame_idx <= long_term_frame_idx)
+      continue;
+    gst_vaapi_picture_h264_set_reference (priv->long_ref[i], 0, FALSE);
+    ARRAY_REMOVE_INDEX (priv->long_ref, i);
+    i--;
+  }
+}
+
+/* 8.2.5.4.5. Mark all reference pictures as "unused for reference" */
+static void
+exec_ref_pic_marking_adaptive_mmco_5 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+
+  dpb_flush (decoder, picture);
+
+  priv->prev_pic_has_mmco5 = TRUE;
+
+  /* The picture shall be inferred to have had frame_num equal to 0 (7.4.3) */
+  priv->frame_num = 0;
+  priv->frame_num_offset = 0;
+  picture->frame_num = 0;
+
+  /* Update TopFieldOrderCnt and BottomFieldOrderCnt (8.2.1) */
+  if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD)
+    picture->field_poc[TOP_FIELD] -= picture->base.poc;
+  if (picture->structure != GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD)
+    picture->field_poc[BOTTOM_FIELD] -= picture->base.poc;
+  picture->base.poc = 0;
+}
+
+/* 8.2.5.4.6. Assign a long-term frame index to the current picture */
+static void
+exec_ref_pic_marking_adaptive_mmco_6 (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture, GstH264RefPicMarking * ref_pic_marking)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPictureH264 *other_field;
+  guint i;
+
+  for (i = 0; i < priv->long_ref_count; i++) {
+    if (priv->long_ref[i]->long_term_frame_idx ==
+        ref_pic_marking->long_term_frame_idx)
+      break;
+  }
+  if (i != priv->long_ref_count) {
+    gst_vaapi_picture_h264_set_reference (priv->long_ref[i], 0, TRUE);
+    ARRAY_REMOVE_INDEX (priv->long_ref, i);
+  }
+
+  picture->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
+  gst_vaapi_picture_h264_set_reference (picture,
+      GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE,
+      GST_VAAPI_PICTURE_IS_COMPLETE (picture));
+
+  /* Assign LongTermFrameIdx to the other field if it was also
+     marked as "used for long-term reference */
+  other_field = GST_VAAPI_PICTURE_H264 (picture->base.parent_picture);
+  if (other_field && GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (other_field))
+    other_field->long_term_frame_idx = ref_pic_marking->long_term_frame_idx;
+}
+
+/* 8.2.5.4. Adaptive memory control decoded reference picture marking process */
+static gboolean
+exec_ref_pic_marking_adaptive (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture,
+    GstH264DecRefPicMarking * dec_ref_pic_marking)
+{
+  guint i;
+
+  typedef void (*exec_ref_pic_marking_adaptive_mmco_func) (GstVaapiDecoderH264 *
+      decoder, GstVaapiPictureH264 * picture,
+      GstH264RefPicMarking * ref_pic_marking);
+
+  static const exec_ref_pic_marking_adaptive_mmco_func mmco_funcs[] = {
+    NULL,
+    exec_ref_pic_marking_adaptive_mmco_1,
+    exec_ref_pic_marking_adaptive_mmco_2,
+    exec_ref_pic_marking_adaptive_mmco_3,
+    exec_ref_pic_marking_adaptive_mmco_4,
+    exec_ref_pic_marking_adaptive_mmco_5,
+    exec_ref_pic_marking_adaptive_mmco_6,
+  };
+
+  GST_DEBUG ("reference picture marking process (adaptive memory control)");
+
+  for (i = 0; i < dec_ref_pic_marking->n_ref_pic_marking; i++) {
+    GstH264RefPicMarking *const ref_pic_marking =
+        &dec_ref_pic_marking->ref_pic_marking[i];
+
+    const guint mmco = ref_pic_marking->memory_management_control_operation;
+    if (mmco < G_N_ELEMENTS (mmco_funcs) && mmco_funcs[mmco])
+      mmco_funcs[mmco] (decoder, picture, ref_pic_marking);
+    else {
+      GST_ERROR ("unhandled MMCO %u", mmco);
+      return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+/* 8.2.5 - Execute reference picture marking process */
+static gboolean
+exec_ref_pic_marking (GstVaapiDecoderH264 * decoder,
+    GstVaapiPictureH264 * picture)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+
+  priv->prev_pic_reference = GST_VAAPI_PICTURE_IS_REFERENCE (picture);
+  priv->prev_pic_has_mmco5 = FALSE;
+  priv->prev_pic_structure = picture->structure;
+
+  if (GST_VAAPI_PICTURE_IS_INTER_VIEW (picture))
+    g_ptr_array_add (priv->inter_views, gst_vaapi_picture_ref (picture));
+
+  if (!priv->prev_pic_reference)
+    return TRUE;
+
+  if (!GST_VAAPI_PICTURE_IS_IDR (picture)) {
+    GstH264DecRefPicMarking *const dec_ref_pic_marking =
+        &picture->last_slice_hdr->dec_ref_pic_marking;
+    if (dec_ref_pic_marking->adaptive_ref_pic_marking_mode_flag) {
+      if (!exec_ref_pic_marking_adaptive (decoder, picture,
+              dec_ref_pic_marking))
+        return FALSE;
+    } else {
+      if (!exec_ref_pic_marking_sliding_window (decoder))
+        return FALSE;
+    }
+  }
+  return TRUE;
+}
+
+static void
+vaapi_init_picture (VAPictureH264 * pic)
+{
+  pic->picture_id = VA_INVALID_ID;
+  pic->frame_idx = 0;
+  pic->flags = VA_PICTURE_H264_INVALID;
+  pic->TopFieldOrderCnt = 0;
+  pic->BottomFieldOrderCnt = 0;
+}
+
+static void
+vaapi_fill_picture (VAPictureH264 * pic, GstVaapiPictureH264 * picture,
+    guint picture_structure)
+{
+  if (!picture_structure)
+    picture_structure = picture->structure;
+
+  pic->picture_id = picture->base.surface_id;
+  pic->flags = 0;
+
+  if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (picture)) {
+    pic->flags |= VA_PICTURE_H264_LONG_TERM_REFERENCE;
+    pic->frame_idx = picture->long_term_frame_idx;
+  } else {
+    if (GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (picture))
+      pic->flags |= VA_PICTURE_H264_SHORT_TERM_REFERENCE;
+    pic->frame_idx = picture->frame_num;
+  }
+
+  switch (picture_structure) {
+    case GST_VAAPI_PICTURE_STRUCTURE_FRAME:
+      pic->TopFieldOrderCnt = picture->field_poc[TOP_FIELD];
+      pic->BottomFieldOrderCnt = picture->field_poc[BOTTOM_FIELD];
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
+      pic->flags |= VA_PICTURE_H264_TOP_FIELD;
+      pic->TopFieldOrderCnt = picture->field_poc[TOP_FIELD];
+      pic->BottomFieldOrderCnt = 0;
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
+      pic->flags |= VA_PICTURE_H264_BOTTOM_FIELD;
+      pic->BottomFieldOrderCnt = picture->field_poc[BOTTOM_FIELD];
+      pic->TopFieldOrderCnt = 0;
+      break;
+  }
+}
+
+static void
+vaapi_fill_picture_for_RefPicListX (VAPictureH264 * pic,
+    GstVaapiPictureH264 * picture)
+{
+  vaapi_fill_picture (pic, picture, 0);
+
+  /* H.8.4 - MVC inter prediction and inter-view prediction process */
+  if (GST_VAAPI_PICTURE_IS_INTER_VIEW (picture)) {
+    /* The inter-view reference components and inter-view only
+       reference components that are included in the reference
+       picture lists are considered as not being marked as "used for
+       short-term reference" or "used for long-term reference" */
+    pic->flags &= ~(VA_PICTURE_H264_SHORT_TERM_REFERENCE |
+        VA_PICTURE_H264_LONG_TERM_REFERENCE);
+  }
+}
+
+static gboolean
+fill_picture (GstVaapiDecoderH264 * decoder, GstVaapiPictureH264 * picture)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiPicture *const base_picture = &picture->base;
+  GstH264PPS *const pps = get_pps (decoder);
+  GstH264SPS *const sps = get_sps (decoder);
+  VAPictureParameterBufferH264 *const pic_param = base_picture->param;
+  guint i, n;
+
+  /* Fill in VAPictureParameterBufferH264 */
+  vaapi_fill_picture (&pic_param->CurrPic, picture, 0);
+
+  for (i = 0, n = 0; i < priv->dpb_count; i++) {
+    GstVaapiFrameStore *const fs = priv->dpb[i];
+    if ((gst_vaapi_frame_store_has_reference (fs) &&
+            fs->view_id == picture->base.view_id) ||
+        (gst_vaapi_frame_store_has_inter_view (fs) &&
+            is_inter_view_reference_for_picture (decoder, fs->view_id,
+                picture)))
+      vaapi_fill_picture (&pic_param->ReferenceFrames[n++], fs->buffers[0],
+          fs->structure);
+    if (n >= G_N_ELEMENTS (pic_param->ReferenceFrames))
+      break;
+  }
+  for (; n < G_N_ELEMENTS (pic_param->ReferenceFrames); n++)
+    vaapi_init_picture (&pic_param->ReferenceFrames[n]);
+
+#define COPY_FIELD(s, f) \
+    pic_param->f = (s)->f
+
+#define COPY_BFM(a, s, f) \
+    pic_param->a.bits.f = (s)->f
+
+  pic_param->picture_width_in_mbs_minus1 = priv->mb_width - 1;
+  pic_param->picture_height_in_mbs_minus1 = priv->mb_height - 1;
+  pic_param->frame_num = priv->frame_num;
+
+  COPY_FIELD (sps, bit_depth_luma_minus8);
+  COPY_FIELD (sps, bit_depth_chroma_minus8);
+  COPY_FIELD (sps, num_ref_frames);
+  if (pic_param->num_ref_frames == 0)
+    pic_param->num_ref_frames = priv->dpb_size;
+
+#if !VA_CHECK_VERSION(1,0,0)
+  /* Deprecate H.264 baseline profile and FMO support */
+  COPY_FIELD (pps, num_slice_groups_minus1);
+  COPY_FIELD (pps, slice_group_map_type);
+  COPY_FIELD (pps, slice_group_change_rate_minus1);
+#endif
+  COPY_FIELD (pps, pic_init_qp_minus26);
+  COPY_FIELD (pps, pic_init_qs_minus26);
+  COPY_FIELD (pps, chroma_qp_index_offset);
+  COPY_FIELD (pps, second_chroma_qp_index_offset);
+
+  pic_param->seq_fields.value = 0;      /* reset all bits */
+  pic_param->seq_fields.bits.residual_colour_transform_flag =
+      sps->separate_colour_plane_flag;
+  pic_param->seq_fields.bits.MinLumaBiPredSize8x8 = sps->level_idc >= 31;       /* A.3.3.2 */
+
+  COPY_BFM (seq_fields, sps, chroma_format_idc);
+  COPY_BFM (seq_fields, sps, gaps_in_frame_num_value_allowed_flag);
+  COPY_BFM (seq_fields, sps, frame_mbs_only_flag);
+  COPY_BFM (seq_fields, sps, mb_adaptive_frame_field_flag);
+  COPY_BFM (seq_fields, sps, direct_8x8_inference_flag);
+  COPY_BFM (seq_fields, sps, log2_max_frame_num_minus4);
+  COPY_BFM (seq_fields, sps, pic_order_cnt_type);
+  COPY_BFM (seq_fields, sps, log2_max_pic_order_cnt_lsb_minus4);
+  COPY_BFM (seq_fields, sps, delta_pic_order_always_zero_flag);
+
+  pic_param->pic_fields.value = 0;      /* reset all bits */
+  pic_param->pic_fields.bits.field_pic_flag =
+      GST_VAAPI_PICTURE_IS_INTERLACED (picture);
+  pic_param->pic_fields.bits.reference_pic_flag =
+      GST_VAAPI_PICTURE_IS_REFERENCE (picture);
+
+  COPY_BFM (pic_fields, pps, entropy_coding_mode_flag);
+  COPY_BFM (pic_fields, pps, weighted_pred_flag);
+  COPY_BFM (pic_fields, pps, weighted_bipred_idc);
+  COPY_BFM (pic_fields, pps, transform_8x8_mode_flag);
+  COPY_BFM (pic_fields, pps, constrained_intra_pred_flag);
+  COPY_BFM (pic_fields, pps, pic_order_present_flag);
+  COPY_BFM (pic_fields, pps, deblocking_filter_control_present_flag);
+  COPY_BFM (pic_fields, pps, redundant_pic_cnt_present_flag);
+  return TRUE;
+}
+
+/* Detection of the first VCL NAL unit of a primary coded picture (7.4.1.2.4) */
+static gboolean
+is_new_picture (GstVaapiParserInfoH264 * pi, GstVaapiParserInfoH264 * prev_pi)
+{
+  GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstH264PPS *const pps = slice_hdr->pps;
+  GstH264SPS *const sps = pps->sequence;
+  GstH264SliceHdr *prev_slice_hdr;
+
+  if (!prev_pi)
+    return TRUE;
+  prev_slice_hdr = &prev_pi->data.slice_hdr;
+
+#define CHECK_EXPR(expr, field_name) do {              \
+        if (!(expr)) {                                 \
+            GST_DEBUG(field_name " differs in value"); \
+            return TRUE;                               \
+        }                                              \
+    } while (0)
+
+#define CHECK_VALUE(new_slice_hdr, old_slice_hdr, field) \
+    CHECK_EXPR(((new_slice_hdr)->field == (old_slice_hdr)->field), #field)
+
+  /* view_id differs in value and VOIdx of current slice_hdr is less
+     than the VOIdx of the prev_slice_hdr */
+  CHECK_VALUE (pi, prev_pi, view_id);
+
+  /* frame_num differs in value, regardless of inferred values to 0 */
+  CHECK_VALUE (slice_hdr, prev_slice_hdr, frame_num);
+
+  /* pic_parameter_set_id differs in value */
+  CHECK_VALUE (slice_hdr, prev_slice_hdr, pps);
+
+  /* field_pic_flag differs in value */
+  CHECK_VALUE (slice_hdr, prev_slice_hdr, field_pic_flag);
+
+  /* bottom_field_flag is present in both and differs in value */
+  if (slice_hdr->field_pic_flag && prev_slice_hdr->field_pic_flag)
+    CHECK_VALUE (slice_hdr, prev_slice_hdr, bottom_field_flag);
+
+  /* nal_ref_idc differs in value with one of the nal_ref_idc values is 0 */
+  CHECK_EXPR ((pi->nalu.ref_idc != 0) ==
+      (prev_pi->nalu.ref_idc != 0), "nal_ref_idc");
+
+  /* POC type is 0 for both and either pic_order_cnt_lsb differs in
+     value or delta_pic_order_cnt_bottom differs in value */
+  if (sps->pic_order_cnt_type == 0) {
+    CHECK_VALUE (slice_hdr, prev_slice_hdr, pic_order_cnt_lsb);
+    if (pps->pic_order_present_flag && !slice_hdr->field_pic_flag)
+      CHECK_VALUE (slice_hdr, prev_slice_hdr, delta_pic_order_cnt_bottom);
+  }
+
+  /* POC type is 1 for both and either delta_pic_order_cnt[0]
+     differs in value or delta_pic_order_cnt[1] differs in value */
+  else if (sps->pic_order_cnt_type == 1) {
+    CHECK_VALUE (slice_hdr, prev_slice_hdr, delta_pic_order_cnt[0]);
+    CHECK_VALUE (slice_hdr, prev_slice_hdr, delta_pic_order_cnt[1]);
+  }
+
+  /* IdrPicFlag differs in value */
+  CHECK_VALUE (&pi->nalu, &prev_pi->nalu, idr_pic_flag);
+
+  /* IdrPicFlag is equal to 1 for both and idr_pic_id differs in value */
+  if (pi->nalu.idr_pic_flag)
+    CHECK_VALUE (slice_hdr, prev_slice_hdr, idr_pic_id);
+
+#undef CHECK_EXPR
+#undef CHECK_VALUE
+  return FALSE;
+}
+
+/* Detection of a new access unit, assuming we are already in presence
+   of a new picture */
+static inline gboolean
+is_new_access_unit (GstVaapiParserInfoH264 * pi,
+    GstVaapiParserInfoH264 * prev_pi)
+{
+  if (!prev_pi || prev_pi->view_id == pi->view_id)
+    return TRUE;
+  return pi->voc < prev_pi->voc;
+}
+
+/* Determines whether the supplied picture has the same field parity
+   than a picture specified through the other slice header */
+static inline gboolean
+same_field_parity (GstVaapiPictureH264 * field, GstH264SliceHdr * slice_hdr)
+{
+  g_return_val_if_fail (GST_VAAPI_PICTURE_IS_INTERLACED (field), FALSE);
+
+  return ((field->base.structure == GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) ^
+      slice_hdr->bottom_field_flag) == 0;
+}
+
+/* Finds the first field picture corresponding to the supplied picture */
+static GstVaapiPictureH264 *
+find_first_field (GstVaapiDecoderH264 * decoder, GstVaapiParserInfoH264 * pi)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstVaapiFrameStore *fs;
+  GstVaapiPictureH264 *f0, *f1;
+
+  fs = priv->prev_frames[pi->voc];
+  if (!fs)
+    return NULL;
+
+  f0 = fs->buffers[0];
+  if (!slice_hdr->field_pic_flag) {
+    if (!gst_vaapi_frame_store_has_frame (fs))
+      fill_picture_other_field_gap (decoder, f0);
+    return NULL;
+  }
+
+  /* At this point, the current frame is known to be interlaced */
+  if (gst_vaapi_frame_store_has_frame (fs)) {
+    return NULL;
+  }
+
+  /* At this point, the previous frame is interlaced and contains a
+     single field */
+  if (f0->frame_num == slice_hdr->frame_num) {
+    f1 = f0;
+    if (same_field_parity (f0, slice_hdr)) {
+      fill_picture_other_field_gap (decoder, f0);
+      f1 = NULL;
+    }
+    return f1;
+  }
+
+  fill_picture_other_field_gap (decoder, f0);
+  return NULL;
+}
+
+static GstVaapiDecoderStatus
+decode_picture (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstH264PPS *const pps = ensure_pps (decoder, slice_hdr->pps);
+  GstH264SPS *const sps = ensure_sps (decoder, slice_hdr->pps->sequence);
+  GstVaapiPictureH264 *picture, *first_field;
+  GstVaapiDecoderStatus status;
+
+  if (!(pps && sps))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  status = ensure_context (decoder, sps);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  priv->decoder_state = 0;
+
+  first_field = find_first_field (decoder, pi);
+  if (first_field) {
+    /* Re-use current picture where the first field was decoded */
+    picture = gst_vaapi_picture_h264_new_field (first_field);
+    if (!picture) {
+      GST_ERROR ("failed to allocate field picture");
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+  } else {
+    /* Create new picture */
+    picture = gst_vaapi_picture_h264_new (decoder);
+    if (!picture) {
+      GST_ERROR ("failed to allocate picture");
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+  }
+  gst_vaapi_picture_replace (&priv->current_picture, picture);
+  gst_vaapi_picture_unref (picture);
+
+  /* Clear inter-view references list if this is the primary coded
+     picture of the current access unit */
+  if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_START)
+    g_ptr_array_set_size (priv->inter_views, 0);
+
+  /* Update cropping rectangle */
+  if (sps->frame_cropping_flag) {
+    GstVaapiRectangle crop_rect;
+    crop_rect.x = sps->crop_rect_x;
+    crop_rect.y = sps->crop_rect_y;
+    crop_rect.width = sps->crop_rect_width;
+    crop_rect.height = sps->crop_rect_height;
+    gst_vaapi_picture_set_crop_rect (&picture->base, &crop_rect);
+  }
+
+  status = ensure_quant_matrix (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    GST_ERROR ("failed to reset quantizer matrix");
+    return status;
+  }
+
+  if (!init_picture (decoder, picture, pi))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  if (!fill_picture (decoder, picture))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  priv->decoder_state = pi->state;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline guint
+get_slice_data_bit_offset (GstH264SliceHdr * slice_hdr, guint nal_header_bytes)
+{
+  guint epb_count;
+
+  epb_count = slice_hdr->n_emulation_prevention_bytes;
+  return 8 * nal_header_bytes + slice_hdr->header_size - epb_count * 8;
+}
+
+static gboolean
+fill_pred_weight_table (GstVaapiDecoderH264 * decoder,
+    GstVaapiSlice * slice, GstH264SliceHdr * slice_hdr)
+{
+  VASliceParameterBufferH264 *const slice_param = slice->param;
+  GstH264PPS *const pps = get_pps (decoder);
+  GstH264SPS *const sps = get_sps (decoder);
+  GstH264PredWeightTable *const w = &slice_hdr->pred_weight_table;
+  guint num_weight_tables = 0;
+  gint i, j;
+
+  if (pps->weighted_pred_flag &&
+      (GST_H264_IS_P_SLICE (slice_hdr) || GST_H264_IS_SP_SLICE (slice_hdr)))
+    num_weight_tables = 1;
+  else if (pps->weighted_bipred_idc == 1 && GST_H264_IS_B_SLICE (slice_hdr))
+    num_weight_tables = 2;
+  else
+    num_weight_tables = 0;
+
+  slice_param->luma_log2_weight_denom = 0;
+  slice_param->chroma_log2_weight_denom = 0;
+  slice_param->luma_weight_l0_flag = 0;
+  slice_param->chroma_weight_l0_flag = 0;
+  slice_param->luma_weight_l1_flag = 0;
+  slice_param->chroma_weight_l1_flag = 0;
+
+  if (num_weight_tables < 1)
+    return TRUE;
+
+  slice_param->luma_log2_weight_denom = w->luma_log2_weight_denom;
+  slice_param->chroma_log2_weight_denom = w->chroma_log2_weight_denom;
+
+  slice_param->luma_weight_l0_flag = 1;
+  for (i = 0; i <= slice_param->num_ref_idx_l0_active_minus1; i++) {
+    slice_param->luma_weight_l0[i] = w->luma_weight_l0[i];
+    slice_param->luma_offset_l0[i] = w->luma_offset_l0[i];
+  }
+
+  slice_param->chroma_weight_l0_flag = sps->chroma_array_type != 0;
+  if (slice_param->chroma_weight_l0_flag) {
+    for (i = 0; i <= slice_param->num_ref_idx_l0_active_minus1; i++) {
+      for (j = 0; j < 2; j++) {
+        slice_param->chroma_weight_l0[i][j] = w->chroma_weight_l0[i][j];
+        slice_param->chroma_offset_l0[i][j] = w->chroma_offset_l0[i][j];
+      }
+    }
+  }
+
+  if (num_weight_tables < 2)
+    return TRUE;
+
+  slice_param->luma_weight_l1_flag = 1;
+  for (i = 0; i <= slice_param->num_ref_idx_l1_active_minus1; i++) {
+    slice_param->luma_weight_l1[i] = w->luma_weight_l1[i];
+    slice_param->luma_offset_l1[i] = w->luma_offset_l1[i];
+  }
+
+  slice_param->chroma_weight_l1_flag = sps->chroma_array_type != 0;
+  if (slice_param->chroma_weight_l1_flag) {
+    for (i = 0; i <= slice_param->num_ref_idx_l1_active_minus1; i++) {
+      for (j = 0; j < 2; j++) {
+        slice_param->chroma_weight_l1[i][j] = w->chroma_weight_l1[i][j];
+        slice_param->chroma_offset_l1[i][j] = w->chroma_offset_l1[i][j];
+      }
+    }
+  }
+  return TRUE;
+}
+
+static gboolean
+fill_RefPicList (GstVaapiDecoderH264 * decoder,
+    GstVaapiSlice * slice, GstH264SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  VASliceParameterBufferH264 *const slice_param = slice->param;
+  guint i, num_ref_lists = 0;
+
+  slice_param->num_ref_idx_l0_active_minus1 = 0;
+  slice_param->num_ref_idx_l1_active_minus1 = 0;
+
+  /* ensure empty list by default */
+  vaapi_init_picture (&slice_param->RefPicList0[0]);
+  vaapi_init_picture (&slice_param->RefPicList1[0]);
+
+  if (GST_H264_IS_B_SLICE (slice_hdr))
+    num_ref_lists = 2;
+  else if (GST_H264_IS_I_SLICE (slice_hdr))
+    num_ref_lists = 0;
+  else
+    num_ref_lists = 1;
+
+  if (num_ref_lists < 1)
+    return TRUE;
+
+  slice_param->num_ref_idx_l0_active_minus1 =
+      slice_hdr->num_ref_idx_l0_active_minus1;
+
+  for (i = 0; i < priv->RefPicList0_count && priv->RefPicList0[i]; i++)
+    vaapi_fill_picture_for_RefPicListX (&slice_param->RefPicList0[i],
+        priv->RefPicList0[i]);
+  if (i < 32)
+    vaapi_init_picture (&slice_param->RefPicList0[i]);
+
+  if (num_ref_lists < 2)
+    return TRUE;
+
+  slice_param->num_ref_idx_l1_active_minus1 =
+      slice_hdr->num_ref_idx_l1_active_minus1;
+
+  for (i = 0; i < priv->RefPicList1_count && priv->RefPicList1[i]; i++)
+    vaapi_fill_picture_for_RefPicListX (&slice_param->RefPicList1[i],
+        priv->RefPicList1[i]);
+  if (i < 32)
+    vaapi_init_picture (&slice_param->RefPicList1[i]);
+
+  return TRUE;
+}
+
+static gboolean
+fill_slice (GstVaapiDecoderH264 * decoder,
+    GstVaapiSlice * slice, GstVaapiParserInfoH264 * pi)
+{
+  VASliceParameterBufferH264 *const slice_param = slice->param;
+  GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+
+  /* Fill in VASliceParameterBufferH264 */
+  slice_param->slice_data_bit_offset =
+      get_slice_data_bit_offset (slice_hdr, pi->nalu.header_bytes);
+  slice_param->first_mb_in_slice = slice_hdr->first_mb_in_slice;
+  slice_param->slice_type = slice_hdr->type % 5;
+  slice_param->direct_spatial_mv_pred_flag =
+      slice_hdr->direct_spatial_mv_pred_flag;
+  slice_param->cabac_init_idc = slice_hdr->cabac_init_idc;
+  slice_param->slice_qp_delta = slice_hdr->slice_qp_delta;
+  slice_param->disable_deblocking_filter_idc =
+      slice_hdr->disable_deblocking_filter_idc;
+  slice_param->slice_alpha_c0_offset_div2 =
+      slice_hdr->slice_alpha_c0_offset_div2;
+  slice_param->slice_beta_offset_div2 = slice_hdr->slice_beta_offset_div2;
+
+  if (!fill_RefPicList (decoder, slice, slice_hdr))
+    return FALSE;
+  if (!fill_pred_weight_table (decoder, slice, slice_hdr))
+    return FALSE;
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_slice (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstVaapiPictureH264 *const picture = priv->current_picture;
+  GstH264SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstVaapiSlice *slice;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  GST_DEBUG ("slice (%u bytes)", pi->nalu.size);
+
+  if (!is_valid_state (pi->state, GST_H264_VIDEO_STATE_VALID_PICTURE_HEADERS)) {
+    GST_WARNING ("failed to receive enough headers to decode slice");
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  }
+
+  if (!ensure_pps (decoder, slice_hdr->pps)) {
+    GST_ERROR ("failed to activate PPS");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (!ensure_sps (decoder, slice_hdr->pps->sequence)) {
+    GST_ERROR ("failed to activate SPS");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  /* Check wether this is the first/last slice in the current access unit */
+  if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_START)
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_START);
+  if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_END)
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_END);
+
+  slice = GST_VAAPI_SLICE_NEW (H264, decoder,
+      (map_info.data + unit->offset + pi->nalu.offset), pi->nalu.size);
+  gst_buffer_unmap (buffer, &map_info);
+  if (!slice) {
+    GST_ERROR ("failed to allocate slice");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  if (!init_picture_refs (decoder, picture, slice_hdr)) {
+    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice));
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (!fill_slice (decoder, slice, pi)) {
+    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice));
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
+  picture->last_slice_hdr = slice_hdr;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline gint
+scan_for_start_code (GstAdapter * adapter, guint ofs, guint size, guint32 * scp)
+{
+  if (size == 0)
+    return -1;
+
+  return (gint) gst_adapter_masked_scan_uint32_peek (adapter,
+      0xffffff00, 0x00000100, ofs, size, scp);
+}
+
+static GstVaapiDecoderStatus
+decode_unit (GstVaapiDecoderH264 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH264 *const pi = unit->parsed_info;
+  GstVaapiDecoderStatus status;
+
+  priv->decoder_state |= pi->state;
+  switch (pi->nalu.type) {
+    case GST_H264_NAL_SPS:
+      status = decode_sps (decoder, unit);
+      break;
+    case GST_H264_NAL_SUBSET_SPS:
+      status = decode_subset_sps (decoder, unit);
+      break;
+    case GST_H264_NAL_PPS:
+      status = decode_pps (decoder, unit);
+      break;
+    case GST_H264_NAL_SLICE_EXT:
+    case GST_H264_NAL_SLICE_IDR:
+      /* fall-through. IDR specifics are handled in init_picture() */
+    case GST_H264_NAL_SLICE:
+      status = decode_slice (decoder, unit);
+      break;
+    case GST_H264_NAL_SEQ_END:
+    case GST_H264_NAL_STREAM_END:
+      status = decode_sequence_end (decoder);
+      break;
+    case GST_H264_NAL_SEI:
+      status = decode_sei (decoder, unit);
+      break;
+    case GST_H264_NAL_SLICE_DPA:
+    case GST_H264_NAL_SLICE_DPB:
+    case GST_H264_NAL_SLICE_DPC:
+    case GST_H264_NAL_AU_DELIMITER:
+    case GST_H264_NAL_FILLER_DATA:
+    case GST_H264_NAL_SPS_EXT:
+    case GST_H264_NAL_PREFIX_UNIT:
+    case GST_H264_NAL_DEPTH_SPS:
+    case GST_H264_NAL_SLICE_AUX:
+    case GST_H264_NAL_SLICE_DEPTH:
+      GST_DEBUG ("unsupported NAL unit type %d, just skip", pi->nalu.type);
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+    default:
+      GST_WARNING ("unknown NAL unit type id %d, skip", pi->nalu.type);
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+  }
+  return status;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h264_decode_codec_data (GstVaapiDecoder * base_decoder,
+    const guchar * buf, guint buf_size)
+{
+  GstVaapiDecoderH264 *const decoder =
+      GST_VAAPI_DECODER_H264_CAST (base_decoder);
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+  GstVaapiDecoderUnit unit;
+  GstVaapiParserInfoH264 *pi = NULL;
+  GstH264ParserResult result;
+  guint i, ofs, num_sps, num_pps;
+
+  if (!priv->is_opened)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  unit.parsed_info = NULL;
+
+  if (buf_size < 7)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  if (buf[0] != 1) {
+    GST_ERROR ("failed to decode codec-data, not in avcC format");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  priv->nal_length_size = (buf[4] & 0x03) + 1;
+
+  num_sps = buf[5] & 0x1f;
+  ofs = 6;
+
+  for (i = 0; i < num_sps; i++) {
+    pi = gst_vaapi_parser_info_h264_new ();
+    if (!pi)
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    unit.parsed_info = pi;
+
+    result = gst_h264_parser_identify_nalu_avc (priv->parser,
+        buf, ofs, buf_size, 2, &pi->nalu);
+    if (result != GST_H264_PARSER_OK) {
+      status = get_status (result);
+      goto cleanup;
+    }
+
+    status = parse_sps (decoder, &unit);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      goto cleanup;
+    ofs = pi->nalu.offset + pi->nalu.size;
+
+    pi->state = priv->parser_state;
+    pi->flags = 0;
+
+    status = decode_sps (decoder, &unit);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      goto cleanup;
+    gst_vaapi_parser_info_h264_replace (&pi, NULL);
+  }
+
+  num_pps = buf[ofs];
+  ofs++;
+
+  for (i = 0; i < num_pps; i++) {
+    pi = gst_vaapi_parser_info_h264_new ();
+    if (!pi)
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    unit.parsed_info = pi;
+
+    result = gst_h264_parser_identify_nalu_avc (priv->parser,
+        buf, ofs, buf_size, 2, &pi->nalu);
+    if (result != GST_H264_PARSER_OK) {
+      status = get_status (result);
+      goto cleanup;
+    }
+
+    status = parse_pps (decoder, &unit);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      goto cleanup;
+    ofs = pi->nalu.offset + pi->nalu.size;
+
+    pi->state = priv->parser_state;
+    pi->flags = 0;
+
+    status = decode_pps (decoder, &unit);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      goto cleanup;
+    gst_vaapi_parser_info_h264_replace (&pi, NULL);
+  }
+
+  priv->is_avcC = TRUE;
+  status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+cleanup:
+  {
+    gst_vaapi_parser_info_h264_replace (&pi, NULL);
+    return status;
+  }
+}
+
+static GstVaapiDecoderStatus
+ensure_decoder (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+
+  if (!priv->is_opened) {
+    priv->is_opened = gst_vaapi_decoder_h264_open (decoder);
+    if (!priv->is_opened)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
+
+    status =
+        gst_vaapi_decoder_decode_codec_data (GST_VAAPI_DECODER_CAST (decoder));
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h264_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264 *const decoder =
+      GST_VAAPI_DECODER_H264_CAST (base_decoder);
+  GstVaapiDecoderH264Private *const priv = &decoder->priv;
+  GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder);
+  GstVaapiParserInfoH264 *pi;
+  GstVaapiDecoderStatus status;
+  GstH264ParserResult result;
+  guchar *buf;
+  guint i, size, buf_size, nalu_size, flags;
+  guint32 start_code;
+  gint ofs, ofs2;
+  gboolean at_au_end = FALSE;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  switch (priv->stream_alignment) {
+    case GST_VAAPI_STREAM_ALIGN_H264_NALU:
+    case GST_VAAPI_STREAM_ALIGN_H264_AU:
+      size = gst_adapter_available_fast (adapter);
+      break;
+    default:
+      size = gst_adapter_available (adapter);
+      break;
+  }
+
+  if (priv->is_avcC) {
+    if (size < priv->nal_length_size)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+    buf = (guchar *) & start_code;
+    g_assert (priv->nal_length_size <= sizeof (start_code));
+    gst_adapter_copy (adapter, buf, 0, priv->nal_length_size);
+
+    nalu_size = 0;
+    for (i = 0; i < priv->nal_length_size; i++)
+      nalu_size = (nalu_size << 8) | buf[i];
+
+    buf_size = priv->nal_length_size + nalu_size;
+    if (size < buf_size)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    else if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H264_AU)
+      at_au_end = (buf_size == size);
+  } else {
+    if (size < 4)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+    if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H264_NALU) {
+      buf_size = size;
+      ofs = scan_for_start_code (adapter, 4, size - 4, NULL);
+      if (ofs > 0)
+        buf_size = ofs;
+    } else {
+      ofs = scan_for_start_code (adapter, 0, size, NULL);
+      if (ofs < 0)
+        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+      if (ofs > 0) {
+        gst_adapter_flush (adapter, ofs);
+        size -= ofs;
+      }
+
+      ofs2 = ps->input_offset2 - ofs - 4;
+      if (ofs2 < 4)
+        ofs2 = 4;
+
+      ofs = G_UNLIKELY (size < ofs2 + 4) ? -1 :
+          scan_for_start_code (adapter, ofs2, size - ofs2, NULL);
+      if (ofs < 0) {
+        // Assume the whole NAL unit is present if end-of-stream
+        // or stream buffers aligned on access unit boundaries
+        if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H264_AU)
+          at_au_end = TRUE;
+        else if (!at_eos) {
+          ps->input_offset2 = size;
+          return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+        }
+        ofs = size;
+      }
+      buf_size = ofs;
+    }
+  }
+  ps->input_offset2 = 0;
+
+  buf = (guchar *) gst_adapter_map (adapter, buf_size);
+  if (!buf)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  unit->size = buf_size;
+
+  pi = gst_vaapi_parser_info_h264_new ();
+  if (!pi)
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit,
+      pi, (GDestroyNotify) gst_vaapi_mini_object_unref);
+
+  if (priv->is_avcC)
+    result = gst_h264_parser_identify_nalu_avc (priv->parser,
+        buf, 0, buf_size, priv->nal_length_size, &pi->nalu);
+  else
+    result = gst_h264_parser_identify_nalu_unchecked (priv->parser,
+        buf, 0, buf_size, &pi->nalu);
+  status = get_status (result);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    goto exit;
+
+  if (priv->base_only && (pi->nalu.type == GST_H264_NAL_PREFIX_UNIT
+          || pi->nalu.type == GST_H264_NAL_SUBSET_SPS
+          || pi->nalu.type == GST_H264_NAL_SLICE_EXT)) {
+    GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, GST_VAAPI_DECODER_UNIT_FLAG_SKIP);
+    pi->nalu.valid = FALSE;
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  }
+  switch (pi->nalu.type) {
+    case GST_H264_NAL_SPS:
+      status = parse_sps (decoder, unit);
+      break;
+    case GST_H264_NAL_SUBSET_SPS:
+      status = parse_subset_sps (decoder, unit);
+      break;
+    case GST_H264_NAL_PPS:
+      status = parse_pps (decoder, unit);
+      break;
+    case GST_H264_NAL_SEI:
+      status = parse_sei (decoder, unit);
+      break;
+    case GST_H264_NAL_SLICE_EXT:
+      if (!GST_H264_IS_MVC_NALU (&pi->nalu)) {
+        status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+        break;
+      }
+      /* fall-through */
+    case GST_H264_NAL_SLICE_IDR:
+    case GST_H264_NAL_SLICE:
+      status = parse_slice (decoder, unit);
+      break;
+    default:
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+  }
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    goto exit;
+
+  flags = 0;
+  if (at_au_end) {
+    flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END |
+        GST_VAAPI_DECODER_UNIT_FLAG_AU_END;
+  }
+  switch (pi->nalu.type) {
+    case GST_H264_NAL_AU_DELIMITER:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      /* fall-through */
+    case GST_H264_NAL_FILLER_DATA:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+      break;
+    case GST_H264_NAL_STREAM_END:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
+      /* fall-through */
+    case GST_H264_NAL_SEQ_END:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_END;
+      break;
+    case GST_H264_NAL_SPS:
+    case GST_H264_NAL_SUBSET_SPS:
+    case GST_H264_NAL_PPS:
+    case GST_H264_NAL_SEI:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      break;
+    case GST_H264_NAL_SLICE_EXT:
+      if (!GST_H264_IS_MVC_NALU (&pi->nalu)) {
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+        break;
+      }
+      /* fall-through */
+    case GST_H264_NAL_SLICE_IDR:
+    case GST_H264_NAL_SLICE:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      if (priv->prev_pi &&
+          (priv->prev_pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_END)) {
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START |
+            GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      } else if (is_new_picture (pi, priv->prev_slice_pi)) {
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+        if (is_new_access_unit (pi, priv->prev_slice_pi))
+          flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START;
+      }
+      gst_vaapi_parser_info_h264_replace (&priv->prev_slice_pi, pi);
+      break;
+    case GST_H264_NAL_SPS_EXT:
+    case GST_H264_NAL_SLICE_AUX:
+      /* skip SPS extension and auxiliary slice for now */
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+      break;
+    case GST_H264_NAL_PREFIX_UNIT:
+      /* skip Prefix NAL units for now */
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP |
+          GST_VAAPI_DECODER_UNIT_FLAG_AU_START |
+          GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      break;
+    default:
+      if (pi->nalu.type >= 14 && pi->nalu.type <= 18)
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START |
+            GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      break;
+  }
+  if ((flags & GST_VAAPI_DECODER_UNIT_FLAGS_AU) && priv->prev_slice_pi)
+    priv->prev_slice_pi->flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_END;
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+
+  pi->nalu.data = NULL;
+  pi->state = priv->parser_state;
+  pi->flags = flags;
+  gst_vaapi_parser_info_h264_replace (&priv->prev_pi, pi);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+exit:
+  {
+    gst_adapter_flush (adapter, unit->size);
+    gst_vaapi_parser_info_h264_unref (pi);
+    return status;
+  }
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h264_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264 *const decoder =
+      GST_VAAPI_DECODER_H264_CAST (base_decoder);
+  GstVaapiDecoderStatus status;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+  return decode_unit (decoder, unit);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h264_start_frame (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH264 *const decoder =
+      GST_VAAPI_DECODER_H264_CAST (base_decoder);
+
+  return decode_picture (decoder, unit);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h264_end_frame (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderH264 *const decoder =
+      GST_VAAPI_DECODER_H264_CAST (base_decoder);
+
+  return decode_current_picture (decoder);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h264_flush (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderH264 *const decoder =
+      GST_VAAPI_DECODER_H264_CAST (base_decoder);
+
+  dpb_flush (decoder, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+gst_vaapi_decoder_h264_finalize (GObject * object)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
+
+  gst_vaapi_decoder_h264_destroy (base_decoder);
+  G_OBJECT_CLASS (gst_vaapi_decoder_h264_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_h264_class_init (GstVaapiDecoderH264Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  decoder_class->reset = gst_vaapi_decoder_h264_reset;
+  decoder_class->parse = gst_vaapi_decoder_h264_parse;
+  decoder_class->decode = gst_vaapi_decoder_h264_decode;
+  decoder_class->start_frame = gst_vaapi_decoder_h264_start_frame;
+  decoder_class->end_frame = gst_vaapi_decoder_h264_end_frame;
+  decoder_class->flush = gst_vaapi_decoder_h264_flush;
+  decoder_class->decode_codec_data = gst_vaapi_decoder_h264_decode_codec_data;
+
+  object_class->finalize = gst_vaapi_decoder_h264_finalize;
+}
+
+static void
+gst_vaapi_decoder_h264_init (GstVaapiDecoderH264 * decoder)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+
+  gst_vaapi_decoder_h264_create (base_decoder);
+}
+
+/**
+ * gst_vaapi_decoder_h264_set_alignment:
+ * @decoder: a #GstVaapiDecoderH264
+ * @alignment: the #GstVaapiStreamAlignH264
+ *
+ * Specifies how stream buffers are aligned / fed, i.e. the boundaries
+ * of each buffer that is supplied to the decoder. This could be no
+ * specific alignment, NAL unit boundaries, or access unit boundaries.
+ */
+void
+gst_vaapi_decoder_h264_set_alignment (GstVaapiDecoderH264 * decoder,
+    GstVaapiStreamAlignH264 alignment)
+{
+  g_return_if_fail (decoder != NULL);
+
+  decoder->priv.stream_alignment = alignment;
+}
+
+/**
+ * gst_vaapi_decoder_h264_set_base_only:
+ * @decoder: a #GstVaapiDecoderH264
+ * @base_only: %TRUE to force decoding the base view only
+ *
+ * if @base_only is %TRUE only the base view of MVC or SVC encoded streams
+ * is decoded.
+ *
+ **/
+void
+gst_vaapi_decoder_h264_set_base_only (GstVaapiDecoderH264 * decoder,
+    gboolean base_only)
+{
+  g_return_if_fail (decoder != NULL);
+
+  decoder->priv.base_only = base_only;
+}
+
+/**
+ * gst_vaapi_decoder_h264_set_low_latency:
+ * @decoder: a #GstVaapiDecoderH264
+ * @force_low_latency: %TRUE if force low latency
+ *
+ * if @force_low_latency is %TRUE the decoded frames are pushed soon
+ * as possible, instead of to wait until decoded picture buffer (DPB)
+ * release them.
+ *
+ * This violate the H.264 specification but it is useful for some live
+ * sources.
+ **/
+void
+gst_vaapi_decoder_h264_set_low_latency (GstVaapiDecoderH264 * decoder,
+    gboolean force_low_latency)
+{
+  g_return_if_fail (decoder != NULL);
+
+  decoder->priv.force_low_latency = force_low_latency;
+}
+
+/**
+ * gst_vaapi_decoder_h264_get_low_latency:
+ * @decoder: a #GstVaapiDecoderH264
+ *
+ * Returns: %TRUE if the low latency mode is enabled; otherwise
+ * %FALSE.
+ **/
+gboolean
+gst_vaapi_decoder_h264_get_low_latency (GstVaapiDecoderH264 * decoder)
+{
+  g_return_val_if_fail (decoder != NULL, FALSE);
+
+  return decoder->priv.force_low_latency;
+}
+
+/**
+ * gst_vaapi_decoder_h264_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for MPEG-2 decoding.  The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_h264_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return g_object_new (GST_TYPE_VAAPI_DECODER_H264, "display", display,
+      "caps", caps, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h264.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h264.h
new file mode 100644 (file)
index 0000000..fd3f6c4
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ *  gstvaapidecoder_h264.h - H.264 decoder
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_H264_H
+#define GST_VAAPI_DECODER_H264_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER_H264 \
+    (gst_vaapi_decoder_h264_get_type ())
+#define GST_VAAPI_DECODER_H264(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_H264, GstVaapiDecoderH264))
+#define GST_VAAPI_IS_DECODER_H264(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_H264))
+
+typedef struct _GstVaapiDecoderH264             GstVaapiDecoderH264;
+
+/**
+ * GstVaapiStreamAlignH264:
+ * @GST_VAAPI_STREAM_ALIGN_H264_NONE: Generic H.264 stream buffers
+ * @GST_VAAPI_STREAM_ALIGN_H264_NALU: H.264 stream buffers aligned NAL
+ *   unit boundaries
+ * @GST_VAAPI_STREAM_ALIGN_H264_AU: H.264 stream buffers aligned on
+ *   access unit boundaries
+ *
+ * Set of possible buffer alignments for H.264 streams.
+ */
+typedef enum {
+    GST_VAAPI_STREAM_ALIGN_H264_NONE,
+    GST_VAAPI_STREAM_ALIGN_H264_NALU,
+    GST_VAAPI_STREAM_ALIGN_H264_AU
+} GstVaapiStreamAlignH264;
+
+GType
+gst_vaapi_decoder_h264_get_type (void) G_GNUC_CONST;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_h264_new (GstVaapiDisplay *display, GstCaps *caps);
+
+void
+gst_vaapi_decoder_h264_set_alignment(GstVaapiDecoderH264 *decoder,
+    GstVaapiStreamAlignH264 alignment);
+
+gboolean
+gst_vaapi_decoder_h264_get_low_latency(GstVaapiDecoderH264 * decoder);
+
+void
+gst_vaapi_decoder_h264_set_low_latency(GstVaapiDecoderH264 * decoder,
+    gboolean force_low_latency);
+
+void
+gst_vaapi_decoder_h264_set_base_only(GstVaapiDecoderH264 * decoder,
+    gboolean base_only);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderH264, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_H264_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h265.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h265.c
new file mode 100644 (file)
index 0000000..025939c
--- /dev/null
@@ -0,0 +1,3419 @@
+/*
+ *  gstvaapidecoder_h265.c - H.265 decoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_h265
+ * @short_description: H.265 decoder
+ */
+
+#include "sysdeps.h"
+#include <math.h>
+#include <gst/base/gstadapter.h>
+#include <gst/codecparsers/gsth265parser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapidecoder_h265.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapiutils_h265_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/* Defined to 1 if strict ordering of DPB is needed. Only useful for debug */
+#define USE_STRICT_DPB_ORDERING 0
+
+typedef struct _GstVaapiDecoderH265Private GstVaapiDecoderH265Private;
+typedef struct _GstVaapiDecoderH265Class GstVaapiDecoderH265Class;
+typedef struct _GstVaapiFrameStore GstVaapiFrameStore;
+typedef struct _GstVaapiFrameStoreClass GstVaapiFrameStoreClass;
+typedef struct _GstVaapiParserInfoH265 GstVaapiParserInfoH265;
+typedef struct _GstVaapiPictureH265 GstVaapiPictureH265;
+
+static gboolean nal_is_slice (guint8 nal_type);
+
+/* ------------------------------------------------------------------------- */
+/* --- H.265 Parser Info                                                 --- */
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Extended decoder unit flags:
+ *
+ * @GST_VAAPI_DECODER_UNIT_AU_START: marks the start of an access unit.
+ * @GST_VAAPI_DECODER_UNIT_AU_END: marks the end of an access unit.
+ */
+enum
+{
+  GST_VAAPI_DECODER_UNIT_FLAG_AU_START =
+      (GST_VAAPI_DECODER_UNIT_FLAG_LAST << 0),
+  GST_VAAPI_DECODER_UNIT_FLAG_AU_END = (GST_VAAPI_DECODER_UNIT_FLAG_LAST << 1),
+
+  GST_VAAPI_DECODER_UNIT_FLAGS_AU = (GST_VAAPI_DECODER_UNIT_FLAG_AU_START |
+      GST_VAAPI_DECODER_UNIT_FLAG_AU_END),
+};
+
+#define GST_VAAPI_PARSER_INFO_H265(obj) \
+    ((GstVaapiParserInfoH265 *)(obj))
+
+struct _GstVaapiParserInfoH265
+{
+  GstVaapiMiniObject parent_instance;
+  GstH265NalUnit nalu;
+  union
+  {
+    GstH265VPS vps;
+    GstH265SPS sps;
+    GstH265PPS pps;
+    GArray *sei;
+    GstH265SliceHdr slice_hdr;
+  } data;
+  guint state;
+  guint flags;                  // Same as decoder unit flags (persistent)
+};
+
+static void
+gst_vaapi_parser_info_h265_finalize (GstVaapiParserInfoH265 * pi)
+{
+  if (nal_is_slice (pi->nalu.type))
+    gst_h265_slice_hdr_free (&pi->data.slice_hdr);
+  else {
+    switch (pi->nalu.type) {
+      case GST_H265_NAL_VPS:
+      case GST_H265_NAL_SPS:
+      case GST_H265_NAL_PPS:
+        break;
+      case GST_H265_NAL_PREFIX_SEI:
+      case GST_H265_NAL_SUFFIX_SEI:
+        if (pi->data.sei) {
+          g_array_unref (pi->data.sei);
+          pi->data.sei = NULL;
+        }
+        break;
+    }
+  }
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_parser_info_h265_class (void)
+{
+  static const GstVaapiMiniObjectClass GstVaapiParserInfoH265Class = {
+    .size = sizeof (GstVaapiParserInfoH265),
+    .finalize = (GDestroyNotify) gst_vaapi_parser_info_h265_finalize
+  };
+  return &GstVaapiParserInfoH265Class;
+}
+
+static inline GstVaapiParserInfoH265 *
+gst_vaapi_parser_info_h265_new (void)
+{
+  return (GstVaapiParserInfoH265 *)
+      gst_vaapi_mini_object_new (gst_vaapi_parser_info_h265_class ());
+}
+
+#define gst_vaapi_parser_info_h265_ref(pi) \
+    gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(pi))
+
+#define gst_vaapi_parser_info_h265_unref(pi) \
+    gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(pi))
+
+#define gst_vaapi_parser_info_h265_replace(old_pi_ptr, new_pi)          \
+    gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_pi_ptr),  \
+        (GstVaapiMiniObject *)(new_pi))
+
+/* ------------------------------------------------------------------------- */
+/* --- H.265 Pictures                                                    --- */
+/* ------------------------------------------------------------------------- */
+
+/*
+ * Extended picture flags:
+ *
+ * @GST_VAAPI_PICTURE_FLAG_IDR: flag that specifies an IDR picture
+ * @GST_VAAPI_PICTURE_FLAG_AU_START: flag that marks the start of an
+ *   access unit (AU)
+ * @GST_VAAPI_PICTURE_FLAG_AU_END: flag that marks the end of an
+ *   access unit (AU)
+ * @GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE: flag indicate the inclusion
+ *   of picture in RefPicSetStCurrBefore reference list
+ * @GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER: flag indicate the inclusion
+ *   of picture in RefPictSetStCurrAfter reference list
+ * @GST_VAAPI_PICTURE_FLAG_RPS_ST_FOLL: flag indicate the inclusion
+ *   of picture in RefPicSetStFoll reference list
+ * @GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR: flag indicate the inclusion
+ *   of picture in RefPicSetLtCurr reference list
+ * @GST_VAAPI_PICTURE_FLAG_RPS_LT_FOLL: flag indicate the inclusion
+ *   of picture in RefPicSetLtFoll reference list
+ * @GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE: flag that specifies
+ *     "used for short-term reference"
+ * @GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE: flag that specifies
+ *     "used for long-term reference"
+ * @GST_VAAPI_PICTURE_FLAGS_REFERENCE: mask covering any kind of
+ *     reference picture (short-term reference or long-term reference)
+ */
+enum
+{
+  GST_VAAPI_PICTURE_FLAG_IDR = (GST_VAAPI_PICTURE_FLAG_LAST << 0),
+  GST_VAAPI_PICTURE_FLAG_REFERENCE2 = (GST_VAAPI_PICTURE_FLAG_LAST << 1),
+  GST_VAAPI_PICTURE_FLAG_AU_START = (GST_VAAPI_PICTURE_FLAG_LAST << 4),
+  GST_VAAPI_PICTURE_FLAG_AU_END = (GST_VAAPI_PICTURE_FLAG_LAST << 5),
+  GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE =
+      (GST_VAAPI_PICTURE_FLAG_LAST << 6),
+  GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER = (GST_VAAPI_PICTURE_FLAG_LAST << 7),
+  GST_VAAPI_PICTURE_FLAG_RPS_ST_FOLL = (GST_VAAPI_PICTURE_FLAG_LAST << 8),
+  GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR = (GST_VAAPI_PICTURE_FLAG_LAST << 9),
+  GST_VAAPI_PICTURE_FLAG_RPS_LT_FOLL = (GST_VAAPI_PICTURE_FLAG_LAST << 10),
+
+  GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE =
+      (GST_VAAPI_PICTURE_FLAG_REFERENCE),
+  GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE =
+      (GST_VAAPI_PICTURE_FLAG_REFERENCE | GST_VAAPI_PICTURE_FLAG_REFERENCE2),
+  GST_VAAPI_PICTURE_FLAGS_REFERENCE =
+      (GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE |
+      GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE),
+
+  GST_VAAPI_PICTURE_FLAGS_RPS_ST =
+      (GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE |
+      GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER |
+      GST_VAAPI_PICTURE_FLAG_RPS_ST_FOLL),
+  GST_VAAPI_PICTURE_FLAGS_RPS_LT =
+      (GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR | GST_VAAPI_PICTURE_FLAG_RPS_LT_FOLL),
+};
+
+#define GST_VAAPI_PICTURE_IS_IDR(picture) \
+    (GST_VAAPI_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_PICTURE_FLAG_IDR))
+
+#define GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE(picture)      \
+    ((GST_VAAPI_PICTURE_FLAGS(picture) &                        \
+      GST_VAAPI_PICTURE_FLAGS_REFERENCE) ==                     \
+     GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE)
+
+#define GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE(picture)       \
+    ((GST_VAAPI_PICTURE_FLAGS(picture) &                        \
+      GST_VAAPI_PICTURE_FLAGS_REFERENCE) ==                     \
+     GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE)
+
+#define GST_VAAPI_PICTURE_H265(picture) \
+    ((GstVaapiPictureH265 *)(picture))
+
+struct _GstVaapiPictureH265
+{
+  GstVaapiPicture base;
+  GstH265SliceHdr *last_slice_hdr;
+  guint structure;
+  gint32 poc;                   // PicOrderCntVal (8.3.1)
+  gint32 poc_lsb;               // slice_pic_order_cnt_lsb
+  guint32 pic_latency_cnt;      // PicLatencyCount
+  guint output_flag:1;
+  guint output_needed:1;
+  guint NoRaslOutputFlag:1;
+  guint NoOutputOfPriorPicsFlag:1;
+  guint RapPicFlag:1;           // nalu type between 16 and 21
+  guint IntraPicFlag:1;         // Intra pic (only Intra slices)
+};
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiPictureH265, gst_vaapi_picture_h265);
+
+void
+gst_vaapi_picture_h265_destroy (GstVaapiPictureH265 * picture)
+{
+  gst_vaapi_picture_destroy (GST_VAAPI_PICTURE (picture));
+}
+
+gboolean
+gst_vaapi_picture_h265_create (GstVaapiPictureH265 * picture,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  if (!gst_vaapi_picture_create (GST_VAAPI_PICTURE (picture), args))
+    return FALSE;
+
+  picture->structure = picture->base.structure;
+  picture->poc = G_MAXINT32;
+  picture->output_needed = FALSE;
+  return TRUE;
+}
+
+static inline void
+gst_vaapi_picture_h265_set_reference (GstVaapiPictureH265 * picture,
+    guint reference_flags)
+{
+  if (!picture)
+    return;
+  GST_VAAPI_PICTURE_FLAG_UNSET (picture,
+      GST_VAAPI_PICTURE_FLAGS_RPS_ST | GST_VAAPI_PICTURE_FLAGS_RPS_LT);
+  GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAGS_REFERENCE);
+  GST_VAAPI_PICTURE_FLAG_SET (picture, reference_flags);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Frame Buffers (DPB)                                               --- */
+/* ------------------------------------------------------------------------- */
+
+struct _GstVaapiFrameStore
+{
+  /*< private > */
+  GstVaapiMiniObject parent_instance;
+
+  GstVaapiPictureH265 *buffer;
+};
+
+static void
+gst_vaapi_frame_store_finalize (gpointer object)
+{
+  GstVaapiFrameStore *const fs = object;
+
+  gst_vaapi_picture_replace (&fs->buffer, NULL);
+}
+
+static GstVaapiFrameStore *
+gst_vaapi_frame_store_new (GstVaapiPictureH265 * picture)
+{
+  GstVaapiFrameStore *fs;
+
+  static const GstVaapiMiniObjectClass GstVaapiFrameStoreClass = {
+    sizeof (GstVaapiFrameStore),
+    gst_vaapi_frame_store_finalize
+  };
+
+  fs = (GstVaapiFrameStore *)
+      gst_vaapi_mini_object_new (&GstVaapiFrameStoreClass);
+  if (!fs)
+    return NULL;
+
+  fs->buffer = gst_vaapi_picture_ref (picture);
+
+  return fs;
+}
+
+static inline gboolean
+gst_vaapi_frame_store_has_reference (GstVaapiFrameStore * fs)
+{
+  if (GST_VAAPI_PICTURE_IS_REFERENCE (fs->buffer))
+    return TRUE;
+  return FALSE;
+}
+
+#define gst_vaapi_frame_store_ref(fs) \
+    gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(fs))
+
+#define gst_vaapi_frame_store_unref(fs) \
+    gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(fs))
+
+#define gst_vaapi_frame_store_replace(old_fs_p, new_fs)                 \
+    gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_fs_p),    \
+        (GstVaapiMiniObject *)(new_fs))
+
+/* ------------------------------------------------------------------------- */
+/* --- H.265 Decoder                                                     --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_DECODER_H265_CAST(decoder) \
+    ((GstVaapiDecoderH265 *)(decoder))
+
+typedef enum
+{
+  GST_H265_VIDEO_STATE_GOT_VPS = 1 << 0,
+  GST_H265_VIDEO_STATE_GOT_SPS = 1 << 1,
+  GST_H265_VIDEO_STATE_GOT_PPS = 1 << 2,
+  GST_H265_VIDEO_STATE_GOT_SLICE = 1 << 3,
+  GST_H265_VIDEO_STATE_GOT_I_FRAME = 1 << 4,    /* persistent across SPS */
+  GST_H265_VIDEO_STATE_GOT_P_SLICE = 1 << 5,    /* predictive (all non-intra) */
+
+  GST_H265_VIDEO_STATE_VALID_PICTURE_HEADERS =
+      (GST_H265_VIDEO_STATE_GOT_SPS | GST_H265_VIDEO_STATE_GOT_PPS),
+  GST_H265_VIDEO_STATE_VALID_PICTURE =
+      (GST_H265_VIDEO_STATE_VALID_PICTURE_HEADERS |
+      GST_H265_VIDEO_STATE_GOT_SLICE)
+} GstH265VideoState;
+
+struct _GstVaapiDecoderH265Private
+{
+  GstH265Parser *parser;
+  guint parser_state;
+  guint decoder_state;
+  GstVaapiStreamAlignH265 stream_alignment;
+  GstVaapiPictureH265 *current_picture;
+  GstVaapiParserInfoH265 *vps[GST_H265_MAX_VPS_COUNT];
+  GstVaapiParserInfoH265 *active_vps;
+  GstVaapiParserInfoH265 *sps[GST_H265_MAX_SPS_COUNT];
+  GstVaapiParserInfoH265 *active_sps;
+  GstVaapiParserInfoH265 *pps[GST_H265_MAX_PPS_COUNT];
+  GstVaapiParserInfoH265 *active_pps;
+  GstVaapiParserInfoH265 *prev_pi;
+  GstVaapiParserInfoH265 *prev_slice_pi;
+  GstVaapiParserInfoH265 *prev_independent_slice_pi;
+  GstVaapiFrameStore **dpb;
+  guint dpb_count;
+  guint dpb_size;
+  guint dpb_size_max;
+  GstVaapiProfile profile;
+  GstVaapiEntrypoint entrypoint;
+  GstVaapiChromaType chroma_type;
+
+  GstVaapiPictureH265 *RefPicSetStCurrBefore[16];
+  GstVaapiPictureH265 *RefPicSetStCurrAfter[16];
+  GstVaapiPictureH265 *RefPicSetStFoll[16];
+  GstVaapiPictureH265 *RefPicSetLtCurr[16];
+  GstVaapiPictureH265 *RefPicSetLtFoll[16];
+
+  GstVaapiPictureH265 *RefPicList0[16];
+  guint RefPicList0_count;
+  GstVaapiPictureH265 *RefPicList1[16];
+  guint RefPicList1_count;
+
+  guint32 SpsMaxLatencyPictures;
+  gint32 WpOffsetHalfRangeC;
+
+  guint nal_length_size;
+
+  guint pic_width_in_luma_samples;      //sps->pic_width_in_luma_samples
+  guint pic_height_in_luma_samples;     //sps->pic_height_in_luma_samples
+  guint pic_structure;          // pic_struct (from SEI pic_timing() or inferred)
+  gint32 poc;                   // PicOrderCntVal
+  gint32 poc_msb;               // PicOrderCntMsb
+  gint32 poc_lsb;               // pic_order_cnt_lsb (from slice_header())
+  gint32 prev_poc_msb;          // prevPicOrderCntMsb
+  gint32 prev_poc_lsb;          // prevPicOrderCntLsb
+  gint32 prev_tid0pic_poc_lsb;
+  gint32 prev_tid0pic_poc_msb;
+  gint32 PocStCurrBefore[16];
+  gint32 PocStCurrAfter[16];
+  gint32 PocStFoll[16];
+  gint32 PocLtCurr[16];
+  gint32 PocLtFoll[16];
+  guint NumPocStCurrBefore;
+  guint NumPocStCurrAfter;
+  guint NumPocStFoll;
+  guint NumPocLtCurr;
+  guint NumPocLtFoll;
+  guint NumPocTotalCurr;
+  guint is_opened:1;
+  guint is_hvcC:1;
+  guint has_context:1;
+  guint progressive_sequence:1;
+  guint new_bitstream:1;
+  guint prev_nal_is_eos:1;      /*previous nal type is EOS */
+  guint associated_irap_NoRaslOutputFlag:1;
+};
+
+/**
+ * GstVaapiDecoderH265:
+ *
+ * A decoder based on H265.
+ */
+struct _GstVaapiDecoderH265
+{
+  /*< private > */
+  GstVaapiDecoder parent_instance;
+  GstVaapiDecoderH265Private priv;
+};
+
+/**
+ * GstVaapiDecoderH265Class:
+ *
+ * A decoder class based on H265.
+ */
+struct _GstVaapiDecoderH265Class
+{
+  /*< private > */
+  GstVaapiDecoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiDecoderH265, gst_vaapi_decoder_h265,
+    GST_TYPE_VAAPI_DECODER);
+
+#define RSV_VCL_N10 10
+#define RSV_VCL_N12 12
+#define RSV_VCL_N14 14
+
+static gboolean
+nal_is_idr (guint8 nal_type)
+{
+  if ((nal_type == GST_H265_NAL_SLICE_IDR_W_RADL) ||
+      (nal_type == GST_H265_NAL_SLICE_IDR_N_LP))
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
+nal_is_irap (guint8 nal_type)
+{
+  if ((nal_type >= GST_H265_NAL_SLICE_BLA_W_LP) &&
+      (nal_type <= RESERVED_IRAP_NAL_TYPE_MAX))
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
+nal_is_bla (guint8 nal_type)
+{
+  if ((nal_type >= GST_H265_NAL_SLICE_BLA_W_LP) &&
+      (nal_type <= GST_H265_NAL_SLICE_BLA_N_LP))
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
+nal_is_cra (guint8 nal_type)
+{
+  if (nal_type == GST_H265_NAL_SLICE_CRA_NUT)
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
+nal_is_radl (guint8 nal_type)
+{
+  if ((nal_type >= GST_H265_NAL_SLICE_RADL_N) &&
+      (nal_type <= GST_H265_NAL_SLICE_RADL_R))
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
+nal_is_rasl (guint8 nal_type)
+{
+  if ((nal_type >= GST_H265_NAL_SLICE_RASL_N) &&
+      (nal_type <= GST_H265_NAL_SLICE_RASL_R))
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
+nal_is_slice (guint8 nal_type)
+{
+  if ((nal_type >= GST_H265_NAL_SLICE_TRAIL_N) &&
+      (nal_type <= GST_H265_NAL_SLICE_CRA_NUT))
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
+nal_is_ref (guint8 nal_type)
+{
+  gboolean ret = FALSE;
+  switch (nal_type) {
+    case GST_H265_NAL_SLICE_TRAIL_N:
+    case GST_H265_NAL_SLICE_TSA_N:
+    case GST_H265_NAL_SLICE_STSA_N:
+    case GST_H265_NAL_SLICE_RADL_N:
+    case GST_H265_NAL_SLICE_RASL_N:
+    case RSV_VCL_N10:
+    case RSV_VCL_N12:
+    case RSV_VCL_N14:
+      ret = FALSE;
+      break;
+    default:
+      ret = TRUE;
+      break;
+  }
+  return ret;
+}
+
+static gboolean
+is_range_extension_profile (GstVaapiProfile profile)
+{
+  if (profile == GST_VAAPI_PROFILE_H265_MAIN_422_10
+      || profile == GST_VAAPI_PROFILE_H265_MAIN_444
+      || profile == GST_VAAPI_PROFILE_H265_MAIN_444_10
+      || profile == GST_VAAPI_PROFILE_H265_MAIN12
+      || profile == GST_VAAPI_PROFILE_H265_MAIN_444_12
+      || profile == GST_VAAPI_PROFILE_H265_MAIN_422_12)
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
+is_scc_profile (GstVaapiProfile profile)
+{
+#if VA_CHECK_VERSION(1,2,0)
+  if (profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN
+      || profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10
+      || profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444
+#if VA_CHECK_VERSION(1,8,0)
+      || profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10
+#endif
+      )
+    return TRUE;
+#endif
+  return FALSE;
+}
+
+static inline GstVaapiPictureH265 *
+gst_vaapi_picture_h265_new (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  if (is_range_extension_profile (priv->profile)
+      || is_scc_profile (priv->profile)) {
+#if VA_CHECK_VERSION(1,2,0)
+    return (GstVaapiPictureH265 *)
+        gst_vaapi_codec_object_new (&GstVaapiPictureH265Class,
+        GST_VAAPI_CODEC_BASE (decoder), NULL,
+        sizeof (VAPictureParameterBufferHEVCExtension), NULL, 0, 0);
+#endif
+    return NULL;
+  } else {
+    return (GstVaapiPictureH265 *)
+        gst_vaapi_codec_object_new (&GstVaapiPictureH265Class,
+        GST_VAAPI_CODEC_BASE (decoder), NULL,
+        sizeof (VAPictureParameterBufferHEVC), NULL, 0, 0);
+  }
+}
+
+/* Activates the supplied PPS */
+static GstH265PPS *
+ensure_pps (GstVaapiDecoderH265 * decoder, GstH265PPS * pps)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = priv->pps[pps->id];
+
+  gst_vaapi_parser_info_h265_replace (&priv->active_pps, pi);
+
+  /* Ensure our copy is up-to-date */
+  if (pi) {
+    pi->data.pps = *pps;
+    pi->data.pps.sps = NULL;
+  }
+
+  return pi ? &pi->data.pps : NULL;
+}
+
+/* Returns the active PPS */
+static inline GstH265PPS *
+get_pps (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiParserInfoH265 *const pi = decoder->priv.active_pps;
+
+  return pi ? &pi->data.pps : NULL;
+}
+
+/* Activate the supplied SPS */
+static GstH265SPS *
+ensure_sps (GstVaapiDecoderH265 * decoder, GstH265SPS * sps)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = priv->sps[sps->id];
+
+  /* Propagate "got I-frame" state to the next SPS unit if the current
+   * sequence was not ended */
+  if (pi && priv->active_sps)
+    pi->state |= (priv->active_sps->state & GST_H265_VIDEO_STATE_GOT_I_FRAME);
+
+  /* Ensure our copy is up-to-date */
+  if (pi)
+    pi->data.sps = *sps;
+
+  gst_vaapi_parser_info_h265_replace (&priv->active_sps, pi);
+  return pi ? &pi->data.sps : NULL;
+}
+
+/* Returns the active SPS */
+static inline GstH265SPS *
+get_sps (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiParserInfoH265 *const pi = decoder->priv.active_sps;
+
+  return pi ? &pi->data.sps : NULL;
+}
+
+/* VPS nal is not necessary to decode the base layers, so this is not
+ * needed at the moment. But in future we need this, especially when
+ * dealing with MVC and scalable layer decoding.
+ * See https://bugzilla.gnome.org/show_bug.cgi?id=754250
+ */
+#if 0
+/* Activate the supplied VPS */
+static GstH265VPS *
+ensure_vps (GstVaapiDecoderH265 * decoder, GstH265VPS * vps)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = priv->vps[vps->id];
+
+  gst_vaapi_parser_info_h265_replace (&priv->active_vps, pi);
+  return pi ? &pi->data.vps : NULL;
+}
+
+/* Returns the active VPS */
+static inline GstH265VPS *
+get_vps (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiParserInfoH265 *const pi = decoder->priv.active_vps;
+  return pi ? &pi->data.vps : NULL;
+}
+#endif
+
+/* Get number of reference frames to use */
+static guint
+get_max_dec_frame_buffering (GstH265SPS * sps)
+{
+  G_GNUC_UNUSED guint max_dec_frame_buffering;  /* FIXME */
+  GstVaapiLevelH265 level;
+  const GstVaapiH265LevelLimits *level_limits;
+
+  level = gst_vaapi_utils_h265_get_level (sps->profile_tier_level.level_idc);
+  level_limits = gst_vaapi_utils_h265_get_level_limits (level);
+  if (G_UNLIKELY (!level_limits)) {
+    GST_FIXME ("unsupported level_idc value (%d)",
+        sps->profile_tier_level.level_idc);
+    max_dec_frame_buffering = 16;
+  }
+
+  /* FIXME: Add limit check based on Annex A */
+
+  /* Assuming HighestTid as sps_max_sub_layers_minus1 */
+  return MAX (1,
+      (sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1] + 1));
+}
+
+static void
+dpb_remove_all (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+
+  while (priv->dpb_count > 0)
+    gst_vaapi_frame_store_replace (&priv->dpb[--priv->dpb_count], NULL);
+}
+
+static void
+dpb_remove_index (GstVaapiDecoderH265 * decoder, gint index)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  guint i, num_frames = --priv->dpb_count;
+
+  if (USE_STRICT_DPB_ORDERING) {
+    for (i = index; i < num_frames; i++)
+      gst_vaapi_frame_store_replace (&priv->dpb[i], priv->dpb[i + 1]);
+  } else if (index != num_frames)
+    gst_vaapi_frame_store_replace (&priv->dpb[index], priv->dpb[num_frames]);
+  gst_vaapi_frame_store_replace (&priv->dpb[num_frames], NULL);
+}
+
+static gboolean
+dpb_output (GstVaapiDecoderH265 * decoder, GstVaapiFrameStore * fs)
+{
+  GstVaapiPictureH265 *picture;
+
+  g_return_val_if_fail (fs != NULL, FALSE);
+
+  picture = fs->buffer;
+  if (!picture)
+    return FALSE;
+
+  picture->output_needed = FALSE;
+  return gst_vaapi_picture_output (GST_VAAPI_PICTURE_CAST (picture));
+}
+
+/* Get the dpb picture having the specifed poc or poc_lsb */
+static GstVaapiPictureH265 *
+dpb_get_picture (GstVaapiDecoderH265 * decoder, gint poc, gboolean match_lsb)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  guint i;
+
+  for (i = 0; i < priv->dpb_count; i++) {
+    GstVaapiPictureH265 *const picture = priv->dpb[i]->buffer;
+
+    if (picture && GST_VAAPI_PICTURE_FLAG_IS_SET (picture,
+            GST_VAAPI_PICTURE_FLAGS_REFERENCE)) {
+      if (match_lsb) {
+        if (picture->poc_lsb == poc)
+          return picture;
+      } else {
+        if (picture->poc == poc)
+          return picture;
+      }
+    }
+  }
+  return NULL;
+}
+
+/* Get the dpb picture having the specifed poc and shor/long ref flags */
+static GstVaapiPictureH265 *
+dpb_get_ref_picture (GstVaapiDecoderH265 * decoder, gint poc, gboolean is_short)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  guint i;
+
+  for (i = 0; i < priv->dpb_count; i++) {
+    GstVaapiPictureH265 *const picture = priv->dpb[i]->buffer;
+
+    if (picture && picture->poc == poc) {
+      if (is_short && GST_VAAPI_PICTURE_IS_SHORT_TERM_REFERENCE (picture))
+        return picture;
+      else if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (picture))
+        return picture;
+    }
+  }
+
+  return NULL;
+}
+
+/* Finds the picture with the lowest POC that needs to be output */
+static gint
+dpb_find_lowest_poc (GstVaapiDecoderH265 * decoder,
+    GstVaapiPictureH265 ** found_picture_ptr)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiPictureH265 *found_picture = NULL;
+  guint i, found_index = -1;
+
+  for (i = 0; i < priv->dpb_count; i++) {
+    GstVaapiPictureH265 *const picture = priv->dpb[i]->buffer;
+    if (picture && !picture->output_needed)
+      continue;
+    if (picture && (!found_picture || found_picture->poc > picture->poc)) {
+      found_picture = picture;
+      found_index = i;
+    }
+  }
+
+  if (found_picture_ptr)
+    *found_picture_ptr = found_picture;
+  return found_index;
+}
+
+static gboolean
+dpb_bump (GstVaapiDecoderH265 * decoder, GstVaapiPictureH265 * picture)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiPictureH265 *found_picture;
+  gint found_index;
+  gboolean success;
+
+  found_index = dpb_find_lowest_poc (decoder, &found_picture);
+  if (found_index < 0)
+    return FALSE;
+
+  success = dpb_output (decoder, priv->dpb[found_index]);
+
+  if (!gst_vaapi_frame_store_has_reference (priv->dpb[found_index]))
+    dpb_remove_index (decoder, found_index);
+
+  return success;
+}
+
+static void
+dpb_clear (GstVaapiDecoderH265 * decoder, gboolean hard_flush)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiPictureH265 *pic;
+  guint i;
+
+  if (hard_flush) {
+    dpb_remove_all (decoder);
+  } else {
+    /* Remove unused pictures from DPB */
+    i = 0;
+    while (i < priv->dpb_count) {
+      GstVaapiFrameStore *const fs = priv->dpb[i];
+      pic = fs->buffer;
+      if (!pic->output_needed && !gst_vaapi_frame_store_has_reference (fs))
+        dpb_remove_index (decoder, i);
+      else
+        i++;
+    }
+  }
+}
+
+static void
+dpb_flush (GstVaapiDecoderH265 * decoder)
+{
+  /* Output any frame remaining in DPB */
+  while (dpb_bump (decoder, NULL));
+  dpb_clear (decoder, TRUE);
+}
+
+static gint
+dpb_get_num_need_output (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  guint i = 0, n_output_needed = 0;
+
+  while (i < priv->dpb_count) {
+    GstVaapiFrameStore *const fs = priv->dpb[i];
+    if (fs->buffer->output_needed)
+      n_output_needed++;
+    i++;
+  }
+
+  return n_output_needed;
+}
+
+static gboolean
+check_latency_cnt (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiPictureH265 *tmp_pic;
+  guint i = 0;
+
+  while (i < priv->dpb_count) {
+    GstVaapiFrameStore *const fs = priv->dpb[i];
+    tmp_pic = fs->buffer;
+    if (tmp_pic->output_needed) {
+      if (tmp_pic->pic_latency_cnt >= priv->SpsMaxLatencyPictures)
+        return TRUE;
+    }
+    i++;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+dpb_add (GstVaapiDecoderH265 * decoder, GstVaapiPictureH265 * picture)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstH265SPS *const sps = get_sps (decoder);
+  GstVaapiFrameStore *fs;
+  GstVaapiPictureH265 *tmp_pic;
+  guint i = 0;
+
+  /* C.5.2.3 */
+  if (picture->output_flag) {
+    while (i < priv->dpb_count) {
+      GstVaapiFrameStore *const fs = priv->dpb[i];
+      tmp_pic = fs->buffer;
+      if (tmp_pic->output_needed)
+        tmp_pic->pic_latency_cnt += 1;
+      i++;
+    }
+  }
+
+  /* Create new frame store */
+  fs = gst_vaapi_frame_store_new (picture);
+  if (!fs)
+    return FALSE;
+  gst_vaapi_frame_store_replace (&priv->dpb[priv->dpb_count++], fs);
+  gst_vaapi_frame_store_unref (fs);
+
+  if (picture->output_flag) {
+    picture->output_needed = 1;
+    picture->pic_latency_cnt = 0;
+  } else
+    picture->output_needed = 0;
+
+  /* set pic as short_term_ref */
+  gst_vaapi_picture_h265_set_reference (picture,
+      GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE);
+
+  /* C.5.2.4 "Bumping" process */
+  while ((dpb_get_num_need_output (decoder) >
+          sps->max_num_reorder_pics[sps->max_sub_layers_minus1])
+      || (sps->max_latency_increase_plus1[sps->max_sub_layers_minus1]
+          && check_latency_cnt (decoder)))
+    dpb_bump (decoder, picture);
+
+  return TRUE;
+}
+
+
+/* C.5.2.2 */
+static gboolean
+dpb_init (GstVaapiDecoderH265 * decoder, GstVaapiPictureH265 * picture,
+    GstVaapiParserInfoH265 * pi)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstH265SPS *const sps = get_sps (decoder);
+
+  if (nal_is_irap (pi->nalu.type)
+      && picture->NoRaslOutputFlag && !priv->new_bitstream) {
+
+    if (pi->nalu.type == GST_H265_NAL_SLICE_CRA_NUT)
+      picture->NoOutputOfPriorPicsFlag = 1;
+    else
+      picture->NoOutputOfPriorPicsFlag =
+          slice_hdr->no_output_of_prior_pics_flag;
+
+    if (picture->NoOutputOfPriorPicsFlag)
+      dpb_clear (decoder, TRUE);
+    else {
+      dpb_clear (decoder, FALSE);
+      while (dpb_bump (decoder, NULL));
+    }
+  } else {
+    dpb_clear (decoder, FALSE);
+    while ((dpb_get_num_need_output (decoder) >
+            sps->max_num_reorder_pics[sps->max_sub_layers_minus1])
+        || (sps->max_latency_increase_plus1[sps->max_sub_layers_minus1]
+            && check_latency_cnt (decoder))
+        || (priv->dpb_count >=
+            (sps->max_dec_pic_buffering_minus1[sps->max_sub_layers_minus1] +
+                1))) {
+      dpb_bump (decoder, picture);
+    }
+  }
+
+  return TRUE;
+}
+
+static gboolean
+dpb_reset (GstVaapiDecoderH265 * decoder, guint dpb_size)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+
+  if (dpb_size > priv->dpb_size_max) {
+    priv->dpb = g_try_realloc_n (priv->dpb, dpb_size, sizeof (*priv->dpb));
+    if (!priv->dpb)
+      return FALSE;
+    memset (&priv->dpb[priv->dpb_size_max], 0,
+        (dpb_size - priv->dpb_size_max) * sizeof (*priv->dpb));
+    priv->dpb_size_max = dpb_size;
+  }
+  priv->dpb_size = dpb_size;
+  GST_DEBUG ("DPB size %u", priv->dpb_size);
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+get_status (GstH265ParserResult result)
+{
+  GstVaapiDecoderStatus status;
+
+  switch (result) {
+    case GST_H265_PARSER_OK:
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+    case GST_H265_PARSER_NO_NAL_END:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+      break;
+    case GST_H265_PARSER_ERROR:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+      break;
+    default:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+      break;
+  }
+  return status;
+}
+
+static void
+gst_vaapi_decoder_h265_close (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  gst_vaapi_parser_info_h265_replace (&priv->prev_slice_pi, NULL);
+  gst_vaapi_parser_info_h265_replace (&priv->prev_independent_slice_pi, NULL);
+  gst_vaapi_parser_info_h265_replace (&priv->prev_pi, NULL);
+
+  dpb_clear (decoder, TRUE);
+
+  if (priv->parser) {
+    gst_h265_parser_free (priv->parser);
+    priv->parser = NULL;
+  }
+
+  priv->is_opened = FALSE;
+}
+
+static gboolean
+gst_vaapi_decoder_h265_open (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_h265_close (decoder);
+  priv->parser = gst_h265_parser_new ();
+  if (!priv->parser)
+    return FALSE;
+  return TRUE;
+}
+
+static void
+gst_vaapi_decoder_h265_destroy (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderH265 *const decoder =
+      GST_VAAPI_DECODER_H265_CAST (base_decoder);
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  guint i;
+
+  gst_vaapi_decoder_h265_close (decoder);
+  g_clear_pointer (&priv->dpb, g_free);
+  priv->dpb_count = priv->dpb_size_max = priv->dpb_size = 0;
+
+  for (i = 0; i < G_N_ELEMENTS (priv->pps); i++)
+    gst_vaapi_parser_info_h265_replace (&priv->pps[i], NULL);
+  gst_vaapi_parser_info_h265_replace (&priv->active_pps, NULL);
+  for (i = 0; i < G_N_ELEMENTS (priv->sps); i++)
+    gst_vaapi_parser_info_h265_replace (&priv->sps[i], NULL);
+  gst_vaapi_parser_info_h265_replace (&priv->active_sps, NULL);
+  for (i = 0; i < G_N_ELEMENTS (priv->vps); i++)
+    gst_vaapi_parser_info_h265_replace (&priv->vps[i], NULL);
+  gst_vaapi_parser_info_h265_replace (&priv->active_vps, NULL);
+}
+
+static gboolean
+gst_vaapi_decoder_h265_create (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderH265 *const decoder =
+      GST_VAAPI_DECODER_H265_CAST (base_decoder);
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+
+  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  priv->entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+  priv->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+  priv->progressive_sequence = TRUE;
+  priv->new_bitstream = TRUE;
+  priv->prev_nal_is_eos = FALSE;
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h265_reset (GstVaapiDecoder * base_decoder)
+{
+  gst_vaapi_decoder_h265_destroy (base_decoder);
+  gst_vaapi_decoder_h265_create (base_decoder);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+fill_profiles (GstVaapiProfile profiles[], guint * n_profiles_ptr,
+    GstVaapiProfile profile)
+{
+  guint n_profiles = *n_profiles_ptr;
+
+  profiles[n_profiles++] = profile;
+  switch (profile) {
+    case GST_VAAPI_PROFILE_H265_MAIN:
+      profiles[n_profiles++] = GST_VAAPI_PROFILE_H265_MAIN10;
+      break;
+    case GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE:
+      profiles[n_profiles++] = GST_VAAPI_PROFILE_H265_MAIN;
+      profiles[n_profiles++] = GST_VAAPI_PROFILE_H265_MAIN10;
+      break;
+    default:
+      break;
+  }
+  *n_profiles_ptr = n_profiles;
+}
+
+static GstVaapiProfile
+get_profile (GstVaapiDecoderH265 * decoder, GstH265SPS * sps, guint dpb_size)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiDisplay *const display = GST_VAAPI_DECODER_DISPLAY (decoder);
+  GstVaapiProfile profile, profiles[3];
+  guint i, n_profiles = 0;
+
+  profile = gst_vaapi_utils_h265_get_profile (sps);
+  if (!profile) {
+    /* HACK: This is a work-around to identify some main profile streams having wrong profile_idc.
+     * There are some wrongly encoded main profile streams(eg: ENTP_C_LG_3.bin) which doesn't
+     * have any of the profile_idc values mentioned in Annex-A, instead general_profile_idc
+     * has been set as zero and having general_profile_compatibility_flag[general_profile_idc]
+     * is TRUE. Assuming them as MAIN profile for now */
+    if (sps->profile_tier_level.profile_space == 0 &&
+        sps->profile_tier_level.profile_idc == 0 &&
+        sps->profile_tier_level.profile_compatibility_flag[0] == 1) {
+      GST_WARNING ("Wrong profile_idc, blindly setting it as main profile !!");
+      profile = GST_VAAPI_PROFILE_H265_MAIN;
+    } else
+      return GST_VAAPI_PROFILE_UNKNOWN;
+  }
+
+  fill_profiles (profiles, &n_profiles, profile);
+  switch (profile) {
+    case GST_VAAPI_PROFILE_H265_MAIN10:
+      if (sps->profile_tier_level.profile_compatibility_flag[1]) {      // A.2.3.2 (main profile)
+        fill_profiles (profiles, &n_profiles, GST_VAAPI_PROFILE_H265_MAIN);
+      }
+      break;
+    default:
+      break;
+  }
+
+  /* If the preferred profile (profiles[0]) matches one that we already
+     found, then just return it now instead of searching for it again */
+  if (profiles[0] == priv->profile)
+    return priv->profile;
+  for (i = 0; i < n_profiles; i++) {
+    if (gst_vaapi_display_has_decoder (display, profiles[i], priv->entrypoint))
+      return profiles[i];
+  }
+  return GST_VAAPI_PROFILE_UNKNOWN;
+}
+
+static GstVaapiDecoderStatus
+ensure_context (GstVaapiDecoderH265 * decoder, GstH265SPS * sps)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER_CAST (decoder);
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiContextInfo info;
+  GstVaapiProfile profile;
+  GstVaapiChromaType chroma_type;
+  gboolean reset_context = FALSE;
+  guint dpb_size;
+
+  dpb_size = get_max_dec_frame_buffering (sps);
+  if (priv->dpb_size < dpb_size) {
+    GST_DEBUG ("DPB size increased");
+    reset_context = TRUE;
+  }
+
+  profile = get_profile (decoder, sps, dpb_size);
+  if (!profile) {
+    GST_ERROR ("unsupported profile_idc %u",
+        sps->profile_tier_level.profile_idc);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  if (!priv->profile || (priv->profile != profile)) {
+    GST_DEBUG ("profile changed");
+    reset_context = TRUE;
+    priv->profile = profile;
+  }
+
+  chroma_type =
+      gst_vaapi_utils_h265_get_chroma_type (sps->chroma_format_idc,
+      sps->bit_depth_luma_minus8 + 8, sps->bit_depth_chroma_minus8 + 8);
+  if (!chroma_type) {
+    GST_ERROR ("unsupported chroma_format_idc %u", sps->chroma_format_idc);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
+  }
+
+  if (priv->chroma_type != chroma_type) {
+    GST_DEBUG ("chroma format changed");
+    reset_context = TRUE;
+    priv->chroma_type = chroma_type;
+  }
+
+  if (priv->pic_width_in_luma_samples != sps->pic_width_in_luma_samples ||
+      priv->pic_height_in_luma_samples != sps->pic_height_in_luma_samples) {
+    GST_DEBUG ("size changed");
+    reset_context = TRUE;
+    priv->pic_width_in_luma_samples = sps->pic_width_in_luma_samples;
+    priv->pic_height_in_luma_samples = sps->pic_height_in_luma_samples;
+  }
+
+  priv->progressive_sequence = 1;       /* FIXME */
+  gst_vaapi_decoder_set_interlaced (base_decoder, !priv->progressive_sequence);
+  gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder,
+      sps->vui_params.par_n, sps->vui_params.par_d);
+  if (!reset_context && priv->has_context)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* XXX: fix surface size when cropping is implemented */
+  info.profile = priv->profile;
+  info.entrypoint = priv->entrypoint;
+  info.chroma_type = priv->chroma_type;
+  info.width = sps->width;
+  info.height = sps->height;
+  info.ref_frames = dpb_size;
+
+  if (!gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  priv->has_context = TRUE;
+
+  /* Reset DPB */
+  if (!dpb_reset (decoder, dpb_size))
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+fill_iq_matrix_4x4 (VAIQMatrixBufferHEVC * iq_matrix,
+    GstH265ScalingList * scaling_list)
+{
+  guint i;
+
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList4x4) == 6);
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList4x4[0]) == 16);
+  for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList4x4); i++) {
+    gst_h265_quant_matrix_4x4_get_raster_from_uprightdiagonal
+        (iq_matrix->ScalingList4x4[i], scaling_list->scaling_lists_4x4[i]);
+  }
+}
+
+static void
+fill_iq_matrix_8x8 (VAIQMatrixBufferHEVC * iq_matrix,
+    GstH265ScalingList * scaling_list)
+{
+  guint i;
+
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList8x8) == 6);
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList8x8[0]) == 64);
+  for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList8x8); i++) {
+    gst_h265_quant_matrix_8x8_get_raster_from_uprightdiagonal
+        (iq_matrix->ScalingList8x8[i], scaling_list->scaling_lists_8x8[i]);
+  }
+}
+
+static void
+fill_iq_matrix_16x16 (VAIQMatrixBufferHEVC * iq_matrix,
+    GstH265ScalingList * scaling_list)
+{
+  guint i;
+
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList16x16) == 6);
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList16x16[0]) == 64);
+  for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList16x16); i++) {
+    gst_h265_quant_matrix_16x16_get_raster_from_uprightdiagonal
+        (iq_matrix->ScalingList16x16[i], scaling_list->scaling_lists_16x16[i]);
+  }
+}
+
+static void
+fill_iq_matrix_32x32 (VAIQMatrixBufferHEVC * iq_matrix,
+    GstH265ScalingList * scaling_list)
+{
+  guint i;
+
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList32x32) == 2);
+  g_assert (G_N_ELEMENTS (iq_matrix->ScalingList32x32[0]) == 64);
+  for (i = 0; i < G_N_ELEMENTS (iq_matrix->ScalingList32x32); i++) {
+    gst_h265_quant_matrix_32x32_get_raster_from_uprightdiagonal
+        (iq_matrix->ScalingList32x32[i], scaling_list->scaling_lists_32x32[i]);
+  }
+}
+
+static void
+fill_iq_matrix_dc_16x16 (VAIQMatrixBufferHEVC * iq_matrix,
+    GstH265ScalingList * scaling_list)
+{
+  guint i;
+
+  for (i = 0; i < 6; i++)
+    iq_matrix->ScalingListDC16x16[i] =
+        scaling_list->scaling_list_dc_coef_minus8_16x16[i] + 8;
+}
+
+static void
+fill_iq_matrix_dc_32x32 (VAIQMatrixBufferHEVC * iq_matrix,
+    GstH265ScalingList * scaling_list)
+{
+  guint i;
+
+  for (i = 0; i < 2; i++)
+    iq_matrix->ScalingListDC32x32[i] =
+        scaling_list->scaling_list_dc_coef_minus8_32x32[i] + 8;
+}
+
+static GstVaapiDecoderStatus
+ensure_quant_matrix (GstVaapiDecoderH265 * decoder,
+    GstVaapiPictureH265 * picture)
+{
+  GstVaapiPicture *const base_picture = &picture->base;
+  GstH265PPS *const pps = get_pps (decoder);
+  GstH265SPS *const sps = get_sps (decoder);
+  GstH265ScalingList *scaling_list = NULL;
+  VAIQMatrixBufferHEVC *iq_matrix;
+
+  if (pps &&
+      (pps->scaling_list_data_present_flag ||
+          (sps->scaling_list_enabled_flag
+              && !sps->scaling_list_data_present_flag)))
+    scaling_list = &pps->scaling_list;
+  else if (sps && sps->scaling_list_enabled_flag
+      && sps->scaling_list_data_present_flag)
+    scaling_list = &sps->scaling_list;
+  else
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  base_picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (HEVC, decoder);
+  if (!base_picture->iq_matrix) {
+    GST_ERROR ("failed to allocate IQ matrix");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  iq_matrix = base_picture->iq_matrix->param;
+
+  fill_iq_matrix_4x4 (iq_matrix, scaling_list);
+  fill_iq_matrix_8x8 (iq_matrix, scaling_list);
+  fill_iq_matrix_16x16 (iq_matrix, scaling_list);
+  fill_iq_matrix_32x32 (iq_matrix, scaling_list);
+  fill_iq_matrix_dc_16x16 (iq_matrix, scaling_list);
+  fill_iq_matrix_dc_32x32 (iq_matrix, scaling_list);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline gboolean
+is_valid_state (guint state, guint ref_state)
+{
+  return (state & ref_state) == ref_state;
+}
+
+static GstVaapiDecoderStatus
+decode_current_picture (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const sps_pi = decoder->priv.active_sps;
+  GstVaapiPictureH265 *const picture = priv->current_picture;
+
+  if (!is_valid_state (priv->decoder_state, GST_H265_VIDEO_STATE_VALID_PICTURE)) {
+    goto drop_frame;
+  }
+
+  priv->decoder_state |= sps_pi->state;
+  if (!(priv->decoder_state & GST_H265_VIDEO_STATE_GOT_I_FRAME)) {
+    const GstH265PPS *pps = get_pps (decoder);
+    /* 7.4.3.3.3: the picture is an IRAP picture, nuh_layer_id is equal to 0,
+       and pps_curr_pic_ref_enabled_flag is equal to 0, slice_type shall be
+       equal to 2(I Slice).
+       And F.8.3.4: Decoding process for reference picture lists construction
+       is invoked at the beginning of the decoding process for each P or B
+       slice.
+       so if pps_curr_pic_ref_enabled_flag is set, which means the picture can
+       ref to itself, the IRAP picture may be set to P/B slice, in order to
+       generate the ref lists. If the slice_type is I, no ref list will be
+       constructed and no MV data for that slice according to the syntax.
+       That kind of CVS may start with P/B slice, but in fact it is a intra
+       frame. */
+    if (priv->decoder_state & GST_H265_VIDEO_STATE_GOT_P_SLICE &&
+        !pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag)
+      goto drop_frame;
+    sps_pi->state |= GST_H265_VIDEO_STATE_GOT_I_FRAME;
+  }
+
+  priv->decoder_state = 0;
+  /* FIXME: Use SEI header values */
+  priv->pic_structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+
+  if (!picture)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_vaapi_picture_decode (GST_VAAPI_PICTURE_CAST (picture)))
+    goto error;
+
+  if (!dpb_add (decoder, picture))
+    goto error;
+
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+drop_frame:
+  {
+    priv->decoder_state = 0;
+    priv->pic_structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+    return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME;
+  }
+}
+
+static GstVaapiDecoderStatus
+parse_vps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GstH265VPS *const vps = &pi->data.vps;
+  GstH265ParserResult result;
+
+  GST_DEBUG ("parse VPS");
+  priv->parser_state = 0;
+
+  memset (vps, 0, sizeof (GstH265VPS));
+
+  result = gst_h265_parser_parse_vps (priv->parser, &pi->nalu, vps);
+  if (result != GST_H265_PARSER_OK)
+    return get_status (result);
+
+  priv->parser_state |= GST_H265_VIDEO_STATE_GOT_VPS;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_sps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GstH265SPS *const sps = &pi->data.sps;
+  GstH265ParserResult result;
+
+  GST_DEBUG ("parse SPS");
+  priv->parser_state = 0;
+
+  memset (sps, 0, sizeof (GstH265SPS));
+
+  result = gst_h265_parser_parse_sps (priv->parser, &pi->nalu, sps, TRUE);
+  if (result != GST_H265_PARSER_OK)
+    return get_status (result);
+
+  priv->parser_state |= GST_H265_VIDEO_STATE_GOT_SPS;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_pps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GstH265PPS *const pps = &pi->data.pps;
+  GstH265ParserResult result;
+
+  GST_DEBUG ("parse PPS");
+  priv->parser_state &= GST_H265_VIDEO_STATE_GOT_SPS;
+
+  memset (pps, 0, sizeof (GstH265PPS));
+
+  result = gst_h265_parser_parse_pps (priv->parser, &pi->nalu, pps);
+  if (result != GST_H265_PARSER_OK)
+    return get_status (result);
+
+  priv->parser_state |= GST_H265_VIDEO_STATE_GOT_PPS;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_sei (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GArray **const sei_ptr = &pi->data.sei;
+  GstH265ParserResult result;
+
+  GST_DEBUG ("parse SEI");
+
+  result = gst_h265_parser_parse_sei (priv->parser, &pi->nalu, sei_ptr);
+  if (result != GST_H265_PARSER_OK) {
+    GST_WARNING ("failed to parse SEI messages");
+    return get_status (result);
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_slice (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstH265ParserResult result;
+
+  GST_DEBUG ("parse slice");
+  priv->parser_state &= (GST_H265_VIDEO_STATE_GOT_SPS |
+      GST_H265_VIDEO_STATE_GOT_PPS);
+
+  slice_hdr->short_term_ref_pic_set_idx = 0;
+
+  memset (slice_hdr, 0, sizeof (GstH265SliceHdr));
+
+  result = gst_h265_parser_parse_slice_hdr (priv->parser, &pi->nalu, slice_hdr);
+  if (result != GST_H265_PARSER_OK)
+    return get_status (result);
+
+  priv->parser_state |= GST_H265_VIDEO_STATE_GOT_SLICE;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_vps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GstH265VPS *const vps = &pi->data.vps;
+
+  GST_DEBUG ("decode VPS");
+
+  gst_vaapi_parser_info_h265_replace (&priv->vps[vps->id], pi);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GstH265SPS *const sps = &pi->data.sps;
+  guint high_precision_offsets_enabled_flag = 0, bitdepthC = 0;
+
+  GST_DEBUG ("decode SPS");
+
+  if (sps->max_latency_increase_plus1[sps->max_sub_layers_minus1])
+    priv->SpsMaxLatencyPictures =
+        sps->max_num_reorder_pics[sps->max_sub_layers_minus1] +
+        sps->max_latency_increase_plus1[sps->max_sub_layers_minus1] - 1;
+
+  /* Calculate WpOffsetHalfRangeC: (7-34)
+   * FIXME: We don't have parser API for sps_range_extension, so
+   * assuming high_precision_offsets_enabled_flag as zero */
+  bitdepthC = sps->bit_depth_chroma_minus8 + 8;
+  priv->WpOffsetHalfRangeC =
+      1 << (high_precision_offsets_enabled_flag ? (bitdepthC - 1) : 7);
+
+  gst_vaapi_parser_info_h265_replace (&priv->sps[sps->id], pi);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_pps (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GstH265PPS *const pps = &pi->data.pps;
+
+  GST_DEBUG ("decode PPS");
+
+  gst_vaapi_parser_info_h265_replace (&priv->pps[pps->id], pi);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sei (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  guint i;
+
+  GST_DEBUG ("decode SEI messages");
+
+  for (i = 0; i < pi->data.sei->len; i++) {
+    const GstH265SEIMessage *const sei =
+        &g_array_index (pi->data.sei, GstH265SEIMessage, i);
+
+    switch (sei->payloadType) {
+      case GST_H265_SEI_PIC_TIMING:{
+        const GstH265PicTiming *const pic_timing = &sei->payload.pic_timing;
+        priv->pic_structure = pic_timing->pic_struct;
+        break;
+      }
+      default:
+        break;
+    }
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_end (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoderStatus status;
+  GstVaapiParserInfoH265 *const sps_pi = decoder->priv.active_sps;
+
+  GST_DEBUG ("decode sequence-end");
+
+  /* Sequence ended, don't try to propagate "got I-frame" state beyond
+   * this point */
+  if (sps_pi)
+    sps_pi->state &= ~GST_H265_VIDEO_STATE_GOT_I_FRAME;
+
+  status = decode_current_picture (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+/* 8.3.1 - Decoding process for picture order count */
+static void
+init_picture_poc (GstVaapiDecoderH265 * decoder,
+    GstVaapiPictureH265 * picture, GstVaapiParserInfoH265 * pi)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstH265SPS *const sps = get_sps (decoder);
+  const gint32 MaxPicOrderCntLsb =
+      1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
+  guint8 nal_type = pi->nalu.type;
+  guint8 temporal_id = pi->nalu.temporal_id_plus1 - 1;
+
+  GST_DEBUG ("decode PicOrderCntVal");
+
+  priv->prev_poc_lsb = priv->poc_lsb;
+  priv->prev_poc_msb = priv->poc_msb;
+
+  if (!(nal_is_irap (nal_type) && picture->NoRaslOutputFlag)) {
+    priv->prev_poc_lsb = priv->prev_tid0pic_poc_lsb;
+    priv->prev_poc_msb = priv->prev_tid0pic_poc_msb;
+  }
+
+  /* Finding PicOrderCntMsb */
+  if (nal_is_irap (nal_type) && picture->NoRaslOutputFlag)
+    priv->poc_msb = 0;
+  else {
+    /* (8-1) */
+    if ((slice_hdr->pic_order_cnt_lsb < priv->prev_poc_lsb) &&
+        ((priv->prev_poc_lsb - slice_hdr->pic_order_cnt_lsb) >=
+            (MaxPicOrderCntLsb / 2)))
+      priv->poc_msb = priv->prev_poc_msb + MaxPicOrderCntLsb;
+
+    else if ((slice_hdr->pic_order_cnt_lsb > priv->prev_poc_lsb) &&
+        ((slice_hdr->pic_order_cnt_lsb - priv->prev_poc_lsb) >
+            (MaxPicOrderCntLsb / 2)))
+      priv->poc_msb = priv->prev_poc_msb - MaxPicOrderCntLsb;
+
+    else
+      priv->poc_msb = priv->prev_poc_msb;
+  }
+
+  /* (8-2) */
+  priv->poc = picture->poc = priv->poc_msb + slice_hdr->pic_order_cnt_lsb;
+  priv->poc_lsb = picture->poc_lsb = slice_hdr->pic_order_cnt_lsb;
+
+  if (nal_is_idr (nal_type)) {
+    picture->poc = 0;
+    picture->poc_lsb = 0;
+    priv->poc_lsb = 0;
+    priv->poc_msb = 0;
+    priv->prev_poc_lsb = 0;
+    priv->prev_poc_msb = 0;
+    priv->prev_tid0pic_poc_lsb = 0;
+    priv->prev_tid0pic_poc_msb = 0;
+  }
+
+  picture->base.poc = picture->poc;
+  GST_DEBUG ("PicOrderCntVal %d", picture->base.poc);
+
+  if (!temporal_id && !nal_is_rasl (nal_type) &&
+      !nal_is_radl (nal_type) && nal_is_ref (nal_type)) {
+    priv->prev_tid0pic_poc_lsb = slice_hdr->pic_order_cnt_lsb;
+    priv->prev_tid0pic_poc_msb = priv->poc_msb;
+  }
+}
+
+static void
+init_picture_refs (GstVaapiDecoderH265 * decoder,
+    GstVaapiPictureH265 * picture, GstH265SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  guint32 NumRpsCurrTempList0 = 0, NumRpsCurrTempList1 = 0;
+  GstVaapiPictureH265 *RefPicListTemp0[16] = { NULL, };
+  GstVaapiPictureH265 *RefPicListTemp1[16] = { NULL, };
+  guint i, rIdx = 0;
+  guint num_ref_idx_l0_active_minus1 = 0;
+  guint num_ref_idx_l1_active_minus1 = 0;
+  GstH265RefPicListModification *ref_pic_list_modification;
+  GstH265PPS *const pps = get_pps (decoder);
+  guint type;
+
+  memset (priv->RefPicList0, 0, sizeof (GstVaapiPictureH265 *) * 16);
+  memset (priv->RefPicList1, 0, sizeof (GstVaapiPictureH265 *) * 16);
+  priv->RefPicList0_count = priv->RefPicList1_count = 0;
+
+  num_ref_idx_l0_active_minus1 = slice_hdr->num_ref_idx_l0_active_minus1;
+  num_ref_idx_l1_active_minus1 = slice_hdr->num_ref_idx_l1_active_minus1;
+  ref_pic_list_modification = &slice_hdr->ref_pic_list_modification;
+  type = slice_hdr->type;
+
+  /* decoding process for reference picture list construction needs to be
+   * invoked only for P and B slice */
+  if (type == GST_H265_I_SLICE)
+    return;
+
+  NumRpsCurrTempList0 =
+      MAX ((num_ref_idx_l0_active_minus1 + 1), priv->NumPocTotalCurr);
+  NumRpsCurrTempList1 =
+      MAX ((num_ref_idx_l1_active_minus1 + 1), priv->NumPocTotalCurr);
+
+  /* (8-8) */
+  while (rIdx < NumRpsCurrTempList0) {
+    for (i = 0; i < priv->NumPocStCurrBefore && rIdx < NumRpsCurrTempList0;
+        rIdx++, i++)
+      RefPicListTemp0[rIdx] = priv->RefPicSetStCurrBefore[i];
+    for (i = 0; i < priv->NumPocStCurrAfter && rIdx < NumRpsCurrTempList0;
+        rIdx++, i++)
+      RefPicListTemp0[rIdx] = priv->RefPicSetStCurrAfter[i];
+    for (i = 0; i < priv->NumPocLtCurr && rIdx < NumRpsCurrTempList0;
+        rIdx++, i++)
+      RefPicListTemp0[rIdx] = priv->RefPicSetLtCurr[i];
+    if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag)
+      RefPicListTemp0[rIdx++] = picture;
+  }
+
+  /* construct RefPicList0 (8-9) */
+  for (rIdx = 0; rIdx <= num_ref_idx_l0_active_minus1; rIdx++)
+    priv->RefPicList0[rIdx] =
+        ref_pic_list_modification->ref_pic_list_modification_flag_l0 ?
+        RefPicListTemp0[ref_pic_list_modification->list_entry_l0[rIdx]] :
+        RefPicListTemp0[rIdx];
+  if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag
+      && !ref_pic_list_modification->ref_pic_list_modification_flag_l0
+      && (NumRpsCurrTempList0 > num_ref_idx_l0_active_minus1 + 1))
+    priv->RefPicList0[num_ref_idx_l0_active_minus1] = picture;
+  priv->RefPicList0_count = rIdx;
+
+  if (type == GST_H265_B_SLICE) {
+    rIdx = 0;
+
+    /* (8-10) */
+    while (rIdx < NumRpsCurrTempList1) {
+      for (i = 0; i < priv->NumPocStCurrAfter && rIdx < NumRpsCurrTempList1;
+          rIdx++, i++)
+        RefPicListTemp1[rIdx] = priv->RefPicSetStCurrAfter[i];
+      for (i = 0; i < priv->NumPocStCurrBefore && rIdx < NumRpsCurrTempList1;
+          rIdx++, i++)
+        RefPicListTemp1[rIdx] = priv->RefPicSetStCurrBefore[i];
+      for (i = 0; i < priv->NumPocLtCurr && rIdx < NumRpsCurrTempList1;
+          rIdx++, i++)
+        RefPicListTemp1[rIdx] = priv->RefPicSetLtCurr[i];
+      if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag)
+        RefPicListTemp1[rIdx++] = picture;
+    }
+
+    /* construct RefPicList1 (8-10) */
+    for (rIdx = 0; rIdx <= num_ref_idx_l1_active_minus1; rIdx++)
+      priv->RefPicList1[rIdx] =
+          ref_pic_list_modification->ref_pic_list_modification_flag_l1 ?
+          RefPicListTemp1[ref_pic_list_modification->list_entry_l1
+          [rIdx]] : RefPicListTemp1[rIdx];
+    priv->RefPicList1_count = rIdx;
+  }
+}
+
+static gboolean
+init_picture (GstVaapiDecoderH265 * decoder,
+    GstVaapiPictureH265 * picture, GstVaapiParserInfoH265 * pi)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiPicture *const base_picture = &picture->base;
+  GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+
+  base_picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
+  base_picture->type = GST_VAAPI_PICTURE_TYPE_NONE;
+
+  if (nal_is_idr (pi->nalu.type)) {
+    GST_DEBUG ("<IDR>");
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_IDR);
+  }
+
+  if (pi->nalu.type >= GST_H265_NAL_SLICE_BLA_W_LP &&
+      pi->nalu.type <= GST_H265_NAL_SLICE_CRA_NUT)
+    picture->RapPicFlag = TRUE;
+
+  /* FIXME: Use SEI header values */
+  base_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+  picture->structure = base_picture->structure;
+
+  /*NoRaslOutputFlag ==1 if the current picture is
+     1) an IDR picture
+     2) a BLA picture
+     3) a CRA picture that is the first access unit in the bitstream
+     4) first picture that follows an end of sequence NAL unit in decoding order
+     5) has HandleCraAsBlaFlag == 1 (set by external means, so not considering )
+   */
+  if (nal_is_idr (pi->nalu.type) || nal_is_bla (pi->nalu.type) ||
+      (nal_is_cra (pi->nalu.type) && priv->new_bitstream)
+      || priv->prev_nal_is_eos) {
+    picture->NoRaslOutputFlag = 1;
+  }
+
+  if (nal_is_irap (pi->nalu.type)) {
+    picture->IntraPicFlag = TRUE;
+    priv->associated_irap_NoRaslOutputFlag = picture->NoRaslOutputFlag;
+  }
+
+  if (nal_is_rasl (pi->nalu.type) && priv->associated_irap_NoRaslOutputFlag)
+    picture->output_flag = FALSE;
+  else
+    picture->output_flag = slice_hdr->pic_output_flag;
+
+  init_picture_poc (decoder, picture, pi);
+
+  return TRUE;
+}
+
+static void
+vaapi_init_picture (VAPictureHEVC * pic)
+{
+  pic->picture_id = VA_INVALID_SURFACE;
+  pic->pic_order_cnt = 0;
+  pic->flags = VA_PICTURE_HEVC_INVALID;
+}
+
+static void
+vaapi_fill_picture (VAPictureHEVC * pic, GstVaapiPictureH265 * picture,
+    guint picture_structure)
+{
+
+  if (!picture_structure)
+    picture_structure = picture->structure;
+
+  pic->picture_id = picture->base.surface_id;
+  pic->pic_order_cnt = picture->poc;
+  pic->flags = 0;
+
+  /* Set the VAPictureHEVC flags */
+  if (GST_VAAPI_PICTURE_IS_LONG_TERM_REFERENCE (picture))
+    pic->flags |= VA_PICTURE_HEVC_LONG_TERM_REFERENCE;
+
+  if (GST_VAAPI_PICTURE_FLAG_IS_SET (picture,
+          GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE))
+    pic->flags |= VA_PICTURE_HEVC_RPS_ST_CURR_BEFORE;
+
+  else if (GST_VAAPI_PICTURE_FLAG_IS_SET (picture,
+          GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER))
+    pic->flags |= VA_PICTURE_HEVC_RPS_ST_CURR_AFTER;
+
+  else if (GST_VAAPI_PICTURE_FLAG_IS_SET (picture,
+          GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR))
+    pic->flags |= VA_PICTURE_HEVC_RPS_LT_CURR;
+
+  switch (picture_structure) {
+    case GST_VAAPI_PICTURE_STRUCTURE_FRAME:
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
+      pic->flags |= VA_PICTURE_HEVC_FIELD_PIC;
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
+      pic->flags |= VA_PICTURE_HEVC_FIELD_PIC;
+      pic->flags |= VA_PICTURE_HEVC_BOTTOM_FIELD;
+      break;
+    default:
+      break;
+  }
+}
+
+static guint
+get_index_for_RefPicListX (VAPictureHEVC * ReferenceFrames,
+    GstVaapiPictureH265 * pic)
+{
+  gint i;
+
+  for (i = 0; i < 15; i++) {
+    if ((ReferenceFrames[i].picture_id != VA_INVALID_ID) && pic) {
+      if ((ReferenceFrames[i].pic_order_cnt == pic->poc) &&
+          (ReferenceFrames[i].picture_id == pic->base.surface_id)) {
+        return i;
+      }
+    }
+  }
+  return 0xff;
+}
+
+static gboolean
+fill_picture (GstVaapiDecoderH265 * decoder, GstVaapiPictureH265 * picture,
+    GstVaapiParserInfoH265 * pi)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiPicture *const base_picture = &picture->base;
+  GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstH265PPS *const pps = get_pps (decoder);
+  GstH265SPS *const sps = get_sps (decoder);
+  VAPictureParameterBufferHEVC *pic_param = base_picture->param;
+  guint i, n;
+
+#if VA_CHECK_VERSION(1,2,0)
+  VAPictureParameterBufferHEVCRext *pic_rext_param = NULL;
+  VAPictureParameterBufferHEVCScc *pic_scc_param = NULL;
+  if (is_range_extension_profile (priv->profile)) {
+    VAPictureParameterBufferHEVCExtension *param = base_picture->param;
+    pic_param = &param->base;
+    pic_rext_param = &param->rext;
+  }
+  if (is_scc_profile (priv->profile)) {
+    VAPictureParameterBufferHEVCExtension *param = base_picture->param;
+    pic_param = &param->base;
+    pic_rext_param = &param->rext;
+    pic_scc_param = &param->scc;
+  }
+#endif
+
+  pic_param->pic_fields.value = 0;
+  pic_param->slice_parsing_fields.value = 0;
+
+  /* Fill in VAPictureHEVC */
+  vaapi_fill_picture (&pic_param->CurrPic, picture, 0);
+  /* Fill in ReferenceFrames */
+  for (i = 0, n = 0; i < priv->dpb_count; i++) {
+    GstVaapiFrameStore *const fs = priv->dpb[i];
+    if ((gst_vaapi_frame_store_has_reference (fs)))
+      vaapi_fill_picture (&pic_param->ReferenceFrames[n++], fs->buffer,
+          fs->buffer->structure);
+    if (n >= G_N_ELEMENTS (pic_param->ReferenceFrames))
+      break;
+  }
+  /* 7.4.3.3.3, the current decoded picture is marked as "used for
+     long-term reference", no matter TwoVersionsOfCurrDecPicFlag */
+  if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag
+      && n < G_N_ELEMENTS (pic_param->ReferenceFrames) - 1) {
+    gst_vaapi_picture_h265_set_reference (picture,
+        GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE);
+    vaapi_fill_picture (&pic_param->ReferenceFrames[n++], picture,
+        picture->structure);
+    gst_vaapi_picture_h265_set_reference (picture, 0);
+  }
+
+  for (; n < G_N_ELEMENTS (pic_param->ReferenceFrames); n++)
+    vaapi_init_picture (&pic_param->ReferenceFrames[n]);
+
+
+#define COPY_FIELD(s, f) \
+    pic_param->f = (s)->f
+#define COPY_BFM(a, s, f) \
+    pic_param->a.bits.f = (s)->f
+
+  COPY_FIELD (sps, pic_width_in_luma_samples);
+  COPY_FIELD (sps, pic_height_in_luma_samples);
+  COPY_BFM (pic_fields, sps, chroma_format_idc);
+  COPY_BFM (pic_fields, sps, separate_colour_plane_flag);
+  COPY_BFM (pic_fields, sps, pcm_enabled_flag);
+  COPY_BFM (pic_fields, sps, scaling_list_enabled_flag);
+  COPY_BFM (pic_fields, pps, transform_skip_enabled_flag);
+  COPY_BFM (pic_fields, sps, amp_enabled_flag);
+  COPY_BFM (pic_fields, sps, strong_intra_smoothing_enabled_flag);
+  COPY_BFM (pic_fields, pps, sign_data_hiding_enabled_flag);
+  COPY_BFM (pic_fields, pps, constrained_intra_pred_flag);
+  COPY_BFM (pic_fields, pps, cu_qp_delta_enabled_flag);
+  COPY_BFM (pic_fields, pps, weighted_pred_flag);
+  COPY_BFM (pic_fields, pps, weighted_bipred_flag);
+  COPY_BFM (pic_fields, pps, transquant_bypass_enabled_flag);
+  COPY_BFM (pic_fields, pps, tiles_enabled_flag);
+  COPY_BFM (pic_fields, pps, entropy_coding_sync_enabled_flag);
+  pic_param->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag =
+      pps->loop_filter_across_slices_enabled_flag;
+  COPY_BFM (pic_fields, pps, loop_filter_across_tiles_enabled_flag);
+  COPY_BFM (pic_fields, sps, pcm_loop_filter_disabled_flag);
+  /* Fix: Assign value based on sps_max_num_reorder_pics */
+  pic_param->pic_fields.bits.NoPicReorderingFlag = 0;
+  /* Fix: Enable if picture has no B slices */
+  pic_param->pic_fields.bits.NoBiPredFlag = 0;
+
+  pic_param->sps_max_dec_pic_buffering_minus1 =
+      sps->max_dec_pic_buffering_minus1[0];
+  COPY_FIELD (sps, bit_depth_luma_minus8);
+  COPY_FIELD (sps, bit_depth_chroma_minus8);
+  COPY_FIELD (sps, pcm_sample_bit_depth_luma_minus1);
+  COPY_FIELD (sps, pcm_sample_bit_depth_chroma_minus1);
+  COPY_FIELD (sps, log2_min_luma_coding_block_size_minus3);
+  COPY_FIELD (sps, log2_diff_max_min_luma_coding_block_size);
+  COPY_FIELD (sps, log2_min_transform_block_size_minus2);
+  COPY_FIELD (sps, log2_diff_max_min_transform_block_size);
+  COPY_FIELD (sps, log2_min_pcm_luma_coding_block_size_minus3);
+  COPY_FIELD (sps, log2_diff_max_min_pcm_luma_coding_block_size);
+  COPY_FIELD (sps, max_transform_hierarchy_depth_intra);
+  COPY_FIELD (sps, max_transform_hierarchy_depth_inter);
+  COPY_FIELD (pps, init_qp_minus26);
+  COPY_FIELD (pps, diff_cu_qp_delta_depth);
+  pic_param->pps_cb_qp_offset = pps->cb_qp_offset;
+  pic_param->pps_cr_qp_offset = pps->cr_qp_offset;
+  COPY_FIELD (pps, log2_parallel_merge_level_minus2);
+  COPY_FIELD (pps, num_tile_columns_minus1);
+  COPY_FIELD (pps, num_tile_rows_minus1);
+  for (i = 0; i <= pps->num_tile_columns_minus1; i++)
+    pic_param->column_width_minus1[i] = pps->column_width_minus1[i];
+  for (; i < 19; i++)
+    pic_param->column_width_minus1[i] = 0;
+  for (i = 0; i <= pps->num_tile_rows_minus1; i++)
+    pic_param->row_height_minus1[i] = pps->row_height_minus1[i];
+  for (; i < 21; i++)
+    pic_param->row_height_minus1[i] = 0;
+
+  COPY_BFM (slice_parsing_fields, pps, lists_modification_present_flag);
+  COPY_BFM (slice_parsing_fields, sps, long_term_ref_pics_present_flag);
+  pic_param->slice_parsing_fields.bits.sps_temporal_mvp_enabled_flag =
+      sps->temporal_mvp_enabled_flag;
+  COPY_BFM (slice_parsing_fields, pps, cabac_init_present_flag);
+  COPY_BFM (slice_parsing_fields, pps, output_flag_present_flag);
+  COPY_BFM (slice_parsing_fields, pps, dependent_slice_segments_enabled_flag);
+  pic_param->slice_parsing_fields.bits.
+      pps_slice_chroma_qp_offsets_present_flag =
+      pps->slice_chroma_qp_offsets_present_flag;
+  COPY_BFM (slice_parsing_fields, sps, sample_adaptive_offset_enabled_flag);
+  COPY_BFM (slice_parsing_fields, pps, deblocking_filter_override_enabled_flag);
+  pic_param->slice_parsing_fields.bits.pps_disable_deblocking_filter_flag =
+      pps->deblocking_filter_disabled_flag;
+  COPY_BFM (slice_parsing_fields, pps,
+      slice_segment_header_extension_present_flag);
+  pic_param->slice_parsing_fields.bits.RapPicFlag = picture->RapPicFlag;
+  pic_param->slice_parsing_fields.bits.IdrPicFlag =
+      GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_IDR);
+  pic_param->slice_parsing_fields.bits.IntraPicFlag = picture->IntraPicFlag;
+
+  COPY_FIELD (sps, log2_max_pic_order_cnt_lsb_minus4);
+  COPY_FIELD (sps, num_short_term_ref_pic_sets);
+  pic_param->num_long_term_ref_pic_sps = sps->num_long_term_ref_pics_sps;
+  COPY_FIELD (pps, num_ref_idx_l0_default_active_minus1);
+  COPY_FIELD (pps, num_ref_idx_l1_default_active_minus1);
+  pic_param->pps_beta_offset_div2 = pps->beta_offset_div2;
+  pic_param->pps_tc_offset_div2 = pps->tc_offset_div2;
+  COPY_FIELD (pps, num_extra_slice_header_bits);
+
+  if (slice_hdr->short_term_ref_pic_set_sps_flag == 0)
+    pic_param->st_rps_bits = slice_hdr->short_term_ref_pic_set_size;
+  else
+    pic_param->st_rps_bits = 0;
+
+#if VA_CHECK_VERSION(1,2,0)
+  if (pic_rext_param) {
+    pic_rext_param->range_extension_pic_fields.value = 0;
+
+#define COPY_REXT_FIELD(s, f) \
+               pic_rext_param->f = s.f
+#define COPY_REXT_BFM(a, s, f) \
+               pic_rext_param->a.bits.f = s.f
+
+    COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extension_params,
+        transform_skip_rotation_enabled_flag);
+    COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extension_params,
+        transform_skip_context_enabled_flag);
+    COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extension_params,
+        implicit_rdpcm_enabled_flag);
+    COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extension_params,
+        explicit_rdpcm_enabled_flag);
+    COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extension_params,
+        extended_precision_processing_flag);
+    COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extension_params,
+        intra_smoothing_disabled_flag);
+    COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extension_params,
+        high_precision_offsets_enabled_flag);
+    COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extension_params,
+        persistent_rice_adaptation_enabled_flag);
+    COPY_REXT_BFM (range_extension_pic_fields, sps->sps_extension_params,
+        cabac_bypass_alignment_enabled_flag);
+
+    COPY_REXT_BFM (range_extension_pic_fields, pps->pps_extension_params,
+        cross_component_prediction_enabled_flag);
+    COPY_REXT_BFM (range_extension_pic_fields, pps->pps_extension_params,
+        chroma_qp_offset_list_enabled_flag);
+
+    COPY_REXT_FIELD (pps->pps_extension_params, diff_cu_chroma_qp_offset_depth);
+    COPY_REXT_FIELD (pps->pps_extension_params,
+        chroma_qp_offset_list_len_minus1);
+    COPY_REXT_FIELD (pps->pps_extension_params, log2_sao_offset_scale_luma);
+    COPY_REXT_FIELD (pps->pps_extension_params, log2_sao_offset_scale_chroma);
+    COPY_REXT_FIELD (pps->pps_extension_params,
+        log2_max_transform_skip_block_size_minus2);
+
+    memcpy (pic_rext_param->cb_qp_offset_list,
+        pps->pps_extension_params.cb_qp_offset_list,
+        sizeof (pic_rext_param->cb_qp_offset_list));
+    memcpy (pic_rext_param->cr_qp_offset_list,
+        pps->pps_extension_params.cr_qp_offset_list,
+        sizeof (pic_rext_param->cr_qp_offset_list));
+  }
+
+  if (pic_scc_param) {
+#define COPY_SCC_FIELD(s, f) \
+    pic_scc_param->f = s->f
+#define COPY_SCC_BFM(a, s, f) \
+    pic_scc_param->a.bits.f = s->f
+
+    const GstH265PPSSccExtensionParams *pps_scc =
+        &pps->pps_scc_extension_params;
+    const GstH265SPSSccExtensionParams *sps_scc =
+        &sps->sps_scc_extension_params;
+    guint32 num_comps;
+
+    pic_scc_param->screen_content_pic_fields.value = 0;
+
+    COPY_SCC_BFM (screen_content_pic_fields, pps_scc,
+        pps_curr_pic_ref_enabled_flag);
+    COPY_SCC_BFM (screen_content_pic_fields, sps_scc,
+        palette_mode_enabled_flag);
+    COPY_SCC_BFM (screen_content_pic_fields, sps_scc,
+        motion_vector_resolution_control_idc);
+    COPY_SCC_BFM (screen_content_pic_fields, sps_scc,
+        intra_boundary_filtering_disabled_flag);
+    COPY_SCC_BFM (screen_content_pic_fields, pps_scc,
+        residual_adaptive_colour_transform_enabled_flag);
+    COPY_SCC_BFM (screen_content_pic_fields, pps_scc,
+        pps_slice_act_qp_offsets_present_flag);
+
+    COPY_SCC_FIELD (sps_scc, palette_max_size);
+    COPY_SCC_FIELD (sps_scc, delta_palette_max_predictor_size);
+    COPY_SCC_FIELD (pps_scc, pps_act_y_qp_offset_plus5);
+    COPY_SCC_FIELD (pps_scc, pps_act_cb_qp_offset_plus5);
+    COPY_SCC_FIELD (pps_scc, pps_act_cr_qp_offset_plus3);
+
+    /* firstly use the pps, then sps */
+    num_comps = sps->chroma_format_idc ? 3 : 1;
+
+    if (pps_scc->pps_palette_predictor_initializers_present_flag) {
+      pic_scc_param->predictor_palette_size =
+          pps_scc->pps_num_palette_predictor_initializer;
+      for (n = 0; n < num_comps; n++)
+        for (i = 0; i < pps_scc->pps_num_palette_predictor_initializer; i++)
+          pic_scc_param->predictor_palette_entries[n][i] =
+              (uint16_t) pps_scc->pps_palette_predictor_initializer[n][i];
+    } else if (sps_scc->sps_palette_predictor_initializers_present_flag) {
+      pic_scc_param->predictor_palette_size =
+          sps_scc->sps_num_palette_predictor_initializer_minus1 + 1;
+      for (n = 0; n < num_comps; n++)
+        for (i = 0;
+            i < sps_scc->sps_num_palette_predictor_initializer_minus1 + 1; i++)
+          pic_scc_param->predictor_palette_entries[n][i] =
+              (uint16_t) sps_scc->sps_palette_predictor_initializer[n][i];
+    }
+  }
+#endif
+  return TRUE;
+}
+
+/* Detection of the first VCL NAL unit of a coded picture (7.4.2.4.5 ) */
+static gboolean
+is_new_picture (GstVaapiParserInfoH265 * pi, GstVaapiParserInfoH265 * prev_pi)
+{
+  GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+
+  if (!prev_pi)
+    return TRUE;
+
+  if (slice_hdr->first_slice_segment_in_pic_flag)
+    return TRUE;
+
+  return FALSE;
+}
+
+/* Detection of a new access unit, assuming we are already in presence
+   of a new picture */
+static inline gboolean
+is_new_access_unit (GstVaapiParserInfoH265 * pi,
+    GstVaapiParserInfoH265 * prev_pi)
+{
+  if (!prev_pi)
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+has_entry_in_rps (GstVaapiPictureH265 * dpb_pic,
+    GstVaapiPictureH265 ** rps_list, guint rps_list_length)
+{
+  guint i;
+
+  if (!dpb_pic || !rps_list || !rps_list_length)
+    return FALSE;
+
+  for (i = 0; i < rps_list_length; i++) {
+    if (rps_list[i] && rps_list[i]->poc == dpb_pic->poc)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+/* the derivation process for the RPS and the picture marking */
+static void
+derive_and_mark_rps (GstVaapiDecoderH265 * decoder,
+    GstVaapiPictureH265 * picture, GstVaapiParserInfoH265 * pi,
+    gint32 * CurrDeltaPocMsbPresentFlag, gint32 * FollDeltaPocMsbPresentFlag)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiPictureH265 *dpb_pic = NULL;
+  guint i;
+
+  memset (priv->RefPicSetLtCurr, 0, sizeof (GstVaapiPictureH265 *) * 16);
+  memset (priv->RefPicSetLtFoll, 0, sizeof (GstVaapiPictureH265 *) * 16);
+  memset (priv->RefPicSetStCurrBefore, 0, sizeof (GstVaapiPictureH265 *) * 16);
+  memset (priv->RefPicSetStCurrAfter, 0, sizeof (GstVaapiPictureH265 *) * 16);
+  memset (priv->RefPicSetStFoll, 0, sizeof (GstVaapiPictureH265 *) * 16);
+
+  /* (8-6) */
+  for (i = 0; i < priv->NumPocLtCurr; i++) {
+    if (!CurrDeltaPocMsbPresentFlag[i]) {
+      dpb_pic = dpb_get_picture (decoder, priv->PocLtCurr[i], TRUE);
+      if (dpb_pic)
+        priv->RefPicSetLtCurr[i] = dpb_pic;
+      else
+        priv->RefPicSetLtCurr[i] = NULL;
+    } else {
+      dpb_pic = dpb_get_picture (decoder, priv->PocLtCurr[i], FALSE);
+      if (dpb_pic)
+        priv->RefPicSetLtCurr[i] = dpb_pic;
+      else
+        priv->RefPicSetLtCurr[i] = NULL;
+    }
+  }
+  for (; i < 16; i++)
+    priv->RefPicSetLtCurr[i] = NULL;
+
+  for (i = 0; i < priv->NumPocLtFoll; i++) {
+    if (!FollDeltaPocMsbPresentFlag[i]) {
+      dpb_pic = dpb_get_picture (decoder, priv->PocLtFoll[i], TRUE);
+      if (dpb_pic)
+        priv->RefPicSetLtFoll[i] = dpb_pic;
+      else
+        priv->RefPicSetLtFoll[i] = NULL;
+    } else {
+      dpb_pic = dpb_get_picture (decoder, priv->PocLtFoll[i], FALSE);
+      if (dpb_pic)
+        priv->RefPicSetLtFoll[i] = dpb_pic;
+      else
+        priv->RefPicSetLtFoll[i] = NULL;
+    }
+  }
+  for (; i < 16; i++)
+    priv->RefPicSetLtFoll[i] = NULL;
+
+  /* Mark all ref pics in RefPicSetLtCurr and RefPicSetLtFol as long_term_refs */
+  for (i = 0; i < priv->NumPocLtCurr; i++) {
+    if (priv->RefPicSetLtCurr[i])
+      gst_vaapi_picture_h265_set_reference (priv->RefPicSetLtCurr[i],
+          GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE |
+          GST_VAAPI_PICTURE_FLAG_RPS_LT_CURR);
+  }
+  for (i = 0; i < priv->NumPocLtFoll; i++) {
+    if (priv->RefPicSetLtFoll[i])
+      gst_vaapi_picture_h265_set_reference (priv->RefPicSetLtFoll[i],
+          GST_VAAPI_PICTURE_FLAG_LONG_TERM_REFERENCE |
+          GST_VAAPI_PICTURE_FLAG_RPS_LT_FOLL);
+  }
+
+  /* (8-7) */
+  for (i = 0; i < priv->NumPocStCurrBefore; i++) {
+    dpb_pic = dpb_get_ref_picture (decoder, priv->PocStCurrBefore[i], TRUE);
+    if (dpb_pic) {
+      gst_vaapi_picture_h265_set_reference (dpb_pic,
+          GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE |
+          GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_BEFORE);
+      priv->RefPicSetStCurrBefore[i] = dpb_pic;
+    } else
+      priv->RefPicSetStCurrBefore[i] = NULL;
+  }
+  for (; i < 16; i++)
+    priv->RefPicSetStCurrBefore[i] = NULL;
+
+  for (i = 0; i < priv->NumPocStCurrAfter; i++) {
+    dpb_pic = dpb_get_ref_picture (decoder, priv->PocStCurrAfter[i], TRUE);
+    if (dpb_pic) {
+      gst_vaapi_picture_h265_set_reference (dpb_pic,
+          GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE |
+          GST_VAAPI_PICTURE_FLAG_RPS_ST_CURR_AFTER);
+      priv->RefPicSetStCurrAfter[i] = dpb_pic;
+    } else
+      priv->RefPicSetStCurrAfter[i] = NULL;
+  }
+  for (; i < 16; i++)
+    priv->RefPicSetStCurrAfter[i] = NULL;
+
+  for (i = 0; i < priv->NumPocStFoll; i++) {
+    dpb_pic = dpb_get_ref_picture (decoder, priv->PocStFoll[i], TRUE);
+    if (dpb_pic) {
+      gst_vaapi_picture_h265_set_reference (dpb_pic,
+          GST_VAAPI_PICTURE_FLAG_SHORT_TERM_REFERENCE |
+          GST_VAAPI_PICTURE_FLAG_RPS_ST_FOLL);
+      priv->RefPicSetStFoll[i] = dpb_pic;
+    } else
+      priv->RefPicSetStFoll[i] = NULL;
+  }
+  for (; i < 16; i++)
+    priv->RefPicSetStFoll[i] = NULL;
+
+  /* Mark all dpb pics not beloging to RefPicSet*[] as unused for ref */
+  for (i = 0; i < priv->dpb_count; i++) {
+    dpb_pic = priv->dpb[i]->buffer;
+    if (dpb_pic &&
+        !has_entry_in_rps (dpb_pic, priv->RefPicSetLtCurr, priv->NumPocLtCurr)
+        && !has_entry_in_rps (dpb_pic, priv->RefPicSetLtFoll,
+            priv->NumPocLtFoll)
+        && !has_entry_in_rps (dpb_pic, priv->RefPicSetStCurrAfter,
+            priv->NumPocStCurrAfter)
+        && !has_entry_in_rps (dpb_pic, priv->RefPicSetStCurrBefore,
+            priv->NumPocStCurrBefore)
+        && !has_entry_in_rps (dpb_pic, priv->RefPicSetStFoll,
+            priv->NumPocStFoll))
+      gst_vaapi_picture_h265_set_reference (dpb_pic, 0);
+  }
+
+}
+
+/* Decoding process for reference picture set (8.3.2) */
+static gboolean
+decode_ref_pic_set (GstVaapiDecoderH265 * decoder,
+    GstVaapiPictureH265 * picture, GstVaapiParserInfoH265 * pi)
+{
+  guint i, j, k;
+  gint32 CurrDeltaPocMsbPresentFlag[16] = { 0, };
+  gint32 FollDeltaPocMsbPresentFlag[16] = { 0, };
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstH265SPS *const sps = get_sps (decoder);
+  GstH265PPS *const pps = get_pps (decoder);
+  const gint32 MaxPicOrderCntLsb =
+      1 << (sps->log2_max_pic_order_cnt_lsb_minus4 + 4);
+
+  /* if it is an irap pic, set all ref pics in dpb as unused for ref */
+  if (nal_is_irap (pi->nalu.type) && picture->NoRaslOutputFlag) {
+    for (i = 0; i < priv->dpb_count; i++) {
+      GstVaapiFrameStore *const fs = priv->dpb[i];
+      gst_vaapi_picture_h265_set_reference (fs->buffer, 0);
+    }
+  }
+
+  /* Reset everything for IDR */
+  if (nal_is_idr (pi->nalu.type)) {
+    memset (priv->PocStCurrBefore, 0, sizeof (guint) * 16);
+    memset (priv->PocStCurrAfter, 0, sizeof (guint) * 16);
+    memset (priv->PocStFoll, 0, sizeof (guint) * 16);
+    memset (priv->PocLtCurr, 0, sizeof (guint) * 16);
+    memset (priv->PocLtFoll, 0, sizeof (guint) * 16);
+    priv->NumPocStCurrBefore = priv->NumPocStCurrAfter = priv->NumPocStFoll = 0;
+    priv->NumPocLtCurr = priv->NumPocLtFoll = 0;
+    priv->NumPocTotalCurr = 0;
+  } else {
+    GstH265ShortTermRefPicSet *stRefPic = NULL;
+    gint32 num_lt_pics, pocLt;
+    gint32 PocLsbLt[16] = { 0, };
+    gint32 UsedByCurrPicLt[16] = { 0, };
+    gint32 DeltaPocMsbCycleLt[16] = { 0, };
+    gint numtotalcurr = 0;
+
+    /* this is based on CurrRpsIdx described in spec */
+    if (!slice_hdr->short_term_ref_pic_set_sps_flag)
+      stRefPic = &slice_hdr->short_term_ref_pic_sets;
+    else if (sps->num_short_term_ref_pic_sets)
+      stRefPic =
+          &sps->short_term_ref_pic_set[slice_hdr->short_term_ref_pic_set_idx];
+
+    g_assert (stRefPic != NULL);
+
+    for (i = 0, j = 0, k = 0; i < stRefPic->NumNegativePics; i++) {
+      if (stRefPic->UsedByCurrPicS0[i]) {
+        priv->PocStCurrBefore[j++] = picture->poc + stRefPic->DeltaPocS0[i];
+        numtotalcurr++;
+      } else
+        priv->PocStFoll[k++] = picture->poc + stRefPic->DeltaPocS0[i];
+    }
+    priv->NumPocStCurrBefore = j;
+    for (i = 0, j = 0; i < stRefPic->NumPositivePics; i++) {
+      if (stRefPic->UsedByCurrPicS1[i]) {
+        priv->PocStCurrAfter[j++] = picture->poc + stRefPic->DeltaPocS1[i];
+        numtotalcurr++;
+      } else
+        priv->PocStFoll[k++] = picture->poc + stRefPic->DeltaPocS1[i];
+    }
+    priv->NumPocStCurrAfter = j;
+    priv->NumPocStFoll = k;
+    num_lt_pics = slice_hdr->num_long_term_sps + slice_hdr->num_long_term_pics;
+    /* The variables PocLsbLt[i] and UsedByCurrPicLt[i] are derived as follows: */
+    for (i = 0; i < num_lt_pics; i++) {
+      if (i < slice_hdr->num_long_term_sps) {
+        PocLsbLt[i] = sps->lt_ref_pic_poc_lsb_sps[slice_hdr->lt_idx_sps[i]];
+        UsedByCurrPicLt[i] =
+            sps->used_by_curr_pic_lt_sps_flag[slice_hdr->lt_idx_sps[i]];
+      } else {
+        PocLsbLt[i] = slice_hdr->poc_lsb_lt[i];
+        UsedByCurrPicLt[i] = slice_hdr->used_by_curr_pic_lt_flag[i];
+      }
+      if (UsedByCurrPicLt[i])
+        numtotalcurr++;
+    }
+
+    if (pps->pps_scc_extension_params.pps_curr_pic_ref_enabled_flag)
+      numtotalcurr++;
+    priv->NumPocTotalCurr = numtotalcurr;
+
+    /* The variable DeltaPocMsbCycleLt[i] is derived as follows: (7-38) */
+    for (i = 0; i < num_lt_pics; i++) {
+      if (i == 0 || i == slice_hdr->num_long_term_sps)
+        DeltaPocMsbCycleLt[i] = slice_hdr->delta_poc_msb_cycle_lt[i];
+      else
+        DeltaPocMsbCycleLt[i] =
+            slice_hdr->delta_poc_msb_cycle_lt[i] + DeltaPocMsbCycleLt[i - 1];
+    }
+
+    /* (8-5) */
+    for (i = 0, j = 0, k = 0; i < num_lt_pics; i++) {
+      pocLt = PocLsbLt[i];
+      if (slice_hdr->delta_poc_msb_present_flag[i])
+        pocLt +=
+            picture->poc - DeltaPocMsbCycleLt[i] * MaxPicOrderCntLsb -
+            slice_hdr->pic_order_cnt_lsb;
+      if (UsedByCurrPicLt[i]) {
+        priv->PocLtCurr[j] = pocLt;
+        CurrDeltaPocMsbPresentFlag[j++] =
+            slice_hdr->delta_poc_msb_present_flag[i];
+      } else {
+        priv->PocLtFoll[k] = pocLt;
+        FollDeltaPocMsbPresentFlag[k++] =
+            slice_hdr->delta_poc_msb_present_flag[i];
+      }
+    }
+    priv->NumPocLtCurr = j;
+    priv->NumPocLtFoll = k;
+
+  }
+
+  /* the derivation process for the RPS and the picture marking */
+  derive_and_mark_rps (decoder, picture, pi, CurrDeltaPocMsbPresentFlag,
+      FollDeltaPocMsbPresentFlag);
+
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_picture (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *pi = unit->parsed_info;
+  GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstH265PPS *const pps = ensure_pps (decoder, slice_hdr->pps);
+  GstH265SPS *const sps = ensure_sps (decoder, slice_hdr->pps->sps);
+  GstVaapiPictureH265 *picture;
+  GstVaapiDecoderStatus status;
+
+  if (!(pps && sps))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  status = ensure_context (decoder, sps);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  priv->decoder_state = 0;
+
+  /* Create new picture */
+  picture = gst_vaapi_picture_h265_new (decoder);
+  if (!picture) {
+    GST_ERROR ("failed to allocate picture");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  gst_vaapi_picture_replace (&priv->current_picture, picture);
+  gst_vaapi_picture_unref (picture);
+
+  /* Update cropping rectangle */
+  if (sps->conformance_window_flag) {
+    GstVaapiRectangle crop_rect;
+    crop_rect.x = sps->crop_rect_x;
+    crop_rect.y = sps->crop_rect_y;
+    crop_rect.width = sps->crop_rect_width;
+    crop_rect.height = sps->crop_rect_height;
+    gst_vaapi_picture_set_crop_rect (&picture->base, &crop_rect);
+  }
+
+  status = ensure_quant_matrix (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    GST_ERROR ("failed to reset quantizer matrix");
+    return status;
+  }
+
+  if (!init_picture (decoder, picture, pi))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  /* Drop all RASL pictures having NoRaslOutputFlag is TRUE for the
+   * associated IRAP picture */
+  if (nal_is_rasl (pi->nalu.type) && priv->associated_irap_NoRaslOutputFlag) {
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+    return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME;
+  }
+
+  if (!decode_ref_pic_set (decoder, picture, pi))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  if (!dpb_init (decoder, picture, pi))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  if (!fill_picture (decoder, picture, pi))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  priv->decoder_state = pi->state;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline guint
+get_slice_data_byte_offset (GstH265SliceHdr * slice_hdr, guint nal_header_bytes)
+{
+  guint epb_count;
+
+  epb_count = slice_hdr->n_emulation_prevention_bytes;
+  return nal_header_bytes + (slice_hdr->header_size + 7) / 8 - epb_count;
+}
+
+static gboolean
+fill_pred_weight_table (GstVaapiDecoderH265 * decoder,
+    GstVaapiSlice * slice, GstH265SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  VASliceParameterBufferHEVC *slice_param = slice->param;
+  GstH265PPS *const pps = get_pps (decoder);
+  GstH265SPS *const sps = get_sps (decoder);
+  GstH265PredWeightTable *const w = &slice_hdr->pred_weight_table;
+  gint chroma_weight, chroma_log2_weight_denom;
+  gint i, j;
+
+#if VA_CHECK_VERSION(1,2,0)
+  VASliceParameterBufferHEVCRext *slice_rext_param = NULL;
+  if (is_range_extension_profile (priv->profile)) {
+    VASliceParameterBufferHEVCExtension *param = slice->param;
+    slice_param = &param->base;
+    slice_rext_param = &param->rext;
+  }
+#endif
+
+  slice_param->luma_log2_weight_denom = 0;
+  slice_param->delta_chroma_log2_weight_denom = 0;
+
+  if ((pps->weighted_pred_flag && GST_H265_IS_P_SLICE (slice_hdr)) ||
+      (pps->weighted_bipred_flag && GST_H265_IS_B_SLICE (slice_hdr))) {
+
+    /* FIXME: This should be done in parser apis */
+    memset (slice_param->delta_luma_weight_l0, 0,
+        sizeof (slice_param->delta_luma_weight_l0));
+    memset (slice_param->luma_offset_l0, 0,
+        sizeof (slice_param->luma_offset_l0));
+    memset (slice_param->delta_luma_weight_l1, 0,
+        sizeof (slice_param->delta_luma_weight_l1));
+    memset (slice_param->luma_offset_l1, 0,
+        sizeof (slice_param->luma_offset_l1));
+    memset (slice_param->delta_chroma_weight_l0, 0,
+        sizeof (slice_param->delta_chroma_weight_l0));
+    memset (slice_param->ChromaOffsetL0, 0,
+        sizeof (slice_param->ChromaOffsetL0));
+    memset (slice_param->delta_chroma_weight_l1, 0,
+        sizeof (slice_param->delta_chroma_weight_l1));
+    memset (slice_param->ChromaOffsetL1, 0,
+        sizeof (slice_param->ChromaOffsetL1));
+
+#if VA_CHECK_VERSION(1,2,0)
+    if (slice_rext_param) {
+      memset (slice_rext_param->luma_offset_l0, 0,
+          sizeof (slice_rext_param->luma_offset_l0));
+      memset (slice_rext_param->luma_offset_l1, 0,
+          sizeof (slice_rext_param->luma_offset_l1));
+      memset (slice_rext_param->ChromaOffsetL0, 0,
+          sizeof (slice_rext_param->ChromaOffsetL0));
+      memset (slice_rext_param->ChromaOffsetL1, 0,
+          sizeof (slice_rext_param->ChromaOffsetL1));
+    }
+#endif
+
+    slice_param->luma_log2_weight_denom = w->luma_log2_weight_denom;
+    if (sps->chroma_array_type != 0)
+      slice_param->delta_chroma_log2_weight_denom =
+          w->delta_chroma_log2_weight_denom;
+
+    chroma_log2_weight_denom =
+        slice_param->luma_log2_weight_denom +
+        slice_param->delta_chroma_log2_weight_denom;
+
+    for (i = 0; i <= slice_param->num_ref_idx_l0_active_minus1; i++) {
+      if (slice_hdr->pred_weight_table.luma_weight_l0_flag[i]) {
+        slice_param->delta_luma_weight_l0[i] = w->delta_luma_weight_l0[i];
+        slice_param->luma_offset_l0[i] = w->luma_offset_l0[i];
+#if VA_CHECK_VERSION(1,2,0)
+        if (slice_rext_param)
+          slice_rext_param->luma_offset_l0[i] = w->luma_offset_l0[i];
+#endif
+      }
+      if (slice_hdr->pred_weight_table.chroma_weight_l0_flag[i]) {
+        for (j = 0; j < 2; j++) {
+          slice_param->delta_chroma_weight_l0[i][j] =
+              w->delta_chroma_weight_l0[i][j];
+          /* Find  ChromaWeightL0 */
+          chroma_weight =
+              (1 << chroma_log2_weight_denom) + w->delta_chroma_weight_l0[i][j];
+          /* 7-56 */
+          slice_param->ChromaOffsetL0[i][j] = CLAMP (
+              (priv->WpOffsetHalfRangeC + w->delta_chroma_offset_l0[i][j] -
+                  ((priv->WpOffsetHalfRangeC *
+                          chroma_weight) >> chroma_log2_weight_denom)),
+              -priv->WpOffsetHalfRangeC, priv->WpOffsetHalfRangeC - 1);
+#if VA_CHECK_VERSION(1,2,0)
+          if (slice_rext_param)
+            slice_rext_param->ChromaOffsetL0[i][j] = CLAMP (
+                (priv->WpOffsetHalfRangeC + w->delta_chroma_offset_l0[i][j] -
+                    ((priv->WpOffsetHalfRangeC *
+                            chroma_weight) >> chroma_log2_weight_denom)),
+                -priv->WpOffsetHalfRangeC, priv->WpOffsetHalfRangeC - 1);
+#endif
+        }
+      }
+    }
+
+    if (GST_H265_IS_B_SLICE (slice_hdr)) {
+      for (i = 0; i <= slice_param->num_ref_idx_l1_active_minus1; i++) {
+        if (slice_hdr->pred_weight_table.luma_weight_l1_flag[i]) {
+          slice_param->delta_luma_weight_l1[i] = w->delta_luma_weight_l1[i];
+          slice_param->luma_offset_l1[i] = w->luma_offset_l1[i];
+#if VA_CHECK_VERSION(1,2,0)
+          if (slice_rext_param)
+            slice_rext_param->luma_offset_l1[i] = w->luma_offset_l1[i];
+#endif
+        }
+        if (slice_hdr->pred_weight_table.chroma_weight_l1_flag[i]) {
+          for (j = 0; j < 2; j++) {
+            slice_param->delta_chroma_weight_l1[i][j] =
+                w->delta_chroma_weight_l1[i][j];
+            /* Find  ChromaWeightL1 */
+            chroma_weight =
+                (1 << chroma_log2_weight_denom) +
+                w->delta_chroma_weight_l1[i][j];
+            /* 7-56 */
+            slice_param->ChromaOffsetL1[i][j] =
+                CLAMP ((priv->WpOffsetHalfRangeC +
+                    w->delta_chroma_offset_l1[i][j] -
+                    ((priv->WpOffsetHalfRangeC *
+                            chroma_weight) >> chroma_log2_weight_denom)),
+                -priv->WpOffsetHalfRangeC, priv->WpOffsetHalfRangeC - 1);
+#if VA_CHECK_VERSION(1,2,0)
+            if (slice_rext_param)
+              slice_rext_param->ChromaOffsetL1[i][j] =
+                  CLAMP ((priv->WpOffsetHalfRangeC +
+                      w->delta_chroma_offset_l1[i][j] -
+                      ((priv->WpOffsetHalfRangeC *
+                              chroma_weight) >> chroma_log2_weight_denom)),
+                  -priv->WpOffsetHalfRangeC, priv->WpOffsetHalfRangeC - 1);
+#endif
+          }
+        }
+      }
+    }
+  }
+  return TRUE;
+}
+
+static gboolean
+fill_RefPicList (GstVaapiDecoderH265 * decoder,
+    GstVaapiPictureH265 * picture, GstVaapiSlice * slice,
+    GstH265SliceHdr * slice_hdr)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  VASliceParameterBufferHEVC *const slice_param = slice->param;
+  GstVaapiPicture *const base_picture = &picture->base;
+  VAPictureParameterBufferHEVC *const pic_param = base_picture->param;
+  guint i, num_ref_lists = 0, j;
+
+  slice_param->num_ref_idx_l0_active_minus1 = 0;
+  slice_param->num_ref_idx_l1_active_minus1 = 0;
+  for (j = 0; j < 2; j++)
+    for (i = 0; i < 15; i++)
+      slice_param->RefPicList[j][i] = 0xFF;
+
+  if (GST_H265_IS_B_SLICE (slice_hdr))
+    num_ref_lists = 2;
+  else if (GST_H265_IS_I_SLICE (slice_hdr))
+    num_ref_lists = 0;
+  else
+    num_ref_lists = 1;
+
+  if (num_ref_lists < 1)
+    return TRUE;
+
+  slice_param->num_ref_idx_l0_active_minus1 =
+      slice_hdr->num_ref_idx_l0_active_minus1;
+  slice_param->num_ref_idx_l1_active_minus1 =
+      slice_hdr->num_ref_idx_l1_active_minus1;
+
+  for (i = 0; i < priv->RefPicList0_count; i++)
+    slice_param->RefPicList[0][i] =
+        get_index_for_RefPicListX (pic_param->ReferenceFrames,
+        priv->RefPicList0[i]);
+  for (; i < 15; i++)
+    slice_param->RefPicList[0][i] = 0xFF;
+
+  if (num_ref_lists < 2)
+    return TRUE;
+
+  for (i = 0; i < priv->RefPicList1_count; i++)
+    slice_param->RefPicList[1][i] =
+        get_index_for_RefPicListX (pic_param->ReferenceFrames,
+        priv->RefPicList1[i]);
+  for (; i < 15; i++)
+    slice_param->RefPicList[1][i] = 0xFF;
+
+  return TRUE;
+}
+
+static gboolean
+fill_slice (GstVaapiDecoderH265 * decoder,
+    GstVaapiPictureH265 * picture, GstVaapiSlice * slice,
+    GstVaapiParserInfoH265 * pi, GstVaapiDecoderUnit * unit)
+{
+  GstH265SliceHdr *slice_hdr = &pi->data.slice_hdr;
+  VASliceParameterBufferHEVC *slice_param = slice->param;
+
+#if VA_CHECK_VERSION(1,2,0)
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  VASliceParameterBufferHEVCRext *slice_rext_param = NULL;
+  if (is_range_extension_profile (priv->profile)
+      || is_scc_profile (priv->profile)) {
+    VASliceParameterBufferHEVCExtension *param = slice->param;
+    slice_param = &param->base;
+    slice_rext_param = &param->rext;
+  }
+#endif
+
+  /* Fill in VASliceParameterBufferH265 */
+  slice_param->LongSliceFlags.value = 0;
+  slice_param->slice_data_byte_offset =
+      get_slice_data_byte_offset (slice_hdr, pi->nalu.header_bytes);
+
+  slice_param->slice_segment_address = slice_hdr->segment_address;
+
+#define COPY_LFF(f) \
+    slice_param->LongSliceFlags.fields.f = (slice_hdr)->f
+
+  if (GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_END))
+    slice_param->LongSliceFlags.fields.LastSliceOfPic = 1;
+  else
+    slice_param->LongSliceFlags.fields.LastSliceOfPic = 0;
+
+  COPY_LFF (dependent_slice_segment_flag);
+
+  COPY_LFF (mvd_l1_zero_flag);
+  COPY_LFF (cabac_init_flag);
+  COPY_LFF (collocated_from_l0_flag);
+  slice_param->LongSliceFlags.fields.color_plane_id =
+      slice_hdr->colour_plane_id;
+  slice_param->LongSliceFlags.fields.slice_type = slice_hdr->type;
+  slice_param->LongSliceFlags.fields.slice_sao_luma_flag =
+      slice_hdr->sao_luma_flag;
+  slice_param->LongSliceFlags.fields.slice_sao_chroma_flag =
+      slice_hdr->sao_chroma_flag;
+  slice_param->LongSliceFlags.fields.slice_temporal_mvp_enabled_flag =
+      slice_hdr->temporal_mvp_enabled_flag;
+  slice_param->LongSliceFlags.fields.slice_deblocking_filter_disabled_flag =
+      slice_hdr->deblocking_filter_disabled_flag;
+  slice_param->LongSliceFlags.fields.
+      slice_loop_filter_across_slices_enabled_flag =
+      slice_hdr->loop_filter_across_slices_enabled_flag;
+
+  if (!slice_hdr->temporal_mvp_enabled_flag)
+    slice_param->collocated_ref_idx = 0xFF;
+  else
+    slice_param->collocated_ref_idx = slice_hdr->collocated_ref_idx;
+
+  slice_param->num_ref_idx_l0_active_minus1 =
+      slice_hdr->num_ref_idx_l0_active_minus1;
+  slice_param->num_ref_idx_l1_active_minus1 =
+      slice_hdr->num_ref_idx_l1_active_minus1;
+  slice_param->slice_qp_delta = slice_hdr->qp_delta;
+  slice_param->slice_cb_qp_offset = slice_hdr->cb_qp_offset;
+  slice_param->slice_cr_qp_offset = slice_hdr->cr_qp_offset;
+  slice_param->slice_beta_offset_div2 = slice_hdr->beta_offset_div2;
+  slice_param->slice_tc_offset_div2 = slice_hdr->tc_offset_div2;
+  slice_param->five_minus_max_num_merge_cand =
+      slice_hdr->five_minus_max_num_merge_cand;
+
+#if VA_CHECK_VERSION(1,2,0)
+  if (slice_rext_param) {
+    slice_rext_param->slice_ext_flags.bits.cu_chroma_qp_offset_enabled_flag =
+        slice_hdr->cu_chroma_qp_offset_enabled_flag;
+    slice_rext_param->slice_ext_flags.bits.use_integer_mv_flag =
+        slice_hdr->use_integer_mv_flag;
+
+    slice_rext_param->slice_act_y_qp_offset = slice_hdr->slice_act_y_qp_offset;
+    slice_rext_param->slice_act_cb_qp_offset =
+        slice_hdr->slice_act_cb_qp_offset;
+    slice_rext_param->slice_act_cr_qp_offset =
+        slice_hdr->slice_act_cr_qp_offset;
+  }
+#endif
+
+  if (!fill_RefPicList (decoder, picture, slice, slice_hdr))
+    return FALSE;
+
+  if (!fill_pred_weight_table (decoder, slice, slice_hdr))
+    return FALSE;
+
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_slice (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GstVaapiPictureH265 *const picture = priv->current_picture;
+  GstH265SliceHdr *const slice_hdr = &pi->data.slice_hdr;
+  GstVaapiSlice *slice = NULL;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  GST_DEBUG ("slice (%u bytes)", pi->nalu.size);
+  if (!is_valid_state (pi->state, GST_H265_VIDEO_STATE_VALID_PICTURE_HEADERS)) {
+    GST_WARNING ("failed to receive enough headers to decode slice");
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  }
+
+  if (!ensure_pps (decoder, slice_hdr->pps)) {
+    GST_ERROR ("failed to activate PPS");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (!ensure_sps (decoder, slice_hdr->pps->sps)) {
+    GST_ERROR ("failed to activate SPS");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  /* Check wether this is the first/last slice in the current access unit */
+  if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_START)
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_START);
+
+  if (pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_END)
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_AU_END);
+
+  if (is_range_extension_profile (priv->profile)
+      || is_scc_profile (priv->profile)) {
+#if VA_CHECK_VERSION(1,2,0)
+    slice = GST_VAAPI_SLICE_NEW (HEVCExtension, decoder,
+        (map_info.data + unit->offset + pi->nalu.offset), pi->nalu.size);
+#endif
+  } else {
+    slice = GST_VAAPI_SLICE_NEW (HEVC, decoder,
+        (map_info.data + unit->offset + pi->nalu.offset), pi->nalu.size);
+  }
+  gst_buffer_unmap (buffer, &map_info);
+  if (!slice) {
+    GST_ERROR ("failed to allocate slice");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  init_picture_refs (decoder, picture, slice_hdr);
+
+  if (!fill_slice (decoder, picture, slice, pi, unit)) {
+    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice));
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
+  picture->last_slice_hdr = slice_hdr;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline gint
+scan_for_start_code (GstAdapter * adapter, guint ofs, guint size, guint32 * scp)
+{
+  if (size == 0)
+    return -1;
+
+  return (gint) gst_adapter_masked_scan_uint32_peek (adapter,
+      0xffffff00, 0x00000100, ofs, size, scp);
+}
+
+static GstVaapiDecoderStatus
+decode_unit (GstVaapiDecoderH265 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserInfoH265 *const pi = unit->parsed_info;
+  GstVaapiDecoderStatus status;
+  priv->decoder_state |= pi->state;
+  switch (pi->nalu.type) {
+    case GST_H265_NAL_VPS:
+      status = decode_vps (decoder, unit);
+      break;
+    case GST_H265_NAL_SPS:
+      status = decode_sps (decoder, unit);
+      break;
+    case GST_H265_NAL_PPS:
+      status = decode_pps (decoder, unit);
+      break;
+    case GST_H265_NAL_SLICE_TRAIL_N:
+    case GST_H265_NAL_SLICE_TRAIL_R:
+    case GST_H265_NAL_SLICE_TSA_N:
+    case GST_H265_NAL_SLICE_TSA_R:
+    case GST_H265_NAL_SLICE_STSA_N:
+    case GST_H265_NAL_SLICE_STSA_R:
+    case GST_H265_NAL_SLICE_RADL_N:
+    case GST_H265_NAL_SLICE_RADL_R:
+    case GST_H265_NAL_SLICE_RASL_N:
+    case GST_H265_NAL_SLICE_RASL_R:
+    case GST_H265_NAL_SLICE_BLA_W_LP:
+    case GST_H265_NAL_SLICE_BLA_W_RADL:
+    case GST_H265_NAL_SLICE_BLA_N_LP:
+    case GST_H265_NAL_SLICE_IDR_W_RADL:
+    case GST_H265_NAL_SLICE_IDR_N_LP:
+    case GST_H265_NAL_SLICE_CRA_NUT:
+      /* slice decoding will get started only after completing all the
+         initialization routines for each picture which is hanlding in
+         start_frame() call back, so the new_bitstream and prev_nal_is_eos
+         flags will have effects starting from the next frame onwards */
+      priv->new_bitstream = FALSE;
+      priv->prev_nal_is_eos = FALSE;
+      status = decode_slice (decoder, unit);
+      break;
+    case GST_H265_NAL_EOB:
+      priv->new_bitstream = TRUE;
+      GST_DEBUG
+          ("Next AU(if there is any) will be the begining of new bitstream");
+      status = decode_sequence_end (decoder);
+      break;
+    case GST_H265_NAL_EOS:
+      priv->prev_nal_is_eos = TRUE;
+      status = decode_sequence_end (decoder);
+      break;
+    case GST_H265_NAL_SUFFIX_SEI:
+    case GST_H265_NAL_PREFIX_SEI:
+      status = decode_sei (decoder, unit);
+      break;
+    default:
+      GST_WARNING ("unsupported NAL unit type %d", pi->nalu.type);
+      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+      break;
+  }
+  return status;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h265_decode_codec_data (GstVaapiDecoder *
+    base_decoder, const guchar * buf, guint buf_size)
+{
+  GstVaapiDecoderH265 *const decoder =
+      GST_VAAPI_DECODER_H265_CAST (base_decoder);
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+  GstVaapiDecoderUnit unit;
+  GstVaapiParserInfoH265 *pi = NULL;
+  GstH265ParserResult result;
+  guint num_nal_arrays, num_nals;
+  guint i, j, ofs;
+
+  if (!priv->is_opened)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  unit.parsed_info = NULL;
+  if (buf_size < 23)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+  if (buf[0] != 1) {
+    GST_ERROR ("failed to decode codec-data, not in hvcC format");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  priv->nal_length_size = (buf[21] & 0x03) + 1;
+  GST_DEBUG ("nal length size %u", priv->nal_length_size);
+  num_nal_arrays = buf[22];
+  ofs = 23;
+  for (i = 0; i < num_nal_arrays; i++) {
+    if (ofs + 1 > buf_size)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    num_nals = GST_READ_UINT16_BE (buf + ofs + 1);
+    /* the max number of nals is GST_H265_MAX_PPS_COUNT (64) */
+    if (num_nals > 64)
+      return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    ofs += 3;
+
+    for (j = 0; j < num_nals; j++) {
+      pi = gst_vaapi_parser_info_h265_new ();
+      if (!pi)
+        return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+      unit.parsed_info = pi;
+      result = gst_h265_parser_identify_nalu_hevc (priv->parser,
+          buf, ofs, buf_size, 2, &pi->nalu);
+      if (result != GST_H265_PARSER_OK) {
+        status = get_status (result);
+        goto cleanup;
+      }
+
+      pi->state = priv->parser_state;
+      pi->flags = 0;
+
+      switch (pi->nalu.type) {
+        case GST_H265_NAL_VPS:
+          status = parse_vps (decoder, &unit);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            goto cleanup;
+          status = decode_vps (decoder, &unit);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            goto cleanup;
+          break;
+        case GST_H265_NAL_SPS:
+          status = parse_sps (decoder, &unit);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            goto cleanup;
+          status = decode_sps (decoder, &unit);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            goto cleanup;
+          break;
+        case GST_H265_NAL_PPS:
+          status = parse_pps (decoder, &unit);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            goto cleanup;
+          status = decode_pps (decoder, &unit);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            goto cleanup;
+          break;
+        case GST_H265_NAL_SUFFIX_SEI:
+        case GST_H265_NAL_PREFIX_SEI:
+          status = parse_sei (decoder, &unit);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            goto cleanup;
+          status = decode_sei (decoder, &unit);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            goto cleanup;
+          break;
+
+      }
+      ofs = pi->nalu.offset + pi->nalu.size;
+      gst_vaapi_parser_info_h265_replace (&pi, NULL);
+    }
+  }
+
+  priv->is_hvcC = TRUE;
+  status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+cleanup:
+  gst_vaapi_parser_info_h265_replace (&pi, NULL);
+  return status;
+}
+
+static GstVaapiDecoderStatus
+ensure_decoder (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+
+  if (!priv->is_opened) {
+    priv->is_opened = gst_vaapi_decoder_h265_open (decoder);
+    if (!priv->is_opened)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
+    status =
+        gst_vaapi_decoder_decode_codec_data (GST_VAAPI_DECODER_CAST (decoder));
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+populate_dependent_slice_hdr (GstVaapiParserInfoH265 * pi,
+    GstVaapiParserInfoH265 * indep_pi)
+{
+  GstH265SliceHdr *slice_hdr = &pi->data.slice_hdr;
+  GstH265SliceHdr *indep_slice_hdr = &indep_pi->data.slice_hdr;
+
+  memcpy (&slice_hdr->type, &indep_slice_hdr->type,
+      offsetof (GstH265SliceHdr, num_entry_point_offsets) -
+      offsetof (GstH265SliceHdr, type));
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h265_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265 *const decoder =
+      GST_VAAPI_DECODER_H265_CAST (base_decoder);
+  GstVaapiDecoderH265Private *const priv = &decoder->priv;
+  GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder);
+  GstVaapiParserInfoH265 *pi;
+  GstVaapiDecoderStatus status;
+  GstH265ParserResult result;
+  guchar *buf;
+  guint i, size, buf_size, nalu_size, flags;
+  guint32 start_code;
+  gint ofs, ofs2;
+  gboolean at_au_end = FALSE;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  switch (priv->stream_alignment) {
+    case GST_VAAPI_STREAM_ALIGN_H265_NALU:
+    case GST_VAAPI_STREAM_ALIGN_H265_AU:
+      size = gst_adapter_available_fast (adapter);
+      break;
+    default:
+      size = gst_adapter_available (adapter);
+      break;
+  }
+
+  if (priv->is_hvcC) {
+    if (size < priv->nal_length_size)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    buf = (guchar *) & start_code;
+    g_assert (priv->nal_length_size <= sizeof (start_code));
+    gst_adapter_copy (adapter, buf, 0, priv->nal_length_size);
+    nalu_size = 0;
+    for (i = 0; i < priv->nal_length_size; i++)
+      nalu_size = (nalu_size << 8) | buf[i];
+    buf_size = priv->nal_length_size + nalu_size;
+    if (size < buf_size)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    else if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H265_AU)
+      at_au_end = (buf_size == size);
+  } else {
+    if (size < 4)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H265_NALU) {
+      buf_size = size;
+      ofs = scan_for_start_code (adapter, 4, size - 4, NULL);
+      if (ofs > 0)
+        buf_size = ofs;
+    } else {
+      ofs = scan_for_start_code (adapter, 0, size, NULL);
+      if (ofs < 0)
+        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+      if (ofs > 0) {
+        gst_adapter_flush (adapter, ofs);
+        size -= ofs;
+      }
+
+      ofs2 = ps->input_offset2 - ofs - 4;
+      if (ofs2 < 4)
+        ofs2 = 4;
+      ofs = G_UNLIKELY (size < ofs2 + 4) ? -1 :
+          scan_for_start_code (adapter, ofs2, size - ofs2, NULL);
+      if (ofs < 0) {
+        // Assume the whole NAL unit is present if end-of-stream
+        // or stream buffers aligned on access unit boundaries
+        if (priv->stream_alignment == GST_VAAPI_STREAM_ALIGN_H265_AU)
+          at_au_end = TRUE;
+        else if (!at_eos) {
+          ps->input_offset2 = size;
+          return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+        }
+        ofs = size;
+      }
+      buf_size = ofs;
+    }
+  }
+  ps->input_offset2 = 0;
+  buf = (guchar *) gst_adapter_map (adapter, buf_size);
+  if (!buf)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+  unit->size = buf_size;
+  pi = gst_vaapi_parser_info_h265_new ();
+  if (!pi)
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  gst_vaapi_decoder_unit_set_parsed_info (unit,
+      pi, (GDestroyNotify) gst_vaapi_mini_object_unref);
+  if (priv->is_hvcC)
+    result = gst_h265_parser_identify_nalu_hevc (priv->parser,
+        buf, 0, buf_size, priv->nal_length_size, &pi->nalu);
+  else
+    result = gst_h265_parser_identify_nalu_unchecked (priv->parser,
+        buf, 0, buf_size, &pi->nalu);
+  status = get_status (result);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    goto exit;
+  switch (pi->nalu.type) {
+    case GST_H265_NAL_VPS:
+      status = parse_vps (decoder, unit);
+      break;
+    case GST_H265_NAL_SPS:
+      status = parse_sps (decoder, unit);
+      break;
+    case GST_H265_NAL_PPS:
+      status = parse_pps (decoder, unit);
+      break;
+    case GST_H265_NAL_PREFIX_SEI:
+    case GST_H265_NAL_SUFFIX_SEI:
+      status = parse_sei (decoder, unit);
+      break;
+    case GST_H265_NAL_SLICE_TRAIL_N:
+    case GST_H265_NAL_SLICE_TRAIL_R:
+    case GST_H265_NAL_SLICE_TSA_N:
+    case GST_H265_NAL_SLICE_TSA_R:
+    case GST_H265_NAL_SLICE_STSA_N:
+    case GST_H265_NAL_SLICE_STSA_R:
+    case GST_H265_NAL_SLICE_RADL_N:
+    case GST_H265_NAL_SLICE_RADL_R:
+    case GST_H265_NAL_SLICE_RASL_N:
+    case GST_H265_NAL_SLICE_RASL_R:
+    case GST_H265_NAL_SLICE_BLA_W_LP:
+    case GST_H265_NAL_SLICE_BLA_W_RADL:
+    case GST_H265_NAL_SLICE_BLA_N_LP:
+    case GST_H265_NAL_SLICE_IDR_W_RADL:
+    case GST_H265_NAL_SLICE_IDR_N_LP:
+    case GST_H265_NAL_SLICE_CRA_NUT:
+      status = parse_slice (decoder, unit);
+      break;
+    default:
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+  }
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    goto exit;
+  flags = 0;
+  if (at_au_end) {
+    flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END |
+        GST_VAAPI_DECODER_UNIT_FLAG_AU_END;
+  }
+
+  switch (pi->nalu.type) {
+    case GST_H265_NAL_AUD:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      /* fall-through */
+    case GST_H265_NAL_FD:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+      break;
+    case GST_H265_NAL_EOB:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
+      /* fall-through */
+    case GST_H265_NAL_SUFFIX_SEI:
+    case GST_H265_NAL_EOS:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_END;
+      break;
+    case GST_H265_NAL_VPS:
+    case GST_H265_NAL_SPS:
+    case GST_H265_NAL_PPS:
+    case GST_H265_NAL_PREFIX_SEI:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      break;
+    case GST_H265_NAL_SLICE_TRAIL_N:
+    case GST_H265_NAL_SLICE_TRAIL_R:
+    case GST_H265_NAL_SLICE_TSA_N:
+    case GST_H265_NAL_SLICE_TSA_R:
+    case GST_H265_NAL_SLICE_STSA_N:
+    case GST_H265_NAL_SLICE_STSA_R:
+    case GST_H265_NAL_SLICE_RADL_N:
+    case GST_H265_NAL_SLICE_RADL_R:
+    case GST_H265_NAL_SLICE_RASL_N:
+    case GST_H265_NAL_SLICE_RASL_R:
+    case GST_H265_NAL_SLICE_BLA_W_LP:
+    case GST_H265_NAL_SLICE_BLA_W_RADL:
+    case GST_H265_NAL_SLICE_BLA_N_LP:
+    case GST_H265_NAL_SLICE_IDR_W_RADL:
+    case GST_H265_NAL_SLICE_IDR_N_LP:
+    case GST_H265_NAL_SLICE_CRA_NUT:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      if (priv->prev_pi &&
+          (priv->prev_pi->flags & GST_VAAPI_DECODER_UNIT_FLAG_AU_END)) {
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START |
+            GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      } else if (is_new_picture (pi, priv->prev_slice_pi)) {
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+        if (is_new_access_unit (pi, priv->prev_slice_pi))
+          flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_START;
+      }
+      gst_vaapi_parser_info_h265_replace (&priv->prev_slice_pi, pi);
+      if (!pi->data.slice_hdr.dependent_slice_segment_flag)
+        gst_vaapi_parser_info_h265_replace (&priv->prev_independent_slice_pi,
+            pi);
+      else
+        populate_dependent_slice_hdr (pi, priv->prev_independent_slice_pi);
+      if (!GST_H265_IS_I_SLICE (&pi->data.slice_hdr))
+        priv->parser_state |= GST_H265_VIDEO_STATE_GOT_P_SLICE;
+      break;
+    default:
+      /* Fix */
+      break;
+  }
+  if ((flags & GST_VAAPI_DECODER_UNIT_FLAGS_AU) && priv->prev_slice_pi)
+    priv->prev_slice_pi->flags |= GST_VAAPI_DECODER_UNIT_FLAG_AU_END;
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+  pi->nalu.data = NULL;
+  pi->state = priv->parser_state;
+  pi->flags = flags;
+  gst_vaapi_parser_info_h265_replace (&priv->prev_pi, pi);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+exit:
+  gst_adapter_flush (adapter, unit->size);
+  gst_vaapi_parser_info_h265_unref (pi);
+  return status;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h265_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265 *const decoder =
+      GST_VAAPI_DECODER_H265_CAST (base_decoder);
+  GstVaapiDecoderStatus status;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+  return decode_unit (decoder, unit);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h265_start_frame (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderH265 *const decoder =
+      GST_VAAPI_DECODER_H265_CAST (base_decoder);
+
+  return decode_picture (decoder, unit);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h265_end_frame (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderH265 *const decoder =
+      GST_VAAPI_DECODER_H265_CAST (base_decoder);
+
+  return decode_current_picture (decoder);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_h265_flush (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderH265 *const decoder =
+      GST_VAAPI_DECODER_H265_CAST (base_decoder);
+
+  dpb_flush (decoder);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+gst_vaapi_decoder_h265_finalize (GObject * object)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
+
+  gst_vaapi_decoder_h265_destroy (base_decoder);
+  G_OBJECT_CLASS (gst_vaapi_decoder_h265_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_h265_class_init (GstVaapiDecoderH265Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_decoder_h265_finalize;
+
+  decoder_class->reset = gst_vaapi_decoder_h265_reset;
+  decoder_class->parse = gst_vaapi_decoder_h265_parse;
+  decoder_class->decode = gst_vaapi_decoder_h265_decode;
+  decoder_class->start_frame = gst_vaapi_decoder_h265_start_frame;
+  decoder_class->end_frame = gst_vaapi_decoder_h265_end_frame;
+  decoder_class->flush = gst_vaapi_decoder_h265_flush;
+  decoder_class->decode_codec_data = gst_vaapi_decoder_h265_decode_codec_data;
+}
+
+static void
+gst_vaapi_decoder_h265_init (GstVaapiDecoderH265 * decoder)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+
+  gst_vaapi_decoder_h265_create (base_decoder);
+}
+
+/**
+ * gst_vaapi_decoder_h265_set_alignment:
+ * @decoder: a #GstVaapiDecoderH265
+ * @alignment: the #GstVaapiStreamAlignH265
+ *
+ * Specifies how stream buffers are aligned / fed, i.e. the boundaries
+ * of each buffer that is supplied to the decoder. This could be no
+ * specific alignment, NAL unit boundaries, or access unit boundaries.
+ */
+void
+gst_vaapi_decoder_h265_set_alignment (GstVaapiDecoderH265 * decoder,
+    GstVaapiStreamAlignH265 alignment)
+{
+  g_return_if_fail (decoder != NULL);
+  decoder->priv.stream_alignment = alignment;
+}
+
+/**
+ * gst_vaapi_decoder_h265_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for MPEG-2 decoding.  The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_h265_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return g_object_new (GST_TYPE_VAAPI_DECODER_H265, "display", display,
+      "caps", caps, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h265.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_h265.h
new file mode 100644 (file)
index 0000000..0b5d092
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  gstvaapidecoder_h265.h - H.265 decoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_H265_H
+#define GST_VAAPI_DECODER_H265_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER_H265 \
+    (gst_vaapi_decoder_h265_get_type ())
+#define GST_VAAPI_DECODER_H265(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_H265, GstVaapiDecoderH265))
+#define GST_VAAPI_IS_DECODER_H265(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_H265))
+
+typedef struct _GstVaapiDecoderH265             GstVaapiDecoderH265;
+
+/**
+ * GstVaapiStreamAlignH265:
+ * @GST_VAAPI_STREAM_ALIGN_H265_NONE: Generic H.265 stream buffers
+ * @GST_VAAPI_STREAM_ALIGN_H265_NALU: H.265 stream buffers aligned NAL
+ *   unit boundaries
+ * @GST_VAAPI_STREAM_ALIGN_H265_AU: H.265 stream buffers aligned on
+ *   access unit boundaries
+ *
+ * Set of possible buffer alignments for H.265 streams.
+ */
+typedef enum {
+    GST_VAAPI_STREAM_ALIGN_H265_NONE,
+    GST_VAAPI_STREAM_ALIGN_H265_NALU,
+    GST_VAAPI_STREAM_ALIGN_H265_AU
+} GstVaapiStreamAlignH265;
+
+GType
+gst_vaapi_decoder_h265_get_type (void) G_GNUC_CONST;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_h265_new (GstVaapiDisplay *display, GstCaps *caps);
+
+void
+gst_vaapi_decoder_h265_set_alignment (GstVaapiDecoderH265 *decoder,
+    GstVaapiStreamAlignH265 alignment);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderH265, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_H265_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c
new file mode 100644 (file)
index 0000000..3122f7b
--- /dev/null
@@ -0,0 +1,964 @@
+/*
+ *  gstvaapidecoder_jpeg.c - JPEG decoder
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_jpeg
+ * @short_description: JPEG decoder
+ */
+
+#include "sysdeps.h"
+#include <gst/codecparsers/gstjpegparser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapidecoder_jpeg.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_DECODER_JPEG_CAST(decoder) \
+    ((GstVaapiDecoderJpeg *)(decoder))
+
+typedef struct _GstVaapiDecoderJpegPrivate GstVaapiDecoderJpegPrivate;
+typedef struct _GstVaapiDecoderJpegClass GstVaapiDecoderJpegClass;
+
+typedef enum
+{
+  GST_JPEG_VIDEO_STATE_GOT_SOI = 1 << 0,
+  GST_JPEG_VIDEO_STATE_GOT_SOF = 1 << 1,
+  GST_JPEG_VIDEO_STATE_GOT_SOS = 1 << 2,
+  GST_JPEG_VIDEO_STATE_GOT_HUF_TABLE = 1 << 3,
+  GST_JPEG_VIDEO_STATE_GOT_IQ_TABLE = 1 << 4,
+
+  GST_JPEG_VIDEO_STATE_VALID_PICTURE = (GST_JPEG_VIDEO_STATE_GOT_SOI |
+      GST_JPEG_VIDEO_STATE_GOT_SOF | GST_JPEG_VIDEO_STATE_GOT_SOS),
+} GstJpegVideoState;
+
+struct _GstVaapiDecoderJpegPrivate
+{
+  GstVaapiProfile profile;
+  guint width;
+  guint height;
+  GstVaapiPicture *current_picture;
+  GstJpegFrameHdr frame_hdr;
+  GstJpegHuffmanTables huf_tables;
+  GstJpegQuantTables quant_tables;
+  guint mcu_restart;
+  guint parser_state;
+  guint decoder_state;
+  guint is_opened:1;
+  guint profile_changed:1;
+  guint size_changed:1;
+};
+
+/**
+ * GstVaapiDecoderJpeg:
+ *
+ * A decoder based on Jpeg.
+ */
+struct _GstVaapiDecoderJpeg
+{
+  /*< private > */
+  GstVaapiDecoder parent_instance;
+  GstVaapiDecoderJpegPrivate priv;
+};
+
+/**
+ * GstVaapiDecoderJpegClass:
+ *
+ * A decoder class based on Jpeg.
+ */
+struct _GstVaapiDecoderJpegClass
+{
+  /*< private > */
+  GstVaapiDecoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiDecoderJpeg, gst_vaapi_decoder_jpeg,
+    GST_TYPE_VAAPI_DECODER);
+
+static inline void
+unit_set_marker_code (GstVaapiDecoderUnit * unit, GstJpegMarker marker)
+{
+  unit->parsed_info = GSIZE_TO_POINTER (marker);
+}
+
+static inline GstJpegMarker
+unit_get_marker_code (GstVaapiDecoderUnit * unit)
+{
+  return GPOINTER_TO_SIZE (unit->parsed_info);
+}
+
+static void
+gst_vaapi_decoder_jpeg_close (GstVaapiDecoderJpeg * decoder)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+
+  /* Reset all */
+  priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE;
+  priv->width = 0;
+  priv->height = 0;
+  priv->is_opened = FALSE;
+  priv->profile_changed = TRUE;
+  priv->size_changed = TRUE;
+}
+
+static gboolean
+gst_vaapi_decoder_jpeg_open (GstVaapiDecoderJpeg * decoder)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_jpeg_close (decoder);
+
+  priv->parser_state = 0;
+  priv->decoder_state = 0;
+  return TRUE;
+}
+
+static void
+gst_vaapi_decoder_jpeg_destroy (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderJpeg *const decoder =
+      GST_VAAPI_DECODER_JPEG_CAST (base_decoder);
+
+  gst_vaapi_decoder_jpeg_close (decoder);
+}
+
+static gboolean
+gst_vaapi_decoder_jpeg_create (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderJpeg *const decoder =
+      GST_VAAPI_DECODER_JPEG_CAST (base_decoder);
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+
+  priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE;
+  priv->profile_changed = TRUE;
+  priv->size_changed = TRUE;
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_jpeg_reset (GstVaapiDecoder * base_decoder)
+{
+  gst_vaapi_decoder_jpeg_destroy (base_decoder);
+  gst_vaapi_decoder_jpeg_create (base_decoder);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static gboolean
+get_chroma_type (GstJpegFrameHdr * frame_hdr, GstVaapiChromaType * chroma_type)
+{
+  int h0 = frame_hdr->components[0].horizontal_factor;
+  int h1 = frame_hdr->components[1].horizontal_factor;
+  int h2 = frame_hdr->components[2].horizontal_factor;
+  int v0 = frame_hdr->components[0].vertical_factor;
+  int v1 = frame_hdr->components[1].vertical_factor;
+  int v2 = frame_hdr->components[2].vertical_factor;
+
+  if (frame_hdr->num_components == 1) {
+    *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV400;
+    return TRUE;
+  }
+
+  if (h1 != h2 || v1 != v2)
+    return FALSE;
+
+  if (h0 == h1) {
+    if (v0 == v1)
+      *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444;
+    else if (v0 == 2 * v1)
+      *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422;
+    else
+      return FALSE;
+  } else if (h0 == 2 * h1) {
+    if (v0 == v1)
+      *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422;
+    else if (v0 == 2 * v1)
+      *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+    else
+      return FALSE;
+  } else if (h0 == 4 * h1) {
+    if (v0 == v1)
+      *chroma_type = GST_VAAPI_CHROMA_TYPE_YUV411;
+    else
+      return FALSE;
+  } else
+    return FALSE;
+
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+ensure_context (GstVaapiDecoderJpeg * decoder)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+  GstJpegFrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+  GstVaapiProfile profiles[2];
+  GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+  guint i, n_profiles = 0;
+  gboolean reset_context = FALSE;
+
+  if (priv->profile_changed) {
+    GST_DEBUG ("profile changed");
+    priv->profile_changed = FALSE;
+    reset_context = TRUE;
+
+    profiles[n_profiles++] = priv->profile;
+    //if (priv->profile == GST_VAAPI_PROFILE_JPEG_EXTENDED)
+    //    profiles[n_profiles++] = GST_VAAPI_PROFILE_JPEG_BASELINE;
+
+    for (i = 0; i < n_profiles; i++) {
+      if (gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
+              profiles[i], entrypoint))
+        break;
+    }
+    if (i == n_profiles)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+    priv->profile = profiles[i];
+  }
+
+  if (priv->size_changed) {
+    GST_DEBUG ("size changed");
+    priv->size_changed = FALSE;
+    reset_context = TRUE;
+  }
+
+  if (reset_context) {
+    GstVaapiContextInfo info;
+
+    info.profile = priv->profile;
+    info.entrypoint = entrypoint;
+    info.width = priv->width;
+    info.height = priv->height;
+    info.ref_frames = 2;
+    if (!get_chroma_type (frame_hdr, &chroma_type))
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
+    info.chroma_type = chroma_type;
+
+    reset_context =
+        gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info);
+    if (!reset_context)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline gboolean
+is_valid_state (guint state, guint ref_state)
+{
+  return (state & ref_state) == ref_state;
+}
+
+#define VALID_STATE(TYPE, STATE)                \
+    is_valid_state(priv->G_PASTE(TYPE,_state),  \
+        G_PASTE(GST_JPEG_VIDEO_STATE_,STATE))
+
+static GstVaapiDecoderStatus
+decode_current_picture (GstVaapiDecoderJpeg * decoder)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->current_picture;
+
+  if (!VALID_STATE (decoder, VALID_PICTURE))
+    goto drop_frame;
+  priv->decoder_state = 0;
+
+  if (!picture)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_vaapi_picture_decode (picture))
+    goto error;
+  if (!gst_vaapi_picture_output (picture))
+    goto error;
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+drop_frame:
+  {
+    priv->decoder_state = 0;
+    return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME;
+  }
+}
+
+static gboolean
+fill_picture (GstVaapiDecoderJpeg * decoder,
+    GstVaapiPicture * picture, GstJpegFrameHdr * frame_hdr)
+{
+  VAPictureParameterBufferJPEGBaseline *const pic_param = picture->param;
+  guint i;
+
+  memset (pic_param, 0, sizeof (VAPictureParameterBufferJPEGBaseline));
+  pic_param->picture_width = frame_hdr->width;
+  pic_param->picture_height = frame_hdr->height;
+
+  pic_param->num_components = frame_hdr->num_components;
+  if (frame_hdr->num_components > 4)
+    return FALSE;
+  for (i = 0; i < pic_param->num_components; i++) {
+    pic_param->components[i].component_id = frame_hdr->components[i].identifier;
+    pic_param->components[i].h_sampling_factor =
+        frame_hdr->components[i].horizontal_factor;
+    pic_param->components[i].v_sampling_factor =
+        frame_hdr->components[i].vertical_factor;
+    pic_param->components[i].quantiser_table_selector =
+        frame_hdr->components[i].quant_table_selector;
+  }
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+fill_quantization_table (GstVaapiDecoderJpeg * decoder,
+    GstVaapiPicture * picture)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+  VAIQMatrixBufferJPEGBaseline *iq_matrix;
+  guint i, j, num_tables;
+
+  if (!VALID_STATE (decoder, GOT_IQ_TABLE))
+    gst_jpeg_get_default_quantization_tables (&priv->quant_tables);
+
+  picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (JPEGBaseline, decoder);
+  if (!picture->iq_matrix) {
+    GST_ERROR ("failed to allocate quantiser table");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  iq_matrix = picture->iq_matrix->param;
+
+  num_tables = MIN (G_N_ELEMENTS (iq_matrix->quantiser_table),
+      GST_JPEG_MAX_QUANT_ELEMENTS);
+
+  for (i = 0; i < num_tables; i++) {
+    GstJpegQuantTable *const quant_table = &priv->quant_tables.quant_tables[i];
+
+    iq_matrix->load_quantiser_table[i] = quant_table->valid;
+    if (!iq_matrix->load_quantiser_table[i])
+      continue;
+
+    if (quant_table->quant_precision != 0) {
+      // Only Baseline profile is supported, thus 8-bit Qk values
+      GST_ERROR ("unsupported quantization table element precision");
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
+    }
+
+    for (j = 0; j < GST_JPEG_MAX_QUANT_ELEMENTS; j++)
+      iq_matrix->quantiser_table[i][j] = quant_table->quant_table[j];
+    iq_matrix->load_quantiser_table[i] = 1;
+    quant_table->valid = FALSE;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static gboolean
+huffman_tables_updated (const GstJpegHuffmanTables * huf_tables)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (huf_tables->dc_tables); i++)
+    if (huf_tables->dc_tables[i].valid)
+      return TRUE;
+  for (i = 0; i < G_N_ELEMENTS (huf_tables->ac_tables); i++)
+    if (huf_tables->ac_tables[i].valid)
+      return TRUE;
+  return FALSE;
+}
+
+static void
+huffman_tables_reset (GstJpegHuffmanTables * huf_tables)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (huf_tables->dc_tables); i++)
+    huf_tables->dc_tables[i].valid = FALSE;
+  for (i = 0; i < G_N_ELEMENTS (huf_tables->ac_tables); i++)
+    huf_tables->ac_tables[i].valid = FALSE;
+}
+
+static void
+fill_huffman_table (GstVaapiHuffmanTable * huf_table,
+    const GstJpegHuffmanTables * huf_tables)
+{
+  VAHuffmanTableBufferJPEGBaseline *const huffman_table = huf_table->param;
+  guint i, num_tables;
+
+  num_tables = MIN (G_N_ELEMENTS (huffman_table->huffman_table),
+      GST_JPEG_MAX_SCAN_COMPONENTS);
+
+  for (i = 0; i < num_tables; i++) {
+    huffman_table->load_huffman_table[i] =
+        huf_tables->dc_tables[i].valid && huf_tables->ac_tables[i].valid;
+    if (!huffman_table->load_huffman_table[i])
+      continue;
+
+    memcpy (huffman_table->huffman_table[i].num_dc_codes,
+        huf_tables->dc_tables[i].huf_bits,
+        sizeof (huffman_table->huffman_table[i].num_dc_codes));
+    memcpy (huffman_table->huffman_table[i].dc_values,
+        huf_tables->dc_tables[i].huf_values,
+        sizeof (huffman_table->huffman_table[i].dc_values));
+    memcpy (huffman_table->huffman_table[i].num_ac_codes,
+        huf_tables->ac_tables[i].huf_bits,
+        sizeof (huffman_table->huffman_table[i].num_ac_codes));
+    memcpy (huffman_table->huffman_table[i].ac_values,
+        huf_tables->ac_tables[i].huf_values,
+        sizeof (huffman_table->huffman_table[i].ac_values));
+    memset (huffman_table->huffman_table[i].pad,
+        0, sizeof (huffman_table->huffman_table[i].pad));
+  }
+}
+
+static void
+get_max_sampling_factors (const GstJpegFrameHdr * frame_hdr,
+    guint * h_max_ptr, guint * v_max_ptr)
+{
+  guint h_max = frame_hdr->components[0].horizontal_factor;
+  guint v_max = frame_hdr->components[0].vertical_factor;
+  guint i;
+
+  for (i = 1; i < frame_hdr->num_components; i++) {
+    const GstJpegFrameComponent *const fcp = &frame_hdr->components[i];
+    if (h_max < fcp->horizontal_factor)
+      h_max = fcp->horizontal_factor;
+    if (v_max < fcp->vertical_factor)
+      v_max = fcp->vertical_factor;
+  }
+
+  if (h_max_ptr)
+    *h_max_ptr = h_max;
+  if (v_max_ptr)
+    *v_max_ptr = v_max;
+}
+
+static const GstJpegFrameComponent *
+get_component (const GstJpegFrameHdr * frame_hdr, guint selector)
+{
+  guint i;
+
+  for (i = 0; i < frame_hdr->num_components; i++) {
+    const GstJpegFrameComponent *const fcp = &frame_hdr->components[i];
+    if (fcp->identifier == selector)
+      return fcp;
+  }
+  return NULL;
+}
+
+static GstVaapiDecoderStatus
+decode_picture (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+  GstJpegFrameHdr *const frame_hdr = &priv->frame_hdr;
+
+  if (!VALID_STATE (decoder, GOT_SOI))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  switch (seg->marker) {
+    case GST_JPEG_MARKER_SOF_MIN:
+      priv->profile = GST_VAAPI_PROFILE_JPEG_BASELINE;
+      break;
+    default:
+      GST_ERROR ("unsupported profile %d", seg->marker);
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  memset (frame_hdr, 0, sizeof (*frame_hdr));
+  if (!gst_jpeg_segment_parse_frame_header (seg, frame_hdr)) {
+    GST_ERROR ("failed to parse image");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  if (priv->height != frame_hdr->height || priv->width != frame_hdr->width)
+    priv->size_changed = TRUE;
+
+  priv->height = frame_hdr->height;
+  priv->width = frame_hdr->width;
+
+  priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOF;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_huffman_table (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+
+  if (!VALID_STATE (decoder, GOT_SOI))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_jpeg_segment_parse_huffman_table (seg, &priv->huf_tables)) {
+    GST_ERROR ("failed to parse Huffman table");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_HUF_TABLE;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_quant_table (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+
+  if (!VALID_STATE (decoder, GOT_SOI))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_jpeg_segment_parse_quantization_table (seg, &priv->quant_tables)) {
+    GST_ERROR ("failed to parse quantization table");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_IQ_TABLE;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_restart_interval (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+
+  if (!VALID_STATE (decoder, GOT_SOI))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_jpeg_segment_parse_restart_interval (seg, &priv->mcu_restart)) {
+    GST_ERROR ("failed to parse restart interval");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_scan (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->current_picture;
+  GstVaapiSlice *slice;
+  VASliceParameterBufferJPEGBaseline *slice_param;
+  GstJpegScanHdr scan_hdr;
+  guint scan_hdr_size, scan_data_size;
+  guint i, h_max, v_max, mcu_width, mcu_height;
+
+  if (!VALID_STATE (decoder, GOT_SOF))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  scan_hdr_size = (seg->data[seg->offset] << 8) | seg->data[seg->offset + 1];
+  scan_data_size = seg->size - scan_hdr_size;
+
+  memset (&scan_hdr, 0, sizeof (scan_hdr));
+  if (!gst_jpeg_segment_parse_scan_header (seg, &scan_hdr)) {
+    GST_ERROR ("failed to parse scan header");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  slice = GST_VAAPI_SLICE_NEW (JPEGBaseline, decoder,
+      seg->data + seg->offset + scan_hdr_size, scan_data_size);
+  if (!slice) {
+    GST_ERROR ("failed to allocate slice");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  gst_vaapi_picture_add_slice (picture, slice);
+
+  if (!VALID_STATE (decoder, GOT_HUF_TABLE))
+    gst_jpeg_get_default_huffman_tables (&priv->huf_tables);
+
+  // Update VA Huffman table if it changed for this scan
+  if (huffman_tables_updated (&priv->huf_tables)) {
+    slice->huf_table = GST_VAAPI_HUFFMAN_TABLE_NEW (JPEGBaseline, decoder);
+    if (!slice->huf_table) {
+      GST_ERROR ("failed to allocate Huffman tables");
+      huffman_tables_reset (&priv->huf_tables);
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+    fill_huffman_table (slice->huf_table, &priv->huf_tables);
+    huffman_tables_reset (&priv->huf_tables);
+  }
+
+  slice_param = slice->param;
+  slice_param->num_components = scan_hdr.num_components;
+  for (i = 0; i < scan_hdr.num_components; i++) {
+    slice_param->components[i].component_selector =
+        scan_hdr.components[i].component_selector;
+    slice_param->components[i].dc_table_selector =
+        scan_hdr.components[i].dc_selector;
+    slice_param->components[i].ac_table_selector =
+        scan_hdr.components[i].ac_selector;
+  }
+  slice_param->restart_interval = priv->mcu_restart;
+  slice_param->slice_horizontal_position = 0;
+  slice_param->slice_vertical_position = 0;
+
+  get_max_sampling_factors (&priv->frame_hdr, &h_max, &v_max);
+  mcu_width = 8 * h_max;
+  mcu_height = 8 * v_max;
+
+  if (scan_hdr.num_components == 1) {   // Non-interleaved
+    const guint Csj = slice_param->components[0].component_selector;
+    const GstJpegFrameComponent *const fcp =
+        get_component (&priv->frame_hdr, Csj);
+
+    if (!fcp || fcp->horizontal_factor == 0 || fcp->vertical_factor == 0) {
+      GST_ERROR ("failed to validate image component %u", Csj);
+      return GST_VAAPI_DECODER_STATUS_ERROR_INVALID_PARAMETER;
+    }
+    mcu_width /= fcp->horizontal_factor;
+    mcu_height /= fcp->vertical_factor;
+  }
+  slice_param->num_mcus =
+      ((priv->frame_hdr.width + mcu_width - 1) / mcu_width) *
+      ((priv->frame_hdr.height + mcu_height - 1) / mcu_height);
+
+  priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOS;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_segment (GstVaapiDecoderJpeg * decoder, GstJpegSegment * seg)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+
+  // Decode segment
+  status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  switch (seg->marker) {
+    case GST_JPEG_MARKER_SOI:
+      priv->mcu_restart = 0;
+      priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOI;
+      break;
+    case GST_JPEG_MARKER_EOI:
+      priv->decoder_state = 0;
+      break;
+    case GST_JPEG_MARKER_DAC:
+      GST_ERROR ("unsupported arithmetic coding mode");
+      status = GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+      break;
+    case GST_JPEG_MARKER_DHT:
+      status = decode_huffman_table (decoder, seg);
+      break;
+    case GST_JPEG_MARKER_DQT:
+      status = decode_quant_table (decoder, seg);
+      break;
+    case GST_JPEG_MARKER_DRI:
+      status = decode_restart_interval (decoder, seg);
+      break;
+    case GST_JPEG_MARKER_SOS:
+      status = decode_scan (decoder, seg);
+      break;
+    default:
+      // SOFn segments
+      if (seg->marker >= GST_JPEG_MARKER_SOF_MIN &&
+          seg->marker <= GST_JPEG_MARKER_SOF_MAX)
+        status = decode_picture (decoder, seg);
+      break;
+  }
+  return status;
+}
+
+static GstVaapiDecoderStatus
+ensure_decoder (GstVaapiDecoderJpeg * decoder)
+{
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+
+  if (!priv->is_opened) {
+    priv->is_opened = gst_vaapi_decoder_jpeg_open (decoder);
+    if (!priv->is_opened)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static gboolean
+is_scan_complete (GstJpegMarker marker)
+{
+  // Scan is assumed to be complete when the new segment is not RSTi
+  return marker < GST_JPEG_MARKER_RST_MIN || marker > GST_JPEG_MARKER_RST_MAX;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_jpeg_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderJpeg *const decoder =
+      GST_VAAPI_DECODER_JPEG_CAST (base_decoder);
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+  GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder);
+  GstVaapiDecoderStatus status;
+  GstJpegMarker marker;
+  GstJpegSegment seg;
+  const guchar *buf;
+  guint buf_size, flags;
+  gint ofs1, ofs2;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  /* Expect at least 2 bytes for the marker */
+  buf_size = gst_adapter_available (adapter);
+  if (buf_size < 2)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  buf = gst_adapter_map (adapter, buf_size);
+  if (!buf)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  ofs1 = ps->input_offset1 - 2;
+  if (ofs1 < 0)
+    ofs1 = 0;
+
+  for (;;) {
+    // Skip any garbage until we reach SOI, if needed
+    if (!gst_jpeg_parse (&seg, buf, buf_size, ofs1)) {
+      gst_adapter_unmap (adapter);
+      ps->input_offset1 = buf_size;
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    }
+    ofs1 = seg.offset;
+
+    marker = seg.marker;
+    if (!VALID_STATE (parser, GOT_SOI) && marker != GST_JPEG_MARKER_SOI)
+      continue;
+    if (marker == GST_JPEG_MARKER_SOS) {
+      ofs2 = ps->input_offset2 - 2;
+      if (ofs2 < ofs1 + seg.size)
+        ofs2 = ofs1 + seg.size;
+
+      // Parse the whole scan + ECSs, including RSTi
+      for (;;) {
+        if (!gst_jpeg_parse (&seg, buf, buf_size, ofs2)) {
+          gst_adapter_unmap (adapter);
+          ps->input_offset1 = ofs1;
+          ps->input_offset2 = buf_size;
+          return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+        }
+
+        if (is_scan_complete (seg.marker))
+          break;
+        ofs2 = seg.offset + seg.size;
+      }
+      ofs2 = seg.offset - 2;
+    } else {
+      // Check that the whole segment is actually available (in buffer)
+      ofs2 = ofs1 + seg.size;
+      if (ofs2 > buf_size) {
+        gst_adapter_unmap (adapter);
+        ps->input_offset1 = ofs1;
+        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+      }
+    }
+    break;
+  }
+  gst_adapter_unmap (adapter);
+
+  unit->size = ofs2 - ofs1;
+  unit_set_marker_code (unit, marker);
+  gst_adapter_flush (adapter, ofs1);
+  ps->input_offset1 = 2;
+  ps->input_offset2 = 2;
+
+  flags = 0;
+  switch (marker) {
+    case GST_JPEG_MARKER_SOI:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOI;
+      break;
+    case GST_JPEG_MARKER_EOI:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      priv->parser_state = 0;
+      break;
+    case GST_JPEG_MARKER_SOS:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOS;
+      break;
+    case GST_JPEG_MARKER_DAC:
+    case GST_JPEG_MARKER_DHT:
+    case GST_JPEG_MARKER_DQT:
+      if (priv->parser_state & GST_JPEG_VIDEO_STATE_GOT_SOF)
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      break;
+    case GST_JPEG_MARKER_DRI:
+      if (priv->parser_state & GST_JPEG_VIDEO_STATE_GOT_SOS)
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      break;
+    case GST_JPEG_MARKER_DNL:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      break;
+    case GST_JPEG_MARKER_COM:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+      break;
+    default:
+      /* SOFn segments */
+      if (marker >= GST_JPEG_MARKER_SOF_MIN &&
+          marker <= GST_JPEG_MARKER_SOF_MAX)
+        priv->parser_state |= GST_JPEG_VIDEO_STATE_GOT_SOF;
+
+      /* Application segments */
+      else if (marker >= GST_JPEG_MARKER_APP_MIN &&
+          marker <= GST_JPEG_MARKER_APP_MAX)
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+
+      /* Reserved */
+      else if (marker >= 0x02 && marker <= 0xbf)
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+      break;
+  }
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_jpeg_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderJpeg *const decoder =
+      GST_VAAPI_DECODER_JPEG_CAST (base_decoder);
+  GstVaapiDecoderStatus status;
+  GstJpegSegment seg;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  seg.marker = unit_get_marker_code (unit);
+  seg.data = map_info.data;
+  seg.offset = unit->offset;
+  seg.size = unit->size;
+
+  status = decode_segment (decoder, &seg);
+  gst_buffer_unmap (buffer, &map_info);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_jpeg_start_frame (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * base_unit)
+{
+  GstVaapiDecoderJpeg *const decoder =
+      GST_VAAPI_DECODER_JPEG_CAST (base_decoder);
+  GstVaapiDecoderJpegPrivate *const priv = &decoder->priv;
+  GstVaapiPicture *picture;
+  GstVaapiDecoderStatus status;
+
+  if (!VALID_STATE (decoder, GOT_SOF))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  status = ensure_context (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    GST_ERROR ("failed to reset context");
+    return status;
+  }
+
+  picture = GST_VAAPI_PICTURE_NEW (JPEGBaseline, decoder);
+  if (!picture) {
+    GST_ERROR ("failed to allocate picture");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  gst_vaapi_picture_replace (&priv->current_picture, picture);
+  gst_vaapi_picture_unref (picture);
+
+  if (!fill_picture (decoder, picture, &priv->frame_hdr))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  status = fill_quantization_table (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  /* Update presentation time */
+  picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_jpeg_end_frame (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderJpeg *const decoder =
+      GST_VAAPI_DECODER_JPEG_CAST (base_decoder);
+
+  return decode_current_picture (decoder);
+}
+
+static void
+gst_vaapi_decoder_jpeg_finalize (GObject * object)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
+
+  gst_vaapi_decoder_jpeg_destroy (base_decoder);
+  G_OBJECT_CLASS (gst_vaapi_decoder_jpeg_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_jpeg_class_init (GstVaapiDecoderJpegClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_decoder_jpeg_finalize;
+
+  decoder_class->reset = gst_vaapi_decoder_jpeg_reset;
+  decoder_class->parse = gst_vaapi_decoder_jpeg_parse;
+  decoder_class->decode = gst_vaapi_decoder_jpeg_decode;
+  decoder_class->start_frame = gst_vaapi_decoder_jpeg_start_frame;
+  decoder_class->end_frame = gst_vaapi_decoder_jpeg_end_frame;
+}
+
+static void
+gst_vaapi_decoder_jpeg_init (GstVaapiDecoderJpeg * decoder)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+
+  gst_vaapi_decoder_jpeg_create (base_decoder);
+}
+
+/**
+ * gst_vaapi_decoder_jpeg_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for JPEG decoding.  The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_jpeg_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return g_object_new (GST_TYPE_VAAPI_DECODER_JPEG, "display", display,
+      "caps", caps, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.h
new file mode 100644 (file)
index 0000000..5c1b4af
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  gstvaapidecoder_jpeg.h - JPEG decoder
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_JPEG_H
+#define GST_VAAPI_DECODER_JPEG_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER_JPEG \
+    (gst_vaapi_decoder_jpeg_get_type ())
+#define GST_VAAPI_DECODER_JPEG(decoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_JPEG, GstVaapiDecoderJpeg))
+#define GST_VAAPI_IS_DECODER_JPEG(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_JPEG))
+
+typedef struct _GstVaapiDecoderJpeg             GstVaapiDecoderJpeg;
+
+GType
+gst_vaapi_decoder_jpeg_get_type (void) G_GNUC_CONST;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_jpeg_new (GstVaapiDisplay *display, GstCaps *caps);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderJpeg, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_JPEG_H */
+
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.c
new file mode 100644 (file)
index 0000000..3855aa0
--- /dev/null
@@ -0,0 +1,1624 @@
+/*
+ *  gstvaapidecoder_mpeg2.c - MPEG-2 decoder
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_mpeg2
+ * @short_description: MPEG-2 decoder
+ */
+
+#include "sysdeps.h"
+#include <gst/base/gstbitreader.h>
+#include <gst/codecparsers/gstmpegvideoparser.h>
+#include "gstvaapidecoder_mpeg2.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_dpb.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/* ------------------------------------------------------------------------- */
+/* --- PTS Generator                                                     --- */
+/* ------------------------------------------------------------------------- */
+
+typedef struct _PTSGenerator PTSGenerator;
+struct _PTSGenerator
+{
+  GstClockTime gop_pts;         // Current GOP PTS
+  GstClockTime max_pts;         // Max picture PTS
+  guint gop_tsn;                // Absolute GOP TSN
+  guint max_tsn;                // Max picture TSN, relative to last GOP TSN
+  guint ovl_tsn;                // How many times TSN overflowed since GOP
+  guint lst_tsn;                // Last picture TSN
+  guint fps_n;
+  guint fps_d;
+};
+
+static void
+pts_init (PTSGenerator * tsg)
+{
+  tsg->gop_pts = GST_CLOCK_TIME_NONE;
+  tsg->max_pts = GST_CLOCK_TIME_NONE;
+  tsg->gop_tsn = 0;
+  tsg->max_tsn = 0;
+  tsg->ovl_tsn = 0;
+  tsg->lst_tsn = 0;
+  tsg->fps_n = 0;
+  tsg->fps_d = 0;
+}
+
+static inline GstClockTime
+pts_get_duration (PTSGenerator * tsg, guint num_frames)
+{
+  return gst_util_uint64_scale (num_frames,
+      GST_SECOND * tsg->fps_d, tsg->fps_n);
+}
+
+static inline guint
+pts_get_poc (PTSGenerator * tsg)
+{
+  return tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->lst_tsn;
+}
+
+static void
+pts_set_framerate (PTSGenerator * tsg, guint fps_n, guint fps_d)
+{
+  tsg->fps_n = fps_n;
+  tsg->fps_d = fps_d;
+}
+
+static void
+pts_sync (PTSGenerator * tsg, GstClockTime gop_pts)
+{
+  guint gop_tsn;
+
+  if (!GST_CLOCK_TIME_IS_VALID (gop_pts) ||
+      (GST_CLOCK_TIME_IS_VALID (tsg->max_pts) && tsg->max_pts >= gop_pts)) {
+    /* Invalid GOP PTS, interpolate from the last known picture PTS */
+    if (GST_CLOCK_TIME_IS_VALID (tsg->max_pts)) {
+      gop_pts = tsg->max_pts + pts_get_duration (tsg, 1);
+      gop_tsn = tsg->gop_tsn + tsg->ovl_tsn * 1024 + tsg->max_tsn + 1;
+    } else {
+      gop_pts = 0;
+      gop_tsn = 0;
+    }
+  } else {
+    /* Interpolate GOP TSN from this valid PTS */
+    if (GST_CLOCK_TIME_IS_VALID (tsg->gop_pts))
+      gop_tsn =
+          tsg->gop_tsn + gst_util_uint64_scale (gop_pts - tsg->gop_pts +
+          pts_get_duration (tsg, 1) - 1, tsg->fps_n, GST_SECOND * tsg->fps_d);
+    else
+      gop_tsn = 0;
+  }
+
+  tsg->gop_pts = gop_pts;
+  tsg->gop_tsn = gop_tsn;
+  tsg->max_tsn = 0;
+  tsg->ovl_tsn = 0;
+  tsg->lst_tsn = 0;
+}
+
+static GstClockTime
+pts_eval (PTSGenerator * tsg, GstClockTime pic_pts, guint pic_tsn)
+{
+  GstClockTime pts;
+
+  if (!GST_CLOCK_TIME_IS_VALID (tsg->gop_pts))
+    tsg->gop_pts = pts_get_duration (tsg, pic_tsn);
+
+  pts = pic_pts;
+  if (!GST_CLOCK_TIME_IS_VALID (pts))
+    pts = tsg->gop_pts + pts_get_duration (tsg, tsg->ovl_tsn * 1024 + pic_tsn);
+  else if (pts == tsg->gop_pts) {
+    /* The picture following the GOP header shall be an I-frame.
+       So we can compensate for the GOP start time from here */
+    tsg->gop_pts -= pts_get_duration (tsg, pic_tsn);
+  }
+
+  if (!GST_CLOCK_TIME_IS_VALID (tsg->max_pts) || tsg->max_pts < pts)
+    tsg->max_pts = pts;
+
+  if (tsg->max_tsn < pic_tsn)
+    tsg->max_tsn = pic_tsn;
+  else if (tsg->max_tsn == 1023 && pic_tsn < tsg->lst_tsn) {    /* TSN wrapped */
+    tsg->max_tsn = pic_tsn;
+    tsg->ovl_tsn++;
+  }
+  tsg->lst_tsn = pic_tsn;
+
+  return pts;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- MPEG-2 Parser Info                                                --- */
+/* ------------------------------------------------------------------------- */
+
+typedef struct _GstVaapiParserInfoMpeg2 GstVaapiParserInfoMpeg2;
+struct _GstVaapiParserInfoMpeg2
+{
+  GstVaapiMiniObject parent_instance;
+  GstMpegVideoPacket packet;
+  guint8 extension_type;        /* for Extension packets */
+  union
+  {
+    GstMpegVideoSequenceHdr seq_hdr;
+    GstMpegVideoSequenceExt seq_ext;
+    GstMpegVideoSequenceDisplayExt seq_display_ext;
+    GstMpegVideoSequenceScalableExt seq_scalable_ext;
+    GstMpegVideoGop gop;
+    GstMpegVideoQuantMatrixExt quant_matrix;
+    GstMpegVideoPictureHdr pic_hdr;
+    GstMpegVideoPictureExt pic_ext;
+    GstMpegVideoSliceHdr slice_hdr;
+  } data;
+};
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_parser_info_mpeg2_class (void)
+{
+  static const GstVaapiMiniObjectClass GstVaapiParserInfoMpeg2Class = {
+    sizeof (GstVaapiParserInfoMpeg2),
+    NULL
+  };
+  return &GstVaapiParserInfoMpeg2Class;
+}
+
+static inline GstVaapiParserInfoMpeg2 *
+gst_vaapi_parser_info_mpeg2_new (void)
+{
+  return (GstVaapiParserInfoMpeg2 *)
+      gst_vaapi_mini_object_new (gst_vaapi_parser_info_mpeg2_class ());
+}
+
+static inline GstVaapiParserInfoMpeg2 *
+gst_vaapi_parser_info_mpeg2_ensure (GstVaapiParserInfoMpeg2 ** pi_ptr)
+{
+  GstVaapiParserInfoMpeg2 *pi = *pi_ptr;
+
+  if (G_LIKELY (pi != NULL))
+    return pi;
+
+  *pi_ptr = pi = gst_vaapi_parser_info_mpeg2_new ();
+  return pi;
+}
+
+#define gst_vaapi_parser_info_mpeg2_ref(pi) \
+    gst_vaapi_mini_object_ref(GST_VAAPI_MINI_OBJECT(pi))
+
+#define gst_vaapi_parser_info_mpeg2_unref(pi) \
+    gst_vaapi_mini_object_unref(GST_VAAPI_MINI_OBJECT(pi))
+
+#define gst_vaapi_parser_info_mpeg2_replace(old_pi_ptr, new_pi)         \
+    gst_vaapi_mini_object_replace((GstVaapiMiniObject **)(old_pi_ptr),  \
+        (GstVaapiMiniObject *)(new_pi))
+
+/* ------------------------------------------------------------------------- */
+/* --- MPEG-2 Decoder                                                    --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_DECODER_MPEG2_CAST(decoder) \
+    ((GstVaapiDecoderMpeg2 *)(decoder))
+
+typedef struct _GstVaapiDecoderMpeg2Private GstVaapiDecoderMpeg2Private;
+typedef struct _GstVaapiDecoderMpeg2Class GstVaapiDecoderMpeg2Class;
+
+typedef enum
+{
+  GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR = 1 << 0,
+  GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT = 1 << 1,
+  GST_MPEG_VIDEO_STATE_GOT_PIC_HDR = 1 << 2,
+  GST_MPEG_VIDEO_STATE_GOT_PIC_EXT = 1 << 3,
+  GST_MPEG_VIDEO_STATE_GOT_SLICE = 1 << 4,
+
+  GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS = (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR |
+      GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT),
+  GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS = (GST_MPEG_VIDEO_STATE_GOT_PIC_HDR |
+      GST_MPEG_VIDEO_STATE_GOT_PIC_EXT),
+  GST_MPEG_VIDEO_STATE_VALID_PICTURE = (GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS |
+      GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS | GST_MPEG_VIDEO_STATE_GOT_SLICE)
+} GstMpegVideoState;
+
+struct _GstVaapiDecoderMpeg2Private
+{
+  GstVaapiProfile profile;
+  GstVaapiProfile hw_profile;
+  guint width;
+  guint height;
+  guint fps_n;
+  guint fps_d;
+  guint state;
+  GstVaapiRectangle crop_rect;
+  GstVaapiParserInfoMpeg2 *seq_hdr;
+  GstVaapiParserInfoMpeg2 *seq_ext;
+  GstVaapiParserInfoMpeg2 *seq_display_ext;
+  GstVaapiParserInfoMpeg2 *seq_scalable_ext;
+  GstVaapiParserInfoMpeg2 *gop;
+  GstVaapiParserInfoMpeg2 *pic_hdr;
+  GstVaapiParserInfoMpeg2 *pic_ext;
+  GstVaapiParserInfoMpeg2 *pic_display_ext;
+  GstVaapiParserInfoMpeg2 *quant_matrix;
+  GstVaapiParserInfoMpeg2 *slice_hdr;
+  GstVaapiPicture *current_picture;
+  GstVaapiDpb *dpb;
+  PTSGenerator tsg;
+  guint is_opened:1;
+  guint size_changed:1;
+  guint profile_changed:1;
+  guint quant_matrix_changed:1;
+  guint progressive_sequence:1;
+  guint closed_gop:1;
+  guint broken_link:1;
+};
+
+/**
+ * GstVaapiDecoderMpeg2:
+ *
+ * A decoder based on Mpeg2.
+ */
+struct _GstVaapiDecoderMpeg2
+{
+  /*< private > */
+  GstVaapiDecoder parent_instance;
+  GstVaapiDecoderMpeg2Private priv;
+};
+
+/**
+ * GstVaapiDecoderMpeg2Class:
+ *
+ * A decoder class based on Mpeg2.
+ */
+struct _GstVaapiDecoderMpeg2Class
+{
+  /*< private > */
+  GstVaapiDecoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiDecoderMpeg2, gst_vaapi_decoder_mpeg2,
+    GST_TYPE_VAAPI_DECODER);
+
+static void
+gst_vaapi_decoder_mpeg2_close (GstVaapiDecoderMpeg2 * decoder)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+
+  gst_vaapi_parser_info_mpeg2_replace (&priv->seq_hdr, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->seq_ext, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->seq_display_ext, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->seq_scalable_ext, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->gop, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->pic_hdr, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->pic_ext, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->pic_display_ext, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->quant_matrix, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->slice_hdr, NULL);
+
+  priv->state = 0;
+
+  gst_vaapi_dpb_replace (&priv->dpb, NULL);
+
+  priv->is_opened = FALSE;
+}
+
+static gboolean
+gst_vaapi_decoder_mpeg2_open (GstVaapiDecoderMpeg2 * decoder)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_mpeg2_close (decoder);
+
+  priv->dpb = gst_vaapi_dpb_new (2);
+  if (!priv->dpb)
+    return FALSE;
+
+  pts_init (&priv->tsg);
+  return TRUE;
+}
+
+static void
+gst_vaapi_decoder_mpeg2_destroy (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderMpeg2 *const decoder =
+      GST_VAAPI_DECODER_MPEG2_CAST (base_decoder);
+
+  gst_vaapi_decoder_mpeg2_close (decoder);
+}
+
+static gboolean
+gst_vaapi_decoder_mpeg2_create (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderMpeg2 *const decoder =
+      GST_VAAPI_DECODER_MPEG2_CAST (base_decoder);
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+
+  priv->hw_profile = GST_VAAPI_PROFILE_UNKNOWN;
+  priv->profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
+  priv->profile_changed = TRUE; /* Allow fallbacks to work */
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg2_reset (GstVaapiDecoder * base_decoder)
+{
+  gst_vaapi_decoder_mpeg2_destroy (base_decoder);
+  gst_vaapi_decoder_mpeg2_create (base_decoder);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline void
+copy_quant_matrix (guint8 dst[64], const guint8 src[64])
+{
+  memcpy (dst, src, 64);
+}
+
+static const char *
+get_profile_str (GstVaapiProfile profile)
+{
+  const char *str;
+
+  switch (profile) {
+    case GST_VAAPI_PROFILE_MPEG2_SIMPLE:
+      str = "simple";
+      break;
+    case GST_VAAPI_PROFILE_MPEG2_MAIN:
+      str = "main";
+      break;
+    case GST_VAAPI_PROFILE_MPEG2_HIGH:
+      str = "high";
+      break;
+    default:
+      str = "<unknown>";
+      break;
+  }
+  return str;
+}
+
+static GstVaapiProfile
+get_profile (GstVaapiDecoderMpeg2 * decoder, GstVaapiEntrypoint entrypoint)
+{
+  GstVaapiDisplay *const va_display = GST_VAAPI_DECODER_DISPLAY (decoder);
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstVaapiProfile profile = priv->profile;
+
+  do {
+    /* Return immediately if the exact same profile was found */
+    if (gst_vaapi_display_has_decoder (va_display, profile, entrypoint))
+      break;
+
+    /* Otherwise, try to map to a higher profile */
+    switch (profile) {
+      case GST_VAAPI_PROFILE_MPEG2_SIMPLE:
+        profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
+        break;
+      case GST_VAAPI_PROFILE_MPEG2_MAIN:
+        profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
+        break;
+      case GST_VAAPI_PROFILE_MPEG2_HIGH:
+        // Try to map to main profile if no high profile specific bits used
+        if (priv->profile == profile &&
+            !priv->seq_scalable_ext &&
+            (priv->seq_ext && priv->seq_ext->data.seq_ext.chroma_format == 1)) {
+          profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
+          break;
+        }
+        // fall-through
+      default:
+        profile = GST_VAAPI_PROFILE_UNKNOWN;
+        break;
+    }
+  } while (profile != GST_VAAPI_PROFILE_UNKNOWN);
+
+  if (profile != priv->profile)
+    GST_INFO ("forced %s profile to %s profile",
+        get_profile_str (priv->profile), get_profile_str (profile));
+  return profile;
+}
+
+static GstVaapiDecoderStatus
+ensure_context (GstVaapiDecoderMpeg2 * decoder)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+  gboolean reset_context = FALSE;
+
+  if (priv->profile_changed) {
+    GST_DEBUG ("profile changed");
+    priv->profile_changed = FALSE;
+    reset_context = TRUE;
+
+    priv->hw_profile = get_profile (decoder, entrypoint);
+    if (priv->hw_profile == GST_VAAPI_PROFILE_UNKNOWN)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  if (priv->size_changed) {
+    GST_DEBUG ("size changed");
+    priv->size_changed = FALSE;
+    reset_context = TRUE;
+  }
+
+  if (reset_context) {
+    GstVaapiContextInfo info;
+
+    info.profile = priv->hw_profile;
+    info.entrypoint = entrypoint;
+    info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+    info.width = priv->width;
+    info.height = priv->height;
+    info.ref_frames = 2;
+    reset_context =
+        gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER_CAST (decoder),
+        &info);
+    if (!reset_context)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+ensure_quant_matrix (GstVaapiDecoderMpeg2 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSequenceHdr *const seq_hdr = &priv->seq_hdr->data.seq_hdr;
+  VAIQMatrixBufferMPEG2 *iq_matrix;
+  guint8 *intra_quant_matrix = NULL;
+  guint8 *non_intra_quant_matrix = NULL;
+  guint8 *chroma_intra_quant_matrix = NULL;
+  guint8 *chroma_non_intra_quant_matrix = NULL;
+
+  if (!priv->quant_matrix_changed)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  priv->quant_matrix_changed = FALSE;
+
+  picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (MPEG2, decoder);
+  if (!picture->iq_matrix) {
+    GST_ERROR ("failed to allocate IQ matrix");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  iq_matrix = picture->iq_matrix->param;
+
+  intra_quant_matrix = seq_hdr->intra_quantizer_matrix;
+  non_intra_quant_matrix = seq_hdr->non_intra_quantizer_matrix;
+
+  if (priv->quant_matrix) {
+    GstMpegVideoQuantMatrixExt *const quant_matrix =
+        &priv->quant_matrix->data.quant_matrix;
+    if (quant_matrix->load_intra_quantiser_matrix)
+      intra_quant_matrix = quant_matrix->intra_quantiser_matrix;
+    if (quant_matrix->load_non_intra_quantiser_matrix)
+      non_intra_quant_matrix = quant_matrix->non_intra_quantiser_matrix;
+    if (quant_matrix->load_chroma_intra_quantiser_matrix)
+      chroma_intra_quant_matrix = quant_matrix->chroma_intra_quantiser_matrix;
+    if (quant_matrix->load_chroma_non_intra_quantiser_matrix)
+      chroma_non_intra_quant_matrix =
+          quant_matrix->chroma_non_intra_quantiser_matrix;
+  }
+
+  iq_matrix->load_intra_quantiser_matrix = intra_quant_matrix != NULL;
+  if (intra_quant_matrix)
+    copy_quant_matrix (iq_matrix->intra_quantiser_matrix, intra_quant_matrix);
+
+  iq_matrix->load_non_intra_quantiser_matrix = non_intra_quant_matrix != NULL;
+  if (non_intra_quant_matrix)
+    copy_quant_matrix (iq_matrix->non_intra_quantiser_matrix,
+        non_intra_quant_matrix);
+
+  iq_matrix->load_chroma_intra_quantiser_matrix =
+      chroma_intra_quant_matrix != NULL;
+  if (chroma_intra_quant_matrix)
+    copy_quant_matrix (iq_matrix->chroma_intra_quantiser_matrix,
+        chroma_intra_quant_matrix);
+
+  iq_matrix->load_chroma_non_intra_quantiser_matrix =
+      chroma_non_intra_quant_matrix != NULL;
+  if (chroma_non_intra_quant_matrix)
+    copy_quant_matrix (iq_matrix->chroma_non_intra_quantiser_matrix,
+        chroma_non_intra_quant_matrix);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline gboolean
+is_valid_state (GstVaapiDecoderMpeg2 * decoder, guint state)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+
+  return (priv->state & state) == state;
+}
+
+static GstVaapiDecoderStatus
+decode_current_picture (GstVaapiDecoderMpeg2 * decoder)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->current_picture;
+
+  if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_PICTURE))
+    goto drop_frame;
+  priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS;
+
+  if (!picture)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_vaapi_picture_decode (picture))
+    goto error;
+  if (GST_VAAPI_PICTURE_IS_COMPLETE (picture)) {
+    if (!gst_vaapi_dpb_add (priv->dpb, picture))
+      goto error;
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    /* XXX: fix for cases where first field failed to be decoded */
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+drop_frame:
+  {
+    priv->state &= GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS;
+    return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME;
+  }
+}
+
+static GstVaapiDecoderStatus
+parse_sequence (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSequenceHdr *seq_hdr;
+
+  priv->state = 0;
+
+  if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->seq_hdr)) {
+    GST_ERROR ("failed to allocate parser info for sequence header");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  seq_hdr = &priv->seq_hdr->data.seq_hdr;
+
+  if (!gst_mpeg_video_packet_parse_sequence_header (packet, seq_hdr)) {
+    GST_ERROR ("failed to parse sequence header");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, seq_hdr, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER_CAST (decoder);
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSequenceHdr *const seq_hdr = unit->parsed_info;
+
+  gst_vaapi_parser_info_mpeg2_replace (&priv->seq_ext, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->seq_display_ext, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->seq_scalable_ext, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->quant_matrix, NULL);
+  gst_vaapi_parser_info_mpeg2_replace (&priv->pic_display_ext, NULL);
+
+  priv->fps_n = seq_hdr->fps_n;
+  priv->fps_d = seq_hdr->fps_d;
+  pts_set_framerate (&priv->tsg, priv->fps_n, priv->fps_d);
+  gst_vaapi_decoder_set_framerate (base_decoder, priv->fps_n, priv->fps_d);
+
+  priv->width = seq_hdr->width;
+  priv->height = seq_hdr->height;
+  priv->size_changed = TRUE;
+  priv->quant_matrix_changed = TRUE;
+  priv->progressive_sequence = TRUE;
+
+  priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_sequence_ext (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSequenceExt *seq_ext;
+
+  priv->state &= GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR;
+
+  if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->seq_ext)) {
+    GST_ERROR ("failed to allocate parser info for sequence extension");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  seq_ext = &priv->seq_ext->data.seq_ext;
+
+  if (!gst_mpeg_video_packet_parse_sequence_extension (packet, seq_ext)) {
+    GST_ERROR ("failed to parse sequence-extension");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, seq_ext, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_ext (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER_CAST (decoder);
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSequenceExt *const seq_ext = unit->parsed_info;
+  GstVaapiProfile profile;
+  guint width, height;
+
+  if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  priv->progressive_sequence = seq_ext->progressive;
+  gst_vaapi_decoder_set_interlaced (base_decoder, !priv->progressive_sequence);
+
+  width = (priv->width & 0x0fff) | ((guint32) seq_ext->horiz_size_ext << 12);
+  height = (priv->height & 0x0fff) | ((guint32) seq_ext->vert_size_ext << 12);
+  GST_DEBUG ("video resolution %ux%u", width, height);
+
+  if (seq_ext->fps_n_ext && seq_ext->fps_d_ext) {
+    priv->fps_n *= seq_ext->fps_n_ext + 1;
+    priv->fps_d *= seq_ext->fps_d_ext + 1;
+    pts_set_framerate (&priv->tsg, priv->fps_n, priv->fps_d);
+    gst_vaapi_decoder_set_framerate (base_decoder, priv->fps_n, priv->fps_d);
+  }
+
+  if (priv->width != width) {
+    priv->width = width;
+    priv->size_changed = TRUE;
+  }
+
+  if (priv->height != height) {
+    priv->height = height;
+    priv->size_changed = TRUE;
+  }
+
+  switch (seq_ext->profile) {
+    case GST_MPEG_VIDEO_PROFILE_SIMPLE:
+      profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
+      break;
+    case GST_MPEG_VIDEO_PROFILE_MAIN:
+      profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
+      break;
+    case GST_MPEG_VIDEO_PROFILE_HIGH:
+      profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
+      break;
+    default:
+      GST_ERROR ("unsupported profile %d", seq_ext->profile);
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+  if (priv->profile != profile) {
+    priv->profile = profile;
+    priv->profile_changed = TRUE;
+  }
+
+  priv->state |= GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_sequence_display_ext (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSequenceDisplayExt *seq_display_ext;
+
+  if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->seq_display_ext)) {
+    GST_ERROR ("failed to allocate parser info for sequence display extension");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  seq_display_ext = &priv->seq_display_ext->data.seq_display_ext;
+
+  if (!gst_mpeg_video_packet_parse_sequence_display_extension (packet,
+          seq_display_ext)) {
+    GST_ERROR ("failed to parse sequence-display-extension");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, seq_display_ext, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_display_ext (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSequenceDisplayExt *seq_display_ext;
+
+  seq_display_ext = priv->seq_display_ext ?
+      &priv->seq_display_ext->data.seq_display_ext : NULL;
+
+  /* Update cropping rectangle */
+  if (seq_display_ext) {
+    GstVaapiRectangle *const crop_rect = &priv->crop_rect;
+    crop_rect->x = 0;
+    crop_rect->y = 0;
+    crop_rect->width = seq_display_ext->display_horizontal_size;
+    crop_rect->height = seq_display_ext->display_vertical_size;
+  }
+
+  /* XXX: handle color primaries */
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_sequence_scalable_ext (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSequenceScalableExt *seq_scalable_ext;
+
+  if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->seq_scalable_ext)) {
+    GST_ERROR
+        ("failed to allocate parser info for sequence scalable extension");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  seq_scalable_ext = &priv->seq_scalable_ext->data.seq_scalable_ext;
+
+  if (!gst_mpeg_video_packet_parse_sequence_scalable_extension (packet,
+          seq_scalable_ext)) {
+    GST_ERROR ("failed to parse sequence-scalable-extension");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, seq_scalable_ext, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_scalable_ext (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  /* XXX: unsupported header -- ignore */
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_end (GstVaapiDecoderMpeg2 * decoder)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+
+  if (priv->dpb)
+    gst_vaapi_dpb_flush (priv->dpb);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_quant_matrix_ext (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoQuantMatrixExt *quant_matrix;
+
+  if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->quant_matrix)) {
+    GST_ERROR ("failed to allocate parser info for quantization matrix");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  quant_matrix = &priv->quant_matrix->data.quant_matrix;
+
+  if (!gst_mpeg_video_packet_parse_quant_matrix_extension (packet,
+          quant_matrix)) {
+    GST_ERROR ("failed to parse quant-matrix-extension");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, quant_matrix, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_quant_matrix_ext (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+
+  priv->quant_matrix_changed = TRUE;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_gop (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoGop *gop;
+
+  if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->gop)) {
+    GST_ERROR ("failed to allocate parser info for GOP");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  gop = &priv->gop->data.gop;
+
+  if (!gst_mpeg_video_packet_parse_gop (packet, gop)) {
+    GST_ERROR ("failed to parse GOP");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, gop, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_gop (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoGop *const gop = unit->parsed_info;
+
+  priv->closed_gop = gop->closed_gop;
+  priv->broken_link = gop->broken_link;
+
+  GST_DEBUG ("GOP %02u:%02u:%02u:%02u (closed_gop %d, broken_link %d)",
+      gop->hour, gop->minute, gop->second, gop->frame,
+      priv->closed_gop, priv->broken_link);
+
+  pts_sync (&priv->tsg, GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_picture (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoPictureHdr *pic_hdr;
+
+  priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR |
+      GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT);
+
+  if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->pic_hdr)) {
+    GST_ERROR ("failed to allocate parser info for picture header");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  pic_hdr = &priv->pic_hdr->data.pic_hdr;
+
+  if (!gst_mpeg_video_packet_parse_picture_header (packet, pic_hdr)) {
+    GST_ERROR ("failed to parse picture header");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, pic_hdr, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_picture (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+
+  if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_SEQ_HEADERS))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  gst_vaapi_parser_info_mpeg2_replace (&priv->pic_ext, NULL);
+
+  priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_HDR;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+parse_picture_ext (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoPictureExt *pic_ext;
+
+  priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR |
+      GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT | GST_MPEG_VIDEO_STATE_GOT_PIC_HDR);
+
+  if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->pic_ext)) {
+    GST_ERROR ("failed to allocate parser info for picture extension");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  pic_ext = &priv->pic_ext->data.pic_ext;
+
+  if (!gst_mpeg_video_packet_parse_picture_extension (packet, pic_ext)) {
+    GST_ERROR ("failed to parse picture-extension");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, pic_ext, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_picture_ext (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoPictureExt *const pic_ext = unit->parsed_info;
+
+  if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_GOT_PIC_HDR))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (priv->progressive_sequence && !pic_ext->progressive_frame) {
+    GST_WARNING ("invalid interlaced frame in progressive sequence, fixing");
+    pic_ext->progressive_frame = 1;
+  }
+
+  if (pic_ext->picture_structure == 0 ||
+      (pic_ext->progressive_frame &&
+          pic_ext->picture_structure !=
+          GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME)) {
+    GST_WARNING ("invalid picture_structure %d, replacing with \"frame\"",
+        pic_ext->picture_structure);
+    pic_ext->picture_structure = GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME;
+  }
+
+  priv->state |= GST_MPEG_VIDEO_STATE_GOT_PIC_EXT;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline guint32
+pack_f_code (guint8 f_code[2][2])
+{
+  return (((guint32) f_code[0][0] << 12) |
+      ((guint32) f_code[0][1] << 8) |
+      ((guint32) f_code[1][0] << 4) | (f_code[1][1]));
+}
+
+static GstVaapiDecoderStatus
+init_picture (GstVaapiDecoderMpeg2 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoPictureHdr *const pic_hdr = &priv->pic_hdr->data.pic_hdr;
+  GstMpegVideoPictureExt *const pic_ext = &priv->pic_ext->data.pic_ext;
+
+  switch (pic_hdr->pic_type) {
+    case GST_MPEG_VIDEO_PICTURE_TYPE_I:
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
+      picture->type = GST_VAAPI_PICTURE_TYPE_I;
+      break;
+    case GST_MPEG_VIDEO_PICTURE_TYPE_P:
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
+      picture->type = GST_VAAPI_PICTURE_TYPE_P;
+      break;
+    case GST_MPEG_VIDEO_PICTURE_TYPE_B:
+      picture->type = GST_VAAPI_PICTURE_TYPE_B;
+      break;
+    default:
+      GST_ERROR ("unsupported picture type %d", pic_hdr->pic_type);
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (!priv->progressive_sequence && !pic_ext->progressive_frame) {
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_INTERLACED);
+    if (pic_ext->top_field_first)
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_TFF);
+  }
+
+  switch (pic_ext->picture_structure) {
+    case GST_MPEG_VIDEO_PICTURE_STRUCTURE_TOP_FIELD:
+      picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
+      break;
+    case GST_MPEG_VIDEO_PICTURE_STRUCTURE_BOTTOM_FIELD:
+      picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
+      break;
+    case GST_MPEG_VIDEO_PICTURE_STRUCTURE_FRAME:
+      picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+      break;
+  }
+
+  /* Allocate dummy picture for first field based I-frame */
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
+      !GST_VAAPI_PICTURE_IS_FRAME (picture) &&
+      gst_vaapi_dpb_size (priv->dpb) == 0) {
+    GstVaapiPicture *dummy_picture;
+    gboolean success;
+
+    dummy_picture = GST_VAAPI_PICTURE_NEW (MPEG2, decoder);
+    if (!dummy_picture) {
+      GST_ERROR ("failed to allocate dummy picture");
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+
+    dummy_picture->type = GST_VAAPI_PICTURE_TYPE_I;
+    dummy_picture->pts = GST_CLOCK_TIME_NONE;
+    dummy_picture->poc = -1;
+    dummy_picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+
+    GST_VAAPI_PICTURE_FLAG_SET (dummy_picture,
+        (GST_VAAPI_PICTURE_FLAG_SKIPPED |
+            GST_VAAPI_PICTURE_FLAG_OUTPUT | GST_VAAPI_PICTURE_FLAG_REFERENCE)
+        );
+
+    success = gst_vaapi_dpb_add (priv->dpb, dummy_picture);
+    gst_vaapi_picture_unref (dummy_picture);
+    if (!success) {
+      GST_ERROR ("failed to add dummy picture into DPB");
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    }
+    GST_INFO ("allocated dummy picture for first field based I-frame");
+  }
+
+  /* Update presentation time */
+  picture->pts = pts_eval (&priv->tsg,
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts, pic_hdr->tsn);
+  picture->poc = pts_get_poc (&priv->tsg);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+fill_picture (GstVaapiDecoderMpeg2 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  VAPictureParameterBufferMPEG2 *const pic_param = picture->param;
+  GstMpegVideoPictureHdr *const pic_hdr = &priv->pic_hdr->data.pic_hdr;
+  GstMpegVideoPictureExt *const pic_ext = &priv->pic_ext->data.pic_ext;
+  GstVaapiPicture *prev_picture, *next_picture;
+
+  /* Fill in VAPictureParameterBufferMPEG2 */
+  pic_param->horizontal_size = priv->width;
+  pic_param->vertical_size = priv->height;
+  pic_param->forward_reference_picture = VA_INVALID_ID;
+  pic_param->backward_reference_picture = VA_INVALID_ID;
+  pic_param->picture_coding_type = pic_hdr->pic_type;
+  pic_param->f_code = pack_f_code (pic_ext->f_code);
+
+#define COPY_FIELD(a, b, f) \
+    pic_param->a.b.f = pic_ext->f
+  pic_param->picture_coding_extension.value = 0;
+  pic_param->picture_coding_extension.bits.is_first_field =
+      GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture);
+  COPY_FIELD (picture_coding_extension, bits, intra_dc_precision);
+  COPY_FIELD (picture_coding_extension, bits, picture_structure);
+  COPY_FIELD (picture_coding_extension, bits, top_field_first);
+  COPY_FIELD (picture_coding_extension, bits, frame_pred_frame_dct);
+  COPY_FIELD (picture_coding_extension, bits, concealment_motion_vectors);
+  COPY_FIELD (picture_coding_extension, bits, q_scale_type);
+  COPY_FIELD (picture_coding_extension, bits, intra_vlc_format);
+  COPY_FIELD (picture_coding_extension, bits, alternate_scan);
+  COPY_FIELD (picture_coding_extension, bits, repeat_first_field);
+  COPY_FIELD (picture_coding_extension, bits, progressive_frame);
+
+  gst_vaapi_dpb_get_neighbours (priv->dpb, picture,
+      &prev_picture, &next_picture);
+
+  switch (pic_hdr->pic_type) {
+    case GST_MPEG_VIDEO_PICTURE_TYPE_B:
+      if (next_picture)
+        pic_param->backward_reference_picture = next_picture->surface_id;
+      if (prev_picture)
+        pic_param->forward_reference_picture = prev_picture->surface_id;
+      else if (!priv->closed_gop)
+        GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
+      break;
+    case GST_MPEG_VIDEO_PICTURE_TYPE_P:
+      if (prev_picture)
+        pic_param->forward_reference_picture = prev_picture->surface_id;
+      break;
+  }
+}
+
+static GstVaapiDecoderStatus
+parse_slice (GstVaapiDecoderMpeg2 * decoder,
+    GstVaapiDecoderUnit * unit, const GstMpegVideoPacket * packet)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSliceHdr *slice_hdr;
+  GstMpegVideoSequenceHdr *seq_hdr;
+  GstMpegVideoSequenceScalableExt *seq_scalable_ext;
+
+  priv->state &= (GST_MPEG_VIDEO_STATE_GOT_SEQ_HDR |
+      GST_MPEG_VIDEO_STATE_GOT_SEQ_EXT |
+      GST_MPEG_VIDEO_STATE_GOT_PIC_HDR | GST_MPEG_VIDEO_STATE_GOT_PIC_EXT);
+
+  if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_vaapi_parser_info_mpeg2_ensure (&priv->slice_hdr)) {
+    GST_ERROR ("failed to allocate parser info for slice header");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  slice_hdr = &priv->slice_hdr->data.slice_hdr;
+  seq_hdr = &priv->seq_hdr->data.seq_hdr;
+  seq_scalable_ext = priv->seq_scalable_ext ?
+      &priv->seq_scalable_ext->data.seq_scalable_ext : NULL;
+
+  if (!gst_mpeg_video_packet_parse_slice_header (packet, slice_hdr,
+          seq_hdr, seq_scalable_ext)) {
+    GST_ERROR ("failed to parse slice header");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  gst_vaapi_decoder_unit_set_parsed_info (unit, slice_hdr, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_slice (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->current_picture;
+  GstVaapiSlice *slice;
+  VASliceParameterBufferMPEG2 *slice_param;
+  GstMpegVideoSliceHdr *const slice_hdr = unit->parsed_info;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  GST_DEBUG ("slice %d (%u bytes)", slice_hdr->mb_row, unit->size);
+
+  slice = GST_VAAPI_SLICE_NEW (MPEG2, decoder,
+      (map_info.data + unit->offset), unit->size);
+  gst_buffer_unmap (buffer, &map_info);
+  if (!slice) {
+    GST_ERROR ("failed to allocate slice");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  gst_vaapi_picture_add_slice (picture, slice);
+
+  /* Fill in VASliceParameterBufferMPEG2 */
+  slice_param = slice->param;
+  slice_param->macroblock_offset = slice_hdr->header_size + 32;
+  slice_param->slice_horizontal_position = slice_hdr->mb_column;
+  slice_param->slice_vertical_position = slice_hdr->mb_row;
+  slice_param->quantiser_scale_code = slice_hdr->quantiser_scale_code;
+  slice_param->intra_slice_flag = slice_hdr->intra_slice;
+
+  priv->state |= GST_MPEG_VIDEO_STATE_GOT_SLICE;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline gint
+scan_for_start_code (const guchar * buf, guint buf_size,
+    GstMpegVideoPacketTypeCode * type_ptr)
+{
+  guint i = 0;
+
+  while (i <= (buf_size - 4)) {
+    if (buf[i + 2] > 1)
+      i += 3;
+    else if (buf[i + 1])
+      i += 2;
+    else if (buf[i] || buf[i + 2] != 1)
+      i++;
+    else
+      break;
+  }
+
+  if (i <= (buf_size - 4)) {
+    if (type_ptr)
+      *type_ptr = buf[i + 3];
+    return i;
+  }
+  return -1;
+}
+
+static GstVaapiDecoderStatus
+parse_unit (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit,
+    GstMpegVideoPacket * packet)
+{
+  GstMpegVideoPacketTypeCode type;
+  GstMpegVideoPacketExtensionCode ext_type;
+  GstVaapiDecoderStatus status;
+
+  type = packet->type;
+  switch (type) {
+    case GST_MPEG_VIDEO_PACKET_PICTURE:
+      status = parse_picture (decoder, unit, packet);
+      break;
+    case GST_MPEG_VIDEO_PACKET_SEQUENCE:
+      status = parse_sequence (decoder, unit, packet);
+      break;
+    case GST_MPEG_VIDEO_PACKET_EXTENSION:
+      ext_type = packet->data[4] >> 4;
+      switch (ext_type) {
+        case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
+          status = parse_sequence_ext (decoder, unit, packet);
+          break;
+        case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
+          status = parse_sequence_display_ext (decoder, unit, packet);
+          break;
+        case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
+          status = parse_sequence_scalable_ext (decoder, unit, packet);
+          break;
+        case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
+          status = parse_quant_matrix_ext (decoder, unit, packet);
+          break;
+        case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
+          status = parse_picture_ext (decoder, unit, packet);
+          break;
+        default:
+          status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+          break;
+      }
+      break;
+    case GST_MPEG_VIDEO_PACKET_GOP:
+      status = parse_gop (decoder, unit, packet);
+      break;
+    default:
+      if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
+          type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
+        status = parse_slice (decoder, unit, packet);
+        break;
+      }
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+  }
+  return status;
+}
+
+static GstVaapiDecoderStatus
+decode_unit (GstVaapiDecoderMpeg2 * decoder, GstVaapiDecoderUnit * unit,
+    GstMpegVideoPacket * packet)
+{
+  GstMpegVideoPacketTypeCode type;
+  GstMpegVideoPacketExtensionCode ext_type;
+  GstVaapiDecoderStatus status;
+
+  type = packet->type;
+  switch (type) {
+    case GST_MPEG_VIDEO_PACKET_PICTURE:
+      status = decode_picture (decoder, unit);
+      break;
+    case GST_MPEG_VIDEO_PACKET_SEQUENCE:
+      status = decode_sequence (decoder, unit);
+      break;
+    case GST_MPEG_VIDEO_PACKET_EXTENSION:
+      ext_type = packet->data[4] >> 4;
+      switch (ext_type) {
+        case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE:
+          status = decode_sequence_ext (decoder, unit);
+          break;
+        case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_DISPLAY:
+          status = decode_sequence_display_ext (decoder, unit);
+          break;
+        case GST_MPEG_VIDEO_PACKET_EXT_SEQUENCE_SCALABLE:
+          status = decode_sequence_scalable_ext (decoder, unit);
+          break;
+        case GST_MPEG_VIDEO_PACKET_EXT_QUANT_MATRIX:
+          status = decode_quant_matrix_ext (decoder, unit);
+          break;
+        case GST_MPEG_VIDEO_PACKET_EXT_PICTURE:
+          status = decode_picture_ext (decoder, unit);
+          break;
+        default:
+          // Ignore unknown start-code extensions
+          GST_WARNING ("unsupported packet extension type 0x%02x", ext_type);
+          status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+          break;
+      }
+      break;
+    case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
+      status = decode_sequence_end (decoder);
+      break;
+    case GST_MPEG_VIDEO_PACKET_GOP:
+      status = decode_gop (decoder, unit);
+      break;
+    default:
+      if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
+          type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
+        status = decode_slice (decoder, unit);
+        break;
+      }
+      GST_WARNING ("unsupported packet type 0x%02x", type);
+      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+      break;
+  }
+  return status;
+}
+
+static GstVaapiDecoderStatus
+ensure_decoder (GstVaapiDecoderMpeg2 * decoder)
+{
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+
+  if (!priv->is_opened) {
+    priv->is_opened = gst_vaapi_decoder_mpeg2_open (decoder);
+    if (!priv->is_opened)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg2_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg2 *const decoder =
+      GST_VAAPI_DECODER_MPEG2_CAST (base_decoder);
+  GstVaapiParserState *const ps = GST_VAAPI_PARSER_STATE (base_decoder);
+  GstVaapiDecoderStatus status;
+  GstMpegVideoPacketTypeCode type, type2 = GST_MPEG_VIDEO_PACKET_NONE;
+  const guchar *buf;
+  guint buf_size, flags;
+  gint ofs, ofs1, ofs2;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  buf_size = gst_adapter_available (adapter);
+  if (buf_size < 4)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  buf = gst_adapter_map (adapter, buf_size);
+  if (!buf)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  ofs = scan_for_start_code (buf, buf_size, &type);
+  if (ofs < 0)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+  ofs1 = ofs;
+
+  ofs2 = ps->input_offset2 - 4;
+  if (ofs2 < ofs1 + 4)
+    ofs2 = ofs1 + 4;
+
+  ofs = G_UNLIKELY (buf_size < ofs2 + 4) ? -1 :
+      scan_for_start_code (&buf[ofs2], buf_size - ofs2, &type2);
+  if (ofs < 0) {
+    // Assume the whole packet is present if end-of-stream
+    if (!at_eos) {
+      ps->input_offset2 = buf_size;
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    }
+    ofs = buf_size - ofs2;
+  }
+  ofs2 += ofs;
+
+  unit->size = ofs2 - ofs1;
+  gst_adapter_flush (adapter, ofs1);
+  ps->input_offset2 = 4;
+
+  /* Check for start of new picture */
+  flags = 0;
+  switch (type) {
+    case GST_MPEG_VIDEO_PACKET_SEQUENCE_END:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
+      break;
+    case GST_MPEG_VIDEO_PACKET_USER_DATA:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+      /* fall-through */
+    case GST_MPEG_VIDEO_PACKET_SEQUENCE:
+    case GST_MPEG_VIDEO_PACKET_GOP:
+    case GST_MPEG_VIDEO_PACKET_PICTURE:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      break;
+    case GST_MPEG_VIDEO_PACKET_EXTENSION:
+      if (G_UNLIKELY (unit->size < 5))
+        return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+      break;
+    default:
+      if (type >= GST_MPEG_VIDEO_PACKET_SLICE_MIN &&
+          type <= GST_MPEG_VIDEO_PACKET_SLICE_MAX) {
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+        switch (type2) {
+          case GST_MPEG_VIDEO_PACKET_USER_DATA:
+          case GST_MPEG_VIDEO_PACKET_SEQUENCE:
+          case GST_MPEG_VIDEO_PACKET_GOP:
+          case GST_MPEG_VIDEO_PACKET_PICTURE:
+            flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+            break;
+          default:
+            break;
+        }
+      }
+      // Ignore system start codes (PES headers)
+      else if (type >= 0xb9 && type <= 0xff)
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+      break;
+  }
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg2_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg2 *const decoder =
+      GST_VAAPI_DECODER_MPEG2_CAST (base_decoder);
+  GstVaapiDecoderStatus status;
+  GstMpegVideoPacket packet;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  packet.data = map_info.data + unit->offset;
+  packet.size = unit->size;
+  packet.type = packet.data[3];
+  packet.offset = 4;
+
+  status = parse_unit (decoder, unit, &packet);
+  gst_buffer_unmap (buffer, &map_info);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+  return decode_unit (decoder, unit, &packet);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg2_start_frame (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * base_unit)
+{
+  GstVaapiDecoderMpeg2 *const decoder =
+      GST_VAAPI_DECODER_MPEG2_CAST (base_decoder);
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+  GstMpegVideoSequenceHdr *seq_hdr;
+  GstMpegVideoSequenceExt *seq_ext;
+  GstMpegVideoSequenceDisplayExt *seq_display_ext;
+  GstVaapiPicture *picture;
+  GstVaapiDecoderStatus status;
+
+  if (!is_valid_state (decoder, GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  priv->state &= ~GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS;
+
+  seq_hdr = &priv->seq_hdr->data.seq_hdr;
+  seq_ext = priv->seq_ext ? &priv->seq_ext->data.seq_ext : NULL;
+  seq_display_ext = priv->seq_display_ext ?
+      &priv->seq_display_ext->data.seq_display_ext : NULL;
+  if (gst_mpeg_video_finalise_mpeg2_sequence_header (seq_hdr, seq_ext,
+          seq_display_ext))
+    gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder,
+        seq_hdr->par_w, seq_hdr->par_h);
+
+  status = ensure_context (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    GST_ERROR ("failed to reset context");
+    return status;
+  }
+
+  if (priv->current_picture) {
+    /* Re-use current picture where the first field was decoded */
+    picture = gst_vaapi_picture_new_field (priv->current_picture);
+    if (!picture) {
+      GST_ERROR ("failed to allocate field picture");
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+  } else {
+    /* Create new picture */
+    picture = GST_VAAPI_PICTURE_NEW (MPEG2, decoder);
+    if (!picture) {
+      GST_ERROR ("failed to allocate picture");
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+  }
+  gst_vaapi_picture_replace (&priv->current_picture, picture);
+  gst_vaapi_picture_unref (picture);
+
+  /* Update cropping rectangle */
+  /* XXX: handle picture_display_extension() */
+  if (seq_display_ext && priv->pic_display_ext) {
+    GstVaapiRectangle *const crop_rect = &priv->crop_rect;
+    if (crop_rect->x + crop_rect->width <= priv->width &&
+        crop_rect->y + crop_rect->height <= priv->height)
+      gst_vaapi_picture_set_crop_rect (picture, crop_rect);
+  }
+
+  status = ensure_quant_matrix (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    GST_ERROR ("failed to reset quantizer matrix");
+    return status;
+  }
+
+  status = init_picture (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  fill_picture (decoder, picture);
+
+  priv->state |= GST_MPEG_VIDEO_STATE_VALID_PIC_HEADERS;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg2_end_frame (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderMpeg2 *const decoder =
+      GST_VAAPI_DECODER_MPEG2_CAST (base_decoder);
+
+  return decode_current_picture (decoder);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg2_flush (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderMpeg2 *const decoder =
+      GST_VAAPI_DECODER_MPEG2_CAST (base_decoder);
+  GstVaapiDecoderMpeg2Private *const priv = &decoder->priv;
+
+  if (priv->dpb)
+    gst_vaapi_dpb_flush (priv->dpb);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+gst_vaapi_decoder_mpeg2_finalize (GObject * object)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
+
+  gst_vaapi_decoder_mpeg2_destroy (base_decoder);
+  G_OBJECT_CLASS (gst_vaapi_decoder_mpeg2_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_mpeg2_class_init (GstVaapiDecoderMpeg2Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_decoder_mpeg2_finalize;
+
+  decoder_class->reset = gst_vaapi_decoder_mpeg2_reset;
+  decoder_class->parse = gst_vaapi_decoder_mpeg2_parse;
+  decoder_class->decode = gst_vaapi_decoder_mpeg2_decode;
+  decoder_class->start_frame = gst_vaapi_decoder_mpeg2_start_frame;
+  decoder_class->end_frame = gst_vaapi_decoder_mpeg2_end_frame;
+  decoder_class->flush = gst_vaapi_decoder_mpeg2_flush;
+}
+
+static void
+gst_vaapi_decoder_mpeg2_init (GstVaapiDecoderMpeg2 * decoder)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+
+  gst_vaapi_decoder_mpeg2_create (base_decoder);
+}
+
+/**
+ * gst_vaapi_decoder_mpeg2_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for MPEG-2 decoding.  The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_mpeg2_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return g_object_new (GST_TYPE_VAAPI_DECODER_MPEG2, "display", display,
+      "caps", caps, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg2.h
new file mode 100644 (file)
index 0000000..765a80c
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  gstvaapidecoder_mpeg2.h - MPEG-2 decoder
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_MPEG2_H
+#define GST_VAAPI_DECODER_MPEG2_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+#include <gst/base/gstadapter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER_MPEG2 \
+    (gst_vaapi_decoder_mpeg2_get_type ())
+#define GST_VAAPI_DECODER_MPEG2(decoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_MPEG2, GstVaapiDecoderMpeg2))
+#define GST_VAAPI_IS_DECODER_MPEG2(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_MPEG2))
+
+typedef struct _GstVaapiDecoderMpeg2            GstVaapiDecoderMpeg2;
+
+GType
+gst_vaapi_decoder_mpeg2_get_type (void) G_GNUC_CONST;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_mpeg2_new (GstVaapiDisplay *display, GstCaps *caps);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderMpeg2, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_MPEG2_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.c
new file mode 100644 (file)
index 0000000..8ecdb32
--- /dev/null
@@ -0,0 +1,1215 @@
+/*
+ *  gstvaapidecoder_mpeg4.c - MPEG-4 decoder
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Halley Zhao <halley.zhao@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_mpeg4
+ * @short_description: MPEG-4 decoder, include h263/divx/xvid support
+ */
+
+#include "sysdeps.h"
+#include <gst/base/gstbitreader.h>
+#include <gst/codecparsers/gstmpeg4parser.h>
+#include "gstvaapidecoder_mpeg4.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_DECODER_MPEG4_CAST(decoder) \
+    ((GstVaapiDecoderMpeg4 *)(decoder))
+
+typedef struct _GstVaapiDecoderMpeg4Private GstVaapiDecoderMpeg4Private;
+typedef struct _GstVaapiDecoderMpeg4Class GstVaapiDecoderMpeg4Class;
+
+struct _GstVaapiDecoderMpeg4Private
+{
+  GstVaapiProfile profile;
+  guint level;
+  guint width;
+  guint height;
+  guint fps_n;
+  guint fps_d;
+  guint coding_type;
+  GstMpeg4VisualObjectSequence vos_hdr;
+  GstMpeg4VisualObject vo_hdr;
+  GstMpeg4VideoSignalType signal_type;
+  GstMpeg4VideoObjectLayer vol_hdr;
+  GstMpeg4VideoObjectPlane vop_hdr;
+  GstMpeg4VideoPlaneShortHdr svh_hdr;
+  GstMpeg4VideoPacketHdr packet_hdr;
+  GstMpeg4SpriteTrajectory sprite_trajectory;
+  VAIQMatrixBufferMPEG4 iq_matrix;
+  GstVaapiPicture *curr_picture;
+  // forward reference pic
+  GstVaapiPicture *next_picture;
+  // backward reference pic
+  GstVaapiPicture *prev_picture;
+  GstClockTime seq_pts;
+  GstClockTime gop_pts;
+  GstClockTime pts_diff;
+  GstClockTime max_pts;
+  // anchor sync time base for any picture type,
+  // it is time base of backward reference frame
+  GstClockTime last_sync_time;
+  // time base for recent I/P/S frame,
+  // it is time base of forward reference frame for B frame
+  GstClockTime sync_time;
+
+  /* last non-b-frame time by resolution */
+  GstClockTime last_non_b_scale_time;
+  GstClockTime non_b_scale_time;
+  GstClockTime trb;
+  GstClockTime trd;
+  // temporal_reference of previous frame of svh
+  guint8 prev_t_ref;
+  guint is_opened:1;
+  guint is_first_field:1;
+  guint size_changed:1;
+  guint profile_changed:1;
+  guint progressive_sequence:1;
+  guint closed_gop:1;
+  guint broken_link:1;
+  guint calculate_pts_diff:1;
+  guint is_svh:1;
+};
+
+/**
+ * GstVaapiDecoderMpeg4:
+ *
+ * A decoder based on Mpeg4.
+ */
+struct _GstVaapiDecoderMpeg4
+{
+  /*< private > */
+  GstVaapiDecoder parent_instance;
+  GstVaapiDecoderMpeg4Private priv;
+};
+
+/**
+ * GstVaapiDecoderMpeg4Class:
+ *
+ * A decoder class based on Mpeg4.
+ */
+struct _GstVaapiDecoderMpeg4Class
+{
+  /*< private > */
+  GstVaapiDecoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiDecoderMpeg4, gst_vaapi_decoder_mpeg4,
+    GST_TYPE_VAAPI_DECODER);
+
+static void
+gst_vaapi_decoder_mpeg4_close (GstVaapiDecoderMpeg4 * decoder)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+
+  gst_vaapi_picture_replace (&priv->curr_picture, NULL);
+  gst_vaapi_picture_replace (&priv->next_picture, NULL);
+  gst_vaapi_picture_replace (&priv->prev_picture, NULL);
+}
+
+static gboolean
+gst_vaapi_decoder_mpeg4_open (GstVaapiDecoderMpeg4 * decoder)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstCaps *caps = NULL;
+  GstStructure *structure = NULL;
+
+  gst_vaapi_decoder_mpeg4_close (decoder);
+
+  priv->is_svh = 0;
+  caps = gst_vaapi_decoder_get_caps (base_decoder);
+  if (caps) {
+    structure = gst_caps_get_structure (caps, 0);
+    if (structure) {
+      if (gst_structure_has_name (structure, "video/x-h263")) {
+        priv->is_svh = 1;
+        priv->profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE;
+        priv->prev_t_ref = -1;
+      }
+    }
+  }
+  return TRUE;
+}
+
+static void
+gst_vaapi_decoder_mpeg4_destroy (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderMpeg4 *const decoder =
+      GST_VAAPI_DECODER_MPEG4_CAST (base_decoder);
+
+  gst_vaapi_decoder_mpeg4_close (decoder);
+}
+
+static gboolean
+gst_vaapi_decoder_mpeg4_create (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderMpeg4 *const decoder =
+      GST_VAAPI_DECODER_MPEG4_CAST (base_decoder);
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+
+  priv->profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE;
+  priv->seq_pts = GST_CLOCK_TIME_NONE;
+  priv->gop_pts = GST_CLOCK_TIME_NONE;
+  priv->max_pts = GST_CLOCK_TIME_NONE;
+  priv->calculate_pts_diff = TRUE;
+  priv->size_changed = TRUE;
+  priv->profile_changed = TRUE;
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg4_reset (GstVaapiDecoder * base_decoder)
+{
+  gst_vaapi_decoder_mpeg4_destroy (base_decoder);
+  gst_vaapi_decoder_mpeg4_create (base_decoder);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline void
+copy_quant_matrix (guint8 dst[64], const guint8 src[64])
+{
+  memcpy (dst, src, 64);
+}
+
+static GstVaapiDecoderStatus
+ensure_context (GstVaapiDecoderMpeg4 * decoder)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstVaapiProfile profiles[2];
+  GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+  guint i, n_profiles = 0;
+  gboolean reset_context = FALSE;
+
+  if (priv->profile_changed) {
+    GST_DEBUG ("profile changed");
+    priv->profile_changed = FALSE;
+    reset_context = TRUE;
+
+    profiles[n_profiles++] = priv->profile;
+    if (priv->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE)
+      profiles[n_profiles++] = GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE;
+
+    for (i = 0; i < n_profiles; i++) {
+      if (gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
+              profiles[i], entrypoint))
+        break;
+    }
+    if (i == n_profiles)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+    priv->profile = profiles[i];
+  }
+
+  if (priv->size_changed) {
+    GST_DEBUG ("size changed");
+    priv->size_changed = FALSE;
+    reset_context = TRUE;
+  }
+
+  if (reset_context) {
+    GstVaapiContextInfo info;
+
+    info.profile = priv->profile;
+    info.entrypoint = entrypoint;
+    info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+    info.width = priv->width;
+    info.height = priv->height;
+    info.ref_frames = 2;
+    reset_context =
+        gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info);
+    if (!reset_context)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+ensure_quant_matrix (GstVaapiDecoderMpeg4 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  VAIQMatrixBufferMPEG4 *iq_matrix;
+
+  if (!priv->vol_hdr.load_intra_quant_mat
+      && !priv->vol_hdr.load_non_intra_quant_mat) {
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  }
+
+  picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (MPEG4, decoder);
+  if (!picture->iq_matrix) {
+    GST_DEBUG ("failed to allocate IQ matrix");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  iq_matrix = picture->iq_matrix->param;
+
+  if (priv->vol_hdr.load_intra_quant_mat) {
+    iq_matrix->load_intra_quant_mat = 1;
+    copy_quant_matrix (iq_matrix->intra_quant_mat,
+        priv->vol_hdr.intra_quant_mat);
+  } else
+    iq_matrix->load_intra_quant_mat = 0;
+
+  if (priv->vol_hdr.load_non_intra_quant_mat) {
+    iq_matrix->load_non_intra_quant_mat = 1;
+    copy_quant_matrix (iq_matrix->non_intra_quant_mat,
+        priv->vol_hdr.non_intra_quant_mat);
+  } else
+    iq_matrix->load_non_intra_quant_mat = 0;
+
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline GstVaapiDecoderStatus
+render_picture (GstVaapiDecoderMpeg4 * decoder, GstVaapiPicture * picture)
+{
+  if (!gst_vaapi_picture_output (picture))
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+/* decode_picture() start to decode a frame/picture
+ * decode_current_picture() finishe decoding a frame/picture
+ * (commit buffer to driver for decoding)
+ */
+static GstVaapiDecoderStatus
+decode_current_picture (GstVaapiDecoderMpeg4 * decoder)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->curr_picture;
+  GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (picture) {
+    if (!gst_vaapi_picture_decode (picture))
+      status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    if (!GST_VAAPI_PICTURE_IS_REFERENCE (picture)) {
+      if ((priv->prev_picture && priv->next_picture) ||
+          (priv->closed_gop && priv->next_picture))
+        status = render_picture (decoder, picture);
+    }
+    gst_vaapi_picture_replace (&priv->curr_picture, NULL);
+  }
+  return status;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf,
+    guint buf_size)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstMpeg4VisualObjectSequence *const vos_hdr = &priv->vos_hdr;
+  GstVaapiProfile profile;
+
+  if (gst_mpeg4_parse_visual_object_sequence (vos_hdr, buf,
+          buf_size) != GST_MPEG4_PARSER_OK) {
+    GST_DEBUG ("failed to parse sequence header");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  priv->level = vos_hdr->level;
+  switch (vos_hdr->profile) {
+    case GST_MPEG4_PROFILE_SIMPLE:
+      profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE;
+      break;
+    case GST_MPEG4_PROFILE_ADVANCED_SIMPLE:
+    case GST_MPEG4_PROFILE_SIMPLE_SCALABLE:    /* shared profile with ADVANCED_SIMPLE */
+      profile = GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE;
+      break;
+    default:
+      GST_DEBUG ("unsupported profile %d", vos_hdr->profile);
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+  if (priv->profile != profile) {
+    priv->profile = profile;
+    priv->profile_changed = TRUE;
+  }
+  priv->seq_pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
+  priv->size_changed = TRUE;
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_end (GstVaapiDecoderMpeg4 * decoder)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+
+  if (priv->curr_picture) {
+    status = decode_current_picture (decoder);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+    status = render_picture (decoder, priv->curr_picture);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+
+  if (priv->next_picture) {
+    status = render_picture (decoder, priv->next_picture);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+  return GST_VAAPI_DECODER_STATUS_END_OF_STREAM;
+}
+
+static GstVaapiDecoderStatus
+decode_visual_object (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf,
+    guint buf_size)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstMpeg4VisualObject *vo_hdr = &priv->vo_hdr;
+  GstMpeg4VideoSignalType *signal_type = &priv->signal_type;
+
+  if (gst_mpeg4_parse_visual_object (vo_hdr, signal_type, buf,
+          buf_size) != GST_MPEG4_PARSER_OK) {
+    GST_DEBUG ("failed to parse visual object");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  /* XXX: video_signal_type isn't used for decoding */
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_video_object_layer (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf,
+    guint buf_size)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstMpeg4VisualObject *vo_hdr = &priv->vo_hdr;
+  GstMpeg4VideoObjectLayer *vol_hdr = &priv->vol_hdr;
+
+  if (gst_mpeg4_parse_video_object_layer (vol_hdr, vo_hdr, buf,
+          buf_size) != GST_MPEG4_PARSER_OK) {
+    GST_DEBUG ("failed to parse video object layer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  priv->width = vol_hdr->width;
+  priv->height = vol_hdr->height;
+
+  priv->progressive_sequence = !vol_hdr->interlaced;
+
+  if (vol_hdr->fixed_vop_rate) {
+    priv->fps_n = vol_hdr->vop_time_increment_resolution;
+    priv->fps_d = vol_hdr->fixed_vop_time_increment;
+    gst_vaapi_decoder_set_framerate (base_decoder, priv->fps_n, priv->fps_d);
+  }
+
+  gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder,
+      priv->vol_hdr.par_width, priv->vol_hdr.par_height);
+  gst_vaapi_decoder_set_picture_size (base_decoder, priv->width, priv->height);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_gop (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf, guint buf_size)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstMpeg4GroupOfVOP gop;
+  GstClockTime gop_time;
+
+  if (buf_size > 4) {
+    if (gst_mpeg4_parse_group_of_vop (&gop, buf,
+            buf_size) != GST_MPEG4_PARSER_OK) {
+      GST_DEBUG ("failed to parse GOP");
+      return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+    }
+  } else {
+    gop.closed = 1;
+    gop.broken_link = 0;
+    gop.hours = 0;
+    gop.minutes = 0;
+    gop.seconds = 0;
+  }
+
+  priv->closed_gop = gop.closed;
+  priv->broken_link = gop.broken_link;
+
+  GST_DEBUG ("GOP %02u:%02u:%02u (closed_gop %d, broken_link %d)",
+      gop.hours, gop.minutes, gop.seconds, priv->closed_gop, priv->broken_link);
+
+  gop_time = gop.hours * 3600 + gop.minutes * 60 + gop.seconds;
+  priv->last_sync_time = gop_time;
+  priv->sync_time = gop_time;
+
+  if (priv->gop_pts != GST_CLOCK_TIME_NONE)
+    priv->pts_diff += gop_time * GST_SECOND - priv->gop_pts;
+  priv->gop_pts = gop_time * GST_SECOND;
+  priv->calculate_pts_diff = TRUE;
+  priv->is_first_field = TRUE;
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+calculate_pts_diff (GstVaapiDecoderMpeg4 * decoder,
+    GstMpeg4VideoObjectLayer * vol_hdr, GstMpeg4VideoObjectPlane * vop_hdr)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstClockTime frame_timestamp;
+
+  frame_timestamp = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
+  if (frame_timestamp && frame_timestamp != GST_CLOCK_TIME_NONE) {
+    /* Buffer with timestamp */
+    if (priv->max_pts != GST_CLOCK_TIME_NONE && frame_timestamp < priv->max_pts) {
+      frame_timestamp = priv->max_pts +
+          gst_util_uint64_scale ((vol_hdr->fixed_vop_rate ?
+              vol_hdr->fixed_vop_time_increment : 1),
+          GST_SECOND, vol_hdr->vop_time_increment_resolution);
+    }
+  } else {
+    /* Buffer without timestamp set */
+    if (priv->max_pts == GST_CLOCK_TIME_NONE)   /* first buffer */
+      frame_timestamp = 0;
+    else {
+      GstClockTime tmp_pts;
+      tmp_pts = priv->pts_diff + priv->gop_pts +
+          vop_hdr->modulo_time_base * GST_SECOND +
+          gst_util_uint64_scale (vop_hdr->time_increment,
+          GST_SECOND, vol_hdr->vop_time_increment_resolution);
+      if (tmp_pts > priv->max_pts)
+        frame_timestamp = tmp_pts;
+      else
+        frame_timestamp = priv->max_pts +
+            gst_util_uint64_scale ((vol_hdr->fixed_vop_rate ?
+                vol_hdr->fixed_vop_time_increment : 1),
+            GST_SECOND, vol_hdr->vop_time_increment_resolution);
+    }
+  }
+
+  priv->pts_diff = frame_timestamp -
+      (priv->gop_pts + vop_hdr->modulo_time_base * GST_SECOND +
+      gst_util_uint64_scale (vop_hdr->time_increment, GST_SECOND,
+          vol_hdr->vop_time_increment_resolution));
+}
+
+static GstVaapiDecoderStatus
+decode_picture (GstVaapiDecoderMpeg4 * decoder, const guint8 * buf,
+    guint buf_size)
+{
+  GstMpeg4ParseResult parser_result = GST_MPEG4_PARSER_OK;
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstMpeg4VideoObjectPlane *const vop_hdr = &priv->vop_hdr;
+  GstMpeg4VideoObjectLayer *const vol_hdr = &priv->vol_hdr;
+  GstMpeg4SpriteTrajectory *const sprite_trajectory = &priv->sprite_trajectory;
+  GstVaapiPicture *picture;
+  GstVaapiDecoderStatus status;
+  GstClockTime pts;
+
+  // context depends on priv->width and priv->height, so we move parse_vop a little earlier
+  if (priv->is_svh) {
+    parser_result =
+        gst_mpeg4_parse_video_plane_short_header (&priv->svh_hdr, buf,
+        buf_size);
+
+  } else {
+    parser_result =
+        gst_mpeg4_parse_video_object_plane (vop_hdr, sprite_trajectory, vol_hdr,
+        buf, buf_size);
+    /* Need to skip this frame if VOP was not coded */
+    if (GST_MPEG4_PARSER_OK == parser_result && !vop_hdr->coded)
+      return (GstVaapiDecoderStatus) GST_VAAPI_DECODER_STATUS_DROP_FRAME;
+  }
+
+  if (parser_result != GST_MPEG4_PARSER_OK) {
+    GST_DEBUG ("failed to parse picture header");
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+
+  if (priv->is_svh) {
+    priv->width = priv->svh_hdr.vop_width;
+    priv->height = priv->svh_hdr.vop_height;
+  } else {
+    if (!vop_hdr->width && !vop_hdr->height) {
+      vop_hdr->width = vol_hdr->width;
+      vop_hdr->height = vol_hdr->height;
+    }
+    priv->width = vop_hdr->width;
+    priv->height = vop_hdr->height;
+  }
+
+  status = ensure_context (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    GST_DEBUG ("failed to reset context");
+    return status;
+  }
+
+  if (priv->curr_picture) {
+    status = decode_current_picture (decoder);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+
+  priv->curr_picture = GST_VAAPI_PICTURE_NEW (MPEG4, decoder);
+  if (!priv->curr_picture) {
+    GST_DEBUG ("failed to allocate picture");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  picture = priv->curr_picture;
+
+  status = ensure_quant_matrix (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    GST_DEBUG ("failed to reset quantizer matrix");
+    return status;
+  }
+
+  /* 7.6.7 Temporal prediction structure
+   * forward reference frame     B B B B B B      backward reference frame
+   *            |                                              |
+   *  nearest I/P/S in the past with vop_coded ==1             |
+   *                         nearest I/P/S in the future with any vop_coded
+   * FIXME: it said that B frame shouldn't use backward reference frame
+   *        when backward reference frame coded is 0
+   */
+  if (priv->is_svh) {
+    priv->coding_type = priv->svh_hdr.picture_coding_type;
+  } else {
+    priv->coding_type = priv->vop_hdr.coding_type;
+  }
+  switch (priv->coding_type) {
+    case GST_MPEG4_I_VOP:
+      picture->type = GST_VAAPI_PICTURE_TYPE_I;
+      if (priv->is_svh || vop_hdr->coded)
+        GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
+      break;
+    case GST_MPEG4_P_VOP:
+      picture->type = GST_VAAPI_PICTURE_TYPE_P;
+      if (priv->is_svh || vop_hdr->coded)
+        GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
+      break;
+    case GST_MPEG4_B_VOP:
+      picture->type = GST_VAAPI_PICTURE_TYPE_B;
+      break;
+    case GST_MPEG4_S_VOP:
+      picture->type = GST_VAAPI_PICTURE_TYPE_S;
+      // see 3.175 reference VOP
+      if (vop_hdr->coded)
+        GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
+      break;
+    default:
+      GST_DEBUG ("unsupported picture type %d", priv->coding_type);
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (!priv->is_svh && !vop_hdr->coded) {
+    status = render_picture (decoder, priv->prev_picture);
+    return status;
+  }
+
+  if (priv->is_svh) {
+    guint temp_ref = priv->svh_hdr.temporal_reference;
+    guint delta_ref;
+
+    if (temp_ref < priv->prev_t_ref) {
+      temp_ref += 256;
+    }
+    delta_ref = temp_ref - priv->prev_t_ref;
+
+    pts = priv->sync_time;
+    // see temporal_reference definition in spec, 30000/1001Hz
+    pts += gst_util_uint64_scale (delta_ref, GST_SECOND * 1001, 30000);
+    priv->sync_time = pts;
+    priv->prev_t_ref = priv->svh_hdr.temporal_reference;
+  } else {
+    /* Update priv->pts_diff */
+    if (priv->calculate_pts_diff) {
+      calculate_pts_diff (decoder, vol_hdr, vop_hdr);
+      priv->calculate_pts_diff = FALSE;
+    }
+
+    /* Update presentation time, 6.3.5 */
+    if (vop_hdr->coding_type != GST_MPEG4_B_VOP) {
+      // increment basing on decoding order
+      priv->last_sync_time = priv->sync_time;
+      priv->sync_time = priv->last_sync_time + vop_hdr->modulo_time_base;
+      pts = priv->sync_time * GST_SECOND;
+      pts +=
+          gst_util_uint64_scale (vop_hdr->time_increment, GST_SECOND,
+          vol_hdr->vop_time_increment_resolution);
+      priv->last_non_b_scale_time = priv->non_b_scale_time;
+      priv->non_b_scale_time =
+          priv->sync_time * vol_hdr->vop_time_increment_resolution +
+          vop_hdr->time_increment;
+      priv->trd = priv->non_b_scale_time - priv->last_non_b_scale_time;
+    } else {
+      // increment basing on display oder
+      pts = (priv->last_sync_time + vop_hdr->modulo_time_base) * GST_SECOND;
+      pts +=
+          gst_util_uint64_scale (vop_hdr->time_increment, GST_SECOND,
+          vol_hdr->vop_time_increment_resolution);
+      priv->trb =
+          (priv->last_sync_time +
+          vop_hdr->modulo_time_base) * vol_hdr->vop_time_increment_resolution +
+          vop_hdr->time_increment - priv->last_non_b_scale_time;
+    }
+  }
+  picture->pts = pts + priv->pts_diff;
+  if (priv->max_pts == GST_CLOCK_TIME_NONE || priv->max_pts < picture->pts)
+    priv->max_pts = picture->pts;
+
+  /* Update reference pictures */
+  /* XXX: consider priv->vol_hdr.low_delay, consider packed video frames for DivX/XviD */
+  if (GST_VAAPI_PICTURE_IS_REFERENCE (picture)) {
+    if (priv->next_picture)
+      status = render_picture (decoder, priv->next_picture);
+    gst_vaapi_picture_replace (&priv->prev_picture, priv->next_picture);
+    gst_vaapi_picture_replace (&priv->next_picture, picture);
+  }
+  return status;
+}
+
+static inline guint
+get_vop_coding_type (GstVaapiPicture * picture)
+{
+  return picture->type - GST_VAAPI_PICTURE_TYPE_I;
+}
+
+static gboolean
+fill_picture (GstVaapiDecoderMpeg4 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  VAPictureParameterBufferMPEG4 *const pic_param = picture->param;
+  GstMpeg4VideoObjectPlane *const vop_hdr = &priv->vop_hdr;
+
+  /* Fill in VAPictureParameterBufferMPEG4 */
+  pic_param->forward_reference_picture = VA_INVALID_ID;
+  pic_param->backward_reference_picture = VA_INVALID_ID;
+
+  pic_param->vol_fields.value = 0;
+  pic_param->vop_fields.value = 0;
+  if (priv->is_svh) {
+    // vol_hdr Parameters
+    pic_param->vol_fields.bits.short_video_header = 1;
+    // does the following vol_hdr parameters matter for short video header?
+    pic_param->vol_fields.bits.chroma_format = 1;       // I420, see table 6-15.
+    pic_param->vol_fields.bits.interlaced = 0;
+    pic_param->vol_fields.bits.obmc_disable = 1;
+    pic_param->vol_fields.bits.sprite_enable = 0;
+    pic_param->vol_fields.bits.sprite_warping_accuracy = 0;
+    pic_param->vol_fields.bits.quant_type = 0;  //method 1; $7.4.4
+    pic_param->vol_fields.bits.quarter_sample = 0;
+    pic_param->vol_fields.bits.data_partitioned = 0;
+    pic_param->vol_fields.bits.reversible_vlc = 0;
+    pic_param->vol_fields.bits.resync_marker_disable = 1;
+    pic_param->no_of_sprite_warping_points = 0;
+    pic_param->quant_precision = 5;
+    // VOP parameters
+    pic_param->vop_width = priv->svh_hdr.vop_width;
+    pic_param->vop_height = priv->svh_hdr.vop_height;
+    pic_param->vop_fields.bits.vop_coding_type =
+        priv->svh_hdr.picture_coding_type;
+    pic_param->vop_time_increment_resolution =
+        priv->vol_hdr.vop_time_increment_resolution;
+
+    pic_param->num_gobs_in_vop = priv->svh_hdr.num_gobs_in_vop;
+    pic_param->num_macroblocks_in_gob = priv->svh_hdr.num_macroblocks_in_gob;
+  } else {
+    int i;
+
+    // VOL parameters
+    pic_param->vol_fields.bits.short_video_header = 0;
+    pic_param->vol_fields.bits.chroma_format = priv->vol_hdr.chroma_format;
+    pic_param->vol_fields.bits.interlaced = priv->vol_hdr.interlaced;
+    pic_param->vol_fields.bits.obmc_disable = priv->vol_hdr.obmc_disable;
+    pic_param->vol_fields.bits.sprite_enable = priv->vol_hdr.sprite_enable;
+    pic_param->vol_fields.bits.sprite_warping_accuracy =
+        priv->vol_hdr.sprite_warping_accuracy;
+    pic_param->vol_fields.bits.quant_type = priv->vol_hdr.quant_type;
+    pic_param->vol_fields.bits.quarter_sample = priv->vol_hdr.quarter_sample;
+    pic_param->vol_fields.bits.data_partitioned =
+        priv->vol_hdr.data_partitioned;
+    pic_param->vol_fields.bits.reversible_vlc = priv->vol_hdr.reversible_vlc;
+    pic_param->vol_fields.bits.resync_marker_disable =
+        priv->vol_hdr.resync_marker_disable;
+    pic_param->no_of_sprite_warping_points =
+        priv->vol_hdr.no_of_sprite_warping_points;
+
+    for (i = 0; i < 3 && i < priv->vol_hdr.no_of_sprite_warping_points; i++) {
+      pic_param->sprite_trajectory_du[i] =
+          priv->sprite_trajectory.vop_ref_points[i];
+      pic_param->sprite_trajectory_dv[i] =
+          priv->sprite_trajectory.sprite_ref_points[i];
+    }
+    pic_param->quant_precision = priv->vol_hdr.quant_precision;
+
+    // VOP parameters
+    pic_param->vop_width = vop_hdr->width;
+    pic_param->vop_height = vop_hdr->height;
+    pic_param->vop_fields.bits.vop_coding_type = vop_hdr->coding_type;
+    pic_param->vop_fields.bits.vop_rounding_type = vop_hdr->rounding_type;
+    pic_param->vop_fields.bits.intra_dc_vlc_thr = vop_hdr->intra_dc_vlc_thr;
+    pic_param->vop_fields.bits.top_field_first = vop_hdr->top_field_first;
+    pic_param->vop_fields.bits.alternate_vertical_scan_flag =
+        vop_hdr->alternate_vertical_scan_flag;
+
+    pic_param->vop_fcode_forward = vop_hdr->fcode_forward;
+    pic_param->vop_fcode_backward = vop_hdr->fcode_backward;
+    pic_param->vop_time_increment_resolution =
+        priv->vol_hdr.vop_time_increment_resolution;
+  }
+
+  pic_param->TRB = 0;
+  pic_param->TRD = 0;
+  switch (priv->coding_type) {
+    case GST_MPEG4_B_VOP:
+      pic_param->TRB = priv->trb;
+      pic_param->backward_reference_picture = priv->next_picture->surface_id;
+      pic_param->vop_fields.bits.backward_reference_vop_coding_type =
+          get_vop_coding_type (priv->next_picture);
+      // fall-through
+    case GST_MPEG4_P_VOP:
+      pic_param->TRD = priv->trd;
+      if (priv->prev_picture)
+        pic_param->forward_reference_picture = priv->prev_picture->surface_id;
+      break;
+  }
+
+  if (priv->vol_hdr.interlaced) {
+    priv->is_first_field ^= 1;
+  }
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_slice (GstVaapiDecoderMpeg4 * decoder,
+    const guint8 * buf, guint buf_size, gboolean has_packet_header)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->curr_picture;
+  GstVaapiSlice *slice;
+  VASliceParameterBufferMPEG4 *slice_param;
+
+  GST_DEBUG ("decoder silce: %p, %u bytes)", buf, buf_size);
+
+  // has_packet_header is ture for the 2+ slice
+  if (!has_packet_header && !fill_picture (decoder, picture))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  slice = GST_VAAPI_SLICE_NEW (MPEG4, decoder, buf, buf_size);
+  if (!slice) {
+    GST_DEBUG ("failed to allocate slice");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  gst_vaapi_picture_add_slice (picture, slice);
+
+  /* Fill in VASliceParameterBufferMPEG4 */
+  slice_param = slice->param;
+  if (priv->is_svh) {
+    slice_param->macroblock_offset = (priv->svh_hdr.size) % 8;
+    slice_param->macroblock_number = 0;
+    // the header of first gob_layer is empty (gob_header_empty=1), use vop_quant
+    slice_param->quant_scale = priv->svh_hdr.vop_quant;
+  } else {
+    if (has_packet_header) {
+      slice_param->macroblock_offset = priv->packet_hdr.size % 8;
+      slice_param->macroblock_number = priv->packet_hdr.macroblock_number;
+      slice_param->quant_scale = priv->packet_hdr.quant_scale;
+    } else {
+      slice_param->macroblock_offset = priv->vop_hdr.size % 8;
+      slice_param->macroblock_number = 0;
+      slice_param->quant_scale = priv->vop_hdr.quant;
+    }
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_packet (GstVaapiDecoderMpeg4 * decoder, GstMpeg4Packet packet)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstMpeg4Packet *tos = &packet;
+  GstVaapiDecoderStatus status;
+
+  // packet.size is the size from current marker to the next.
+  if (tos->type == GST_MPEG4_VISUAL_OBJ_SEQ_START) {
+    status =
+        decode_sequence (decoder, packet.data + packet.offset, packet.size);
+  } else if (tos->type == GST_MPEG4_VISUAL_OBJ_SEQ_END) {
+    status = decode_sequence_end (decoder);
+  } else if (tos->type == GST_MPEG4_VISUAL_OBJ) {
+    status =
+        decode_visual_object (decoder, packet.data + packet.offset,
+        packet.size);
+  } else if (tos->type >= GST_MPEG4_VIDEO_OBJ_FIRST
+      && tos->type <= GST_MPEG4_VIDEO_OBJ_LAST) {
+    GST_WARNING
+        ("unexpected marker: (GST_MPEG4_VIDEO_OBJ_FIRST, GST_MPEG4_VIDEO_OBJ_LAST)");
+    status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  } else if (tos->type >= GST_MPEG4_VIDEO_LAYER_FIRST
+      && tos->type <= GST_MPEG4_VIDEO_LAYER_LAST) {
+    status =
+        decode_video_object_layer (decoder, packet.data + packet.offset,
+        packet.size);
+  } else if (tos->type == GST_MPEG4_GROUP_OF_VOP) {
+    status = decode_gop (decoder, packet.data + packet.offset, packet.size);
+  } else if (tos->type == GST_MPEG4_VIDEO_OBJ_PLANE) {
+    GstMpeg4Packet video_packet;
+    const guint8 *_data;
+    gint _data_size;
+
+    status = decode_picture (decoder, packet.data + packet.offset, packet.size);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+
+    /* decode slice
+     * A resync marker shall only be located immediately before a macroblock
+     * (or video packet header if exists) and aligned with a byte
+     * either start_code or resync_marker are scaned/measured by byte,
+     * while the header itself are parsed/measured in bit
+     * it means: resync_marker(video_packet_header) start from byte boundary,
+     * while MB doesn't start from byte boundary -- it is what 'macroblock_offset'
+     * in slice refer to
+     */
+    _data = packet.data + packet.offset + priv->vop_hdr.size / 8;
+    _data_size = packet.size - (priv->vop_hdr.size / 8);
+
+    if (priv->vol_hdr.resync_marker_disable) {
+      status = decode_slice (decoder, _data, _data_size, FALSE);
+      if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+        return status;
+    } else {
+      GstMpeg4ParseResult ret = GST_MPEG4_PARSER_OK;
+      gboolean first_slice = TRUE;
+
+      // next start_code is required to determine the end of last slice
+      _data_size += 4;
+
+      while (_data_size > 0) {
+        // we can skip user data here
+        ret =
+            gst_mpeg4_parse (&video_packet, TRUE, &priv->vop_hdr, _data, 0,
+            _data_size);
+        if (ret != GST_MPEG4_PARSER_OK) {
+          break;
+        }
+
+        if (first_slice) {
+          status = decode_slice (decoder, _data, video_packet.size, FALSE);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            return status;
+          first_slice = FALSE;
+        } else {
+          _data += video_packet.offset;
+          _data_size -= video_packet.offset;
+
+          ret =
+              gst_mpeg4_parse_video_packet_header (&priv->packet_hdr,
+              &priv->vol_hdr, &priv->vop_hdr, &priv->sprite_trajectory, _data,
+              _data_size);
+          if (ret != GST_MPEG4_PARSER_OK)
+            return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+          status =
+              decode_slice (decoder, _data + priv->packet_hdr.size / 8,
+              video_packet.size - priv->packet_hdr.size / 8, TRUE);
+          if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+            return status;
+        }
+
+        _data += video_packet.size;
+        _data_size -= video_packet.size;
+      }
+    }
+    status = decode_current_picture (decoder);
+  } else if (tos->type == GST_MPEG4_USER_DATA
+      || tos->type == GST_MPEG4_VIDEO_SESSION_ERR
+      || tos->type == GST_MPEG4_FBA
+      || tos->type == GST_MPEG4_FBA_PLAN
+      || tos->type == GST_MPEG4_MESH
+      || tos->type == GST_MPEG4_MESH_PLAN
+      || tos->type == GST_MPEG4_STILL_TEXTURE_OBJ
+      || tos->type == GST_MPEG4_TEXTURE_SPATIAL
+      || tos->type == GST_MPEG4_TEXTURE_SNR_LAYER
+      || tos->type == GST_MPEG4_TEXTURE_TILE
+      || tos->type == GST_MPEG4_SHAPE_LAYER
+      || tos->type == GST_MPEG4_STUFFING
+      || tos->type == GST_MPEG4_SYSTEM_FIRST
+      || tos->type == GST_MPEG4_SYSTEM_LAST) {
+    GST_WARNING ("Ignore marker: %x\n", tos->type);
+    status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  } else {
+    GST_ERROR ("unsupported start code %x\n", tos->type);
+    status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  }
+
+  return status;
+}
+
+static GstVaapiDecoderStatus
+decode_buffer (GstVaapiDecoderMpeg4 * decoder, const guchar * buf,
+    guint buf_size)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+  GstMpeg4Packet packet;
+  guint ofs;
+
+  if (priv->is_svh) {
+    status = decode_picture (decoder, buf, buf_size);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+
+    ofs = priv->svh_hdr.size / 8;
+    status = decode_slice (decoder, buf + ofs, buf_size - ofs, FALSE);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  } else {
+    packet.data = buf;
+    packet.offset = 0;
+    packet.size = buf_size;
+    packet.type = (GstMpeg4StartCode) packet.data[0];
+
+    status = decode_packet (decoder, packet);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg4_decode_codec_data (GstVaapiDecoder * base_decoder,
+    const guchar * _buf, guint _buf_size)
+{
+  GstVaapiDecoderMpeg4 *const decoder =
+      GST_VAAPI_DECODER_MPEG4_CAST (base_decoder);
+  GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+  GstMpeg4ParseResult result = GST_MPEG4_PARSER_OK;
+  GstMpeg4Packet packet;
+  guchar *buf;
+  guint pos, buf_size;
+
+  // add additional 0x000001b2 to enclose the last header
+  buf_size = _buf_size + 4;
+  buf = malloc (buf_size);
+  memcpy (buf, _buf, buf_size);
+  buf[buf_size - 4] = 0;
+  buf[buf_size - 3] = 0;
+  buf[buf_size - 2] = 1;
+  buf[buf_size - 1] = 0xb2;
+
+  pos = 0;
+
+  while (result == GST_MPEG4_PARSER_OK && pos < buf_size) {
+    result = gst_mpeg4_parse (&packet, FALSE, NULL, buf, pos, buf_size);
+    if (result != GST_MPEG4_PARSER_OK) {
+      break;
+    }
+    status = decode_packet (decoder, packet);
+    if (GST_VAAPI_DECODER_STATUS_SUCCESS == status) {
+      pos = packet.offset + packet.size;
+    } else {
+      GST_WARNING ("decode mp4 packet failed when decoding codec data\n");
+      break;
+    }
+  }
+  free (buf);
+  return status;
+}
+
+static GstVaapiDecoderStatus
+ensure_decoder (GstVaapiDecoderMpeg4 * decoder)
+{
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+
+  if (!priv->is_opened) {
+    priv->is_opened = gst_vaapi_decoder_mpeg4_open (decoder);
+    if (!priv->is_opened)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
+
+    status =
+        gst_vaapi_decoder_decode_codec_data (GST_VAAPI_DECODER_CAST (decoder));
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg4_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg4 *const decoder =
+      GST_VAAPI_DECODER_MPEG4_CAST (base_decoder);
+  GstVaapiDecoderMpeg4Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+  GstMpeg4Packet packet;
+  GstMpeg4ParseResult result;
+  const guchar *buf;
+  guint size, buf_size, flags = 0;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  size = gst_adapter_available (adapter);
+  buf = gst_adapter_map (adapter, size);
+  if (!buf)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  packet.type = GST_MPEG4_USER_DATA;
+  if (priv->is_svh)
+    result = gst_h263_parse (&packet, buf, 0, size);
+  else
+    result = gst_mpeg4_parse (&packet, FALSE, NULL, buf, 0, size);
+  if (result == GST_MPEG4_PARSER_NO_PACKET_END && at_eos)
+    packet.size = size - packet.offset;
+  else if (result == GST_MPEG4_PARSER_ERROR)
+    return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  else if (result != GST_MPEG4_PARSER_OK)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  buf_size = packet.size;
+  gst_adapter_flush (adapter, packet.offset);
+  unit->size = buf_size;
+
+  /* Check for start of new picture */
+  switch (packet.type) {
+    case GST_MPEG4_VIDEO_SESSION_ERR:
+    case GST_MPEG4_FBA:
+    case GST_MPEG4_FBA_PLAN:
+    case GST_MPEG4_MESH:
+    case GST_MPEG4_MESH_PLAN:
+    case GST_MPEG4_STILL_TEXTURE_OBJ:
+    case GST_MPEG4_TEXTURE_SPATIAL:
+    case GST_MPEG4_TEXTURE_SNR_LAYER:
+    case GST_MPEG4_TEXTURE_TILE:
+    case GST_MPEG4_SHAPE_LAYER:
+    case GST_MPEG4_STUFFING:
+      gst_adapter_flush (adapter, packet.size);
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    case GST_MPEG4_USER_DATA:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+      break;
+    case GST_MPEG4_VISUAL_OBJ_SEQ_END:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
+      break;
+    case GST_MPEG4_VIDEO_OBJ_PLANE:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      /* fall-through */
+    case GST_MPEG4_VISUAL_OBJ_SEQ_START:
+    case GST_MPEG4_VISUAL_OBJ:
+    case GST_MPEG4_GROUP_OF_VOP:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      break;
+    default:
+      if (packet.type >= GST_MPEG4_VIDEO_OBJ_FIRST &&
+          packet.type <= GST_MPEG4_VIDEO_OBJ_LAST) {
+        gst_adapter_flush (adapter, packet.size);
+        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+      }
+      if (packet.type >= GST_MPEG4_VIDEO_LAYER_FIRST &&
+          packet.type <= GST_MPEG4_VIDEO_LAYER_LAST) {
+        break;
+      }
+      if (packet.type >= GST_MPEG4_SYSTEM_FIRST &&
+          packet.type <= GST_MPEG4_SYSTEM_LAST) {
+        flags |= GST_VAAPI_DECODER_UNIT_FLAG_SKIP;
+        break;
+      }
+      GST_WARNING ("unsupported start code (0x%02x)", packet.type);
+      return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+  }
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_mpeg4_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderMpeg4 *const decoder =
+      GST_VAAPI_DECODER_MPEG4_CAST (base_decoder);
+  GstVaapiDecoderStatus status;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  status = decode_buffer (decoder, map_info.data + unit->offset, unit->size);
+  gst_buffer_unmap (buffer, &map_info);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+gst_vaapi_decoder_mpeg4_finalize (GObject * object)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
+
+  gst_vaapi_decoder_mpeg4_destroy (base_decoder);
+  G_OBJECT_CLASS (gst_vaapi_decoder_mpeg4_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_mpeg4_class_init (GstVaapiDecoderMpeg4Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_decoder_mpeg4_finalize;
+
+  decoder_class->reset = gst_vaapi_decoder_mpeg4_reset;
+  decoder_class->parse = gst_vaapi_decoder_mpeg4_parse;
+  decoder_class->decode = gst_vaapi_decoder_mpeg4_decode;
+  decoder_class->decode_codec_data = gst_vaapi_decoder_mpeg4_decode_codec_data;
+}
+
+static void
+gst_vaapi_decoder_mpeg4_init (GstVaapiDecoderMpeg4 * decoder)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+
+  gst_vaapi_decoder_mpeg4_create (base_decoder);
+}
+
+/**
+ * gst_vaapi_decoder_mpeg4_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for MPEG-2 decoding.  The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_mpeg4_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return g_object_new (GST_TYPE_VAAPI_DECODER_MPEG4, "display", display,
+      "caps", caps, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_mpeg4.h
new file mode 100644 (file)
index 0000000..2efd164
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  gstvaapidecoder_mpeg4.h - MPEG-4 decoder
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Halley Zhao <halley.zhao@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_MPEG4_H
+#define GST_VAAPI_DECODER_MPEG4_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER_MPEG4 \
+    (gst_vaapi_decoder_mpeg4_get_type ())
+#define GST_VAAPI_DECODER_MPEG4(decoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_MPEG4, GstVaapiDecoderMpeg4))
+#define GST_VAAPI_IS_DECODER_MPEG4(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_MPEG4))
+
+typedef struct _GstVaapiDecoderMpeg4            GstVaapiDecoderMpeg4;
+
+GType
+gst_vaapi_decoder_mpeg4_get_type (void) G_GNUC_CONST;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_mpeg4_new (GstVaapiDisplay *display, GstCaps *caps);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderMpeg4, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_MPEG4_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_objects.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_objects.c
new file mode 100644 (file)
index 0000000..159625f
--- /dev/null
@@ -0,0 +1,507 @@
+/*
+ *  gstvaapidecoder_objects.c - VA decoder objects helpers
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <gst/vaapi/gstvaapicontext.h>
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapisurfaceproxy_priv.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GET_DECODER(obj)    GST_VAAPI_DECODER_CAST((obj)->parent_instance.codec)
+#define GET_CONTEXT(obj)    GET_DECODER(obj)->context
+#define GET_VA_DISPLAY(obj) GET_DECODER(obj)->va_display
+#define GET_VA_CONTEXT(obj) GET_DECODER(obj)->va_context
+
+static inline void
+gst_video_codec_frame_clear (GstVideoCodecFrame ** frame_ptr)
+{
+  if (!*frame_ptr)
+    return;
+  gst_video_codec_frame_unref (*frame_ptr);
+  *frame_ptr = NULL;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Pictures                                                          --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiPicture, gst_vaapi_picture);
+
+enum
+{
+  GST_VAAPI_CREATE_PICTURE_FLAG_CLONE = 1 << 0,
+  GST_VAAPI_CREATE_PICTURE_FLAG_FIELD = 1 << 1,
+};
+
+void
+gst_vaapi_picture_destroy (GstVaapiPicture * picture)
+{
+  if (picture->slices) {
+    g_ptr_array_unref (picture->slices);
+    picture->slices = NULL;
+  }
+
+  gst_vaapi_codec_object_replace (&picture->iq_matrix, NULL);
+  gst_vaapi_codec_object_replace (&picture->huf_table, NULL);
+  gst_vaapi_codec_object_replace (&picture->bitplane, NULL);
+  gst_vaapi_codec_object_replace (&picture->prob_table, NULL);
+
+  if (picture->proxy) {
+    gst_vaapi_surface_proxy_unref (picture->proxy);
+    picture->proxy = NULL;
+  }
+  picture->surface_id = VA_INVALID_ID;
+  picture->surface = NULL;
+
+  vaapi_destroy_buffer (GET_VA_DISPLAY (picture), &picture->param_id);
+  picture->param = NULL;
+
+  gst_video_codec_frame_clear (&picture->frame);
+  gst_vaapi_picture_replace (&picture->parent_picture, NULL);
+}
+
+gboolean
+gst_vaapi_picture_create (GstVaapiPicture * picture,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  gboolean success;
+
+  picture->param_id = VA_INVALID_ID;
+
+  if (args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_CLONE) {
+    GstVaapiPicture *const parent_picture = GST_VAAPI_PICTURE (args->data);
+
+    picture->parent_picture = gst_vaapi_picture_ref (parent_picture);
+
+    picture->proxy = gst_vaapi_surface_proxy_ref (parent_picture->proxy);
+    picture->type = parent_picture->type;
+    picture->pts = parent_picture->pts;
+    picture->poc = parent_picture->poc;
+    picture->voc = parent_picture->voc;
+    picture->view_id = parent_picture->view_id;
+
+    // Copy all picture flags but "output"
+    GST_VAAPI_PICTURE_FLAG_SET (picture,
+        GST_VAAPI_PICTURE_FLAGS (parent_picture) &
+        (GST_VAAPI_PICTURE_FLAG_SKIPPED |
+            GST_VAAPI_PICTURE_FLAG_REFERENCE |
+            GST_VAAPI_PICTURE_FLAG_INTERLACED |
+            GST_VAAPI_PICTURE_FLAG_FF | GST_VAAPI_PICTURE_FLAG_TFF |
+            GST_VAAPI_PICTURE_FLAG_ONEFIELD |
+            GST_VAAPI_PICTURE_FLAG_RFF | GST_VAAPI_PICTURE_FLAG_MVC));
+
+    // Propagate "corrupted" flag while not presuming that the second
+    // field is itself corrupted if the first one was marked as such
+    if (GST_VAAPI_PICTURE_IS_CORRUPTED (parent_picture) &&
+        !(args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_FIELD))
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_CORRUPTED);
+
+    picture->structure = parent_picture->structure;
+    if ((args->flags & GST_VAAPI_CREATE_PICTURE_FLAG_FIELD) &&
+        GST_VAAPI_PICTURE_IS_INTERLACED (picture)) {
+      switch (picture->structure) {
+        case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
+          picture->structure = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
+          break;
+        case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
+          picture->structure = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
+          break;
+      }
+      GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAG_FF);
+    }
+
+    if (parent_picture->has_crop_rect) {
+      picture->has_crop_rect = TRUE;
+      picture->crop_rect = parent_picture->crop_rect;
+    }
+  } else {
+    picture->type = GST_VAAPI_PICTURE_TYPE_NONE;
+    picture->pts = GST_CLOCK_TIME_NONE;
+
+    picture->proxy =
+        gst_vaapi_context_get_surface_proxy (GET_CONTEXT (picture));
+    if (!picture->proxy)
+      return FALSE;
+
+    picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_FF);
+  }
+  picture->surface = GST_VAAPI_SURFACE_PROXY_SURFACE (picture->proxy);
+  picture->surface_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (picture->proxy);
+
+  success = vaapi_create_buffer (GET_VA_DISPLAY (picture),
+      GET_VA_CONTEXT (picture), VAPictureParameterBufferType,
+      args->param_size, args->param, &picture->param_id, &picture->param);
+  if (!success)
+    return FALSE;
+  picture->param_size = args->param_size;
+
+  picture->slices = g_ptr_array_new_with_free_func ((GDestroyNotify)
+      gst_vaapi_mini_object_unref);
+  if (!picture->slices)
+    return FALSE;
+
+  picture->frame =
+      gst_video_codec_frame_ref (GST_VAAPI_DECODER_CODEC_FRAME (GET_DECODER
+          (picture)));
+  return TRUE;
+}
+
+GstVaapiPicture *
+gst_vaapi_picture_new (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiPictureClass,
+      GST_VAAPI_CODEC_BASE (decoder), param, param_size, NULL, 0, 0);
+  if (!object)
+    return NULL;
+  return GST_VAAPI_PICTURE_CAST (object);
+}
+
+GstVaapiPicture *
+gst_vaapi_picture_new_field (GstVaapiPicture * picture)
+{
+  GstVaapiDecoder *const decoder = GET_DECODER (picture);
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (gst_vaapi_codec_object_get_class
+      (&picture->parent_instance), GST_VAAPI_CODEC_BASE (decoder), NULL,
+      picture->param_size, picture, 0,
+      (GST_VAAPI_CREATE_PICTURE_FLAG_CLONE |
+          GST_VAAPI_CREATE_PICTURE_FLAG_FIELD));
+  if (!object)
+    return NULL;
+  return GST_VAAPI_PICTURE_CAST (object);
+}
+
+GstVaapiPicture *
+gst_vaapi_picture_new_clone (GstVaapiPicture * picture)
+{
+  GstVaapiDecoder *const decoder = GET_DECODER (picture);
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (gst_vaapi_codec_object_get_class
+      (&picture->parent_instance), GST_VAAPI_CODEC_BASE (decoder), NULL,
+      picture->param_size, picture, 0, GST_VAAPI_CREATE_PICTURE_FLAG_CLONE);
+  if (!object)
+    return NULL;
+  return GST_VAAPI_PICTURE_CAST (object);
+}
+
+void
+gst_vaapi_picture_add_slice (GstVaapiPicture * picture, GstVaapiSlice * slice)
+{
+  g_return_if_fail (GST_VAAPI_IS_PICTURE (picture));
+  g_return_if_fail (GST_VAAPI_IS_SLICE (slice));
+
+  g_ptr_array_add (picture->slices, slice);
+}
+
+static gboolean
+do_decode (VADisplay dpy, VAContextID ctx, VABufferID * buf_id, void **buf_ptr)
+{
+  VAStatus status;
+
+  vaapi_unmap_buffer (dpy, *buf_id, buf_ptr);
+
+  status = vaRenderPicture (dpy, ctx, buf_id, 1);
+  if (!vaapi_check_status (status, "vaRenderPicture()"))
+    return FALSE;
+
+  /* XXX: vaRenderPicture() is meant to destroy the VA buffer implicitly */
+  vaapi_destroy_buffer (dpy, buf_id);
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_picture_decode_with_surface_id (GstVaapiPicture * picture,
+    VASurfaceID surface_id)
+{
+  GstVaapiIqMatrix *iq_matrix;
+  GstVaapiBitPlane *bitplane;
+  GstVaapiHuffmanTable *huf_table;
+  GstVaapiProbabilityTable *prob_table;
+  VADisplay va_display;
+  VAContextID va_context;
+  VAStatus status;
+  guint i;
+
+  g_return_val_if_fail (GST_VAAPI_IS_PICTURE (picture), FALSE);
+  g_return_val_if_fail (surface_id != VA_INVALID_SURFACE, FALSE);
+
+  va_display = GET_VA_DISPLAY (picture);
+  va_context = GET_VA_CONTEXT (picture);
+
+  GST_DEBUG ("decode picture 0x%08x", surface_id);
+
+  status = vaBeginPicture (va_display, va_context, surface_id);
+  if (!vaapi_check_status (status, "vaBeginPicture()"))
+    return FALSE;
+
+  if (!do_decode (va_display, va_context, &picture->param_id, &picture->param))
+    return FALSE;
+
+  iq_matrix = picture->iq_matrix;
+  if (iq_matrix && !do_decode (va_display, va_context,
+          &iq_matrix->param_id, &iq_matrix->param))
+    return FALSE;
+
+  bitplane = picture->bitplane;
+  if (bitplane && !do_decode (va_display, va_context,
+          &bitplane->data_id, (void **) &bitplane->data))
+    return FALSE;
+
+  huf_table = picture->huf_table;
+  if (huf_table && !do_decode (va_display, va_context,
+          &huf_table->param_id, (void **) &huf_table->param))
+    return FALSE;
+
+  prob_table = picture->prob_table;
+  if (prob_table && !do_decode (va_display, va_context,
+          &prob_table->param_id, (void **) &prob_table->param))
+    return FALSE;
+
+  for (i = 0; i < picture->slices->len; i++) {
+    GstVaapiSlice *const slice = g_ptr_array_index (picture->slices, i);
+    VABufferID va_buffers[2];
+
+    huf_table = slice->huf_table;
+    if (huf_table && !do_decode (va_display, va_context,
+            &huf_table->param_id, (void **) &huf_table->param))
+      return FALSE;
+
+    vaapi_unmap_buffer (va_display, slice->param_id, NULL);
+    va_buffers[0] = slice->param_id;
+    va_buffers[1] = slice->data_id;
+
+    status = vaRenderPicture (va_display, va_context, va_buffers, 2);
+    if (!vaapi_check_status (status, "vaRenderPicture()"))
+      return FALSE;
+  }
+
+  status = vaEndPicture (va_display, va_context);
+
+  for (i = 0; i < picture->slices->len; i++) {
+    GstVaapiSlice *const slice = g_ptr_array_index (picture->slices, i);
+
+    vaapi_destroy_buffer (va_display, &slice->param_id);
+    vaapi_destroy_buffer (va_display, &slice->data_id);
+  }
+
+  if (!vaapi_check_status (status, "vaEndPicture()"))
+    return FALSE;
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_picture_decode (GstVaapiPicture * picture)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_PICTURE (picture), FALSE);
+
+  return gst_vaapi_picture_decode_with_surface_id (picture,
+      picture->surface_id);
+}
+
+/* Mark picture as output for internal purposes only. Don't push frame out */
+static void
+do_output_internal (GstVaapiPicture * picture)
+{
+  if (GST_VAAPI_PICTURE_IS_OUTPUT (picture))
+    return;
+
+  gst_video_codec_frame_clear (&picture->frame);
+  GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_OUTPUT);
+}
+
+static gboolean
+do_output (GstVaapiPicture * picture)
+{
+  GstVideoCodecFrame *const out_frame = picture->frame;
+  GstVaapiSurfaceProxy *proxy;
+  guint flags = 0;
+
+  if (GST_VAAPI_PICTURE_IS_OUTPUT (picture))
+    return TRUE;
+
+  if (!picture->proxy)
+    return FALSE;
+
+  proxy = gst_vaapi_surface_proxy_ref (picture->proxy);
+
+  if (picture->has_crop_rect)
+    gst_vaapi_surface_proxy_set_crop_rect (proxy, &picture->crop_rect);
+
+  gst_video_codec_frame_set_user_data (out_frame,
+      proxy, (GDestroyNotify) gst_vaapi_mini_object_unref);
+
+  out_frame->pts = picture->pts;
+
+  if (GST_VAAPI_PICTURE_IS_SKIPPED (picture))
+    GST_VIDEO_CODEC_FRAME_FLAG_SET (out_frame,
+        GST_VIDEO_CODEC_FRAME_FLAG_DECODE_ONLY);
+
+  if (GST_VAAPI_PICTURE_IS_CORRUPTED (picture))
+    flags |= GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED;
+
+  if (GST_VAAPI_PICTURE_IS_MVC (picture)) {
+    if (picture->voc == 0)
+      flags |= GST_VAAPI_SURFACE_PROXY_FLAG_FFB;
+    GST_VAAPI_SURFACE_PROXY_VIEW_ID (proxy) = picture->view_id;
+  }
+
+  if (GST_VAAPI_PICTURE_IS_INTERLACED (picture)) {
+    flags |= GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED;
+    if (GST_VAAPI_PICTURE_IS_TFF (picture))
+      flags |= GST_VAAPI_SURFACE_PROXY_FLAG_TFF;
+    if (GST_VAAPI_PICTURE_IS_RFF (picture))
+      flags |= GST_VAAPI_SURFACE_PROXY_FLAG_RFF;
+    if (GST_VAAPI_PICTURE_IS_ONEFIELD (picture))
+      flags |= GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD;
+  }
+  GST_VAAPI_SURFACE_PROXY_FLAG_SET (proxy, flags);
+
+  gst_vaapi_decoder_push_frame (GET_DECODER (picture), out_frame);
+  gst_video_codec_frame_clear (&picture->frame);
+
+  GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_OUTPUT);
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_picture_output (GstVaapiPicture * picture)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_PICTURE (picture), FALSE);
+
+  if (G_UNLIKELY (picture->parent_picture)) {
+    /* Emit the first field to GstVideoDecoder so that to release
+       the underlying GstVideoCodecFrame. However, mark this
+       picture as skipped so that to not display it */
+    GstVaapiPicture *const parent_picture = picture->parent_picture;
+    do {
+      if (!GST_VAAPI_PICTURE_IS_INTERLACED (parent_picture))
+        break;
+      if (!GST_VAAPI_PICTURE_IS_FIRST_FIELD (parent_picture))
+        break;
+      if (parent_picture->frame == picture->frame)
+        do_output_internal (parent_picture);
+      else {
+        GST_VAAPI_PICTURE_FLAG_SET (parent_picture,
+            GST_VAAPI_PICTURE_FLAG_SKIPPED);
+        if (!do_output (parent_picture))
+          return FALSE;
+      }
+    } while (0);
+  }
+  return do_output (picture);
+}
+
+void
+gst_vaapi_picture_set_crop_rect (GstVaapiPicture * picture,
+    const GstVaapiRectangle * crop_rect)
+{
+  g_return_if_fail (GST_VAAPI_IS_PICTURE (picture));
+
+  picture->has_crop_rect = crop_rect != NULL;
+  if (picture->has_crop_rect)
+    picture->crop_rect = *crop_rect;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Slices                                                            --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiSlice, gst_vaapi_slice);
+
+void
+gst_vaapi_slice_destroy (GstVaapiSlice * slice)
+{
+  VADisplay const va_display = GET_VA_DISPLAY (slice);
+
+  gst_vaapi_codec_object_replace (&slice->huf_table, NULL);
+
+  vaapi_destroy_buffer (va_display, &slice->data_id);
+  vaapi_destroy_buffer (va_display, &slice->param_id);
+  slice->param = NULL;
+}
+
+gboolean
+gst_vaapi_slice_create (GstVaapiSlice * slice,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  VASliceParameterBufferBase *slice_param;
+  gboolean success;
+
+  slice->param_id = VA_INVALID_ID;
+  slice->data_id = VA_INVALID_ID;
+
+  success = vaapi_create_buffer (GET_VA_DISPLAY (slice), GET_VA_CONTEXT (slice),
+      VASliceDataBufferType, args->data_size, args->data, &slice->data_id,
+      NULL);
+  if (!success)
+    return FALSE;
+
+  g_assert (args->param_num >= 1);
+  success = vaapi_create_n_elements_buffer (GET_VA_DISPLAY (slice),
+      GET_VA_CONTEXT (slice), VASliceParameterBufferType, args->param_size,
+      args->param, &slice->param_id, &slice->param, args->param_num);
+  if (!success)
+    return FALSE;
+
+  slice_param = slice->param;
+  slice_param->slice_data_size = args->data_size;
+  slice_param->slice_data_offset = 0;
+  slice_param->slice_data_flag = VA_SLICE_DATA_FLAG_ALL;
+  return TRUE;
+}
+
+GstVaapiSlice *
+gst_vaapi_slice_new (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size, const guchar * data, guint data_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiSliceClass,
+      GST_VAAPI_CODEC_BASE (decoder), param, param_size, data, data_size, 0);
+  return GST_VAAPI_SLICE_CAST (object);
+}
+
+GstVaapiSlice *
+gst_vaapi_slice_new_n_params (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size, guint param_num, const guchar * data,
+    guint data_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new_with_param_num (&GstVaapiSliceClass,
+      GST_VAAPI_CODEC_BASE (decoder), param, param_size, param_num, data,
+      data_size, 0);
+  return GST_VAAPI_SLICE_CAST (object);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_objects.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_objects.h
new file mode 100644 (file)
index 0000000..cc301d1
--- /dev/null
@@ -0,0 +1,294 @@
+/*
+ *  gstvaapidecoder_objects.h - VA decoder objects
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_OBJECTS_H
+#define GST_VAAPI_DECODER_OBJECTS_H
+
+#include <gst/vaapi/gstvaapicodec_objects.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiPicture         GstVaapiPicture;
+typedef struct _GstVaapiSlice           GstVaapiSlice;
+
+/* ------------------------------------------------------------------------- */
+/* --- Pictures                                                          --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_PICTURE_CAST(obj) \
+  ((GstVaapiPicture *) (obj))
+
+#define GST_VAAPI_PICTURE(obj) \
+  GST_VAAPI_PICTURE_CAST (obj)
+
+#define GST_VAAPI_IS_PICTURE(obj) \
+  (GST_VAAPI_PICTURE (obj) != NULL)
+
+typedef enum
+{
+  GST_VAAPI_PICTURE_TYPE_NONE = 0,      // Undefined
+  GST_VAAPI_PICTURE_TYPE_I,             // Intra
+  GST_VAAPI_PICTURE_TYPE_P,             // Predicted
+  GST_VAAPI_PICTURE_TYPE_B,             // Bi-directional predicted
+  GST_VAAPI_PICTURE_TYPE_S,             // S(GMC)-VOP (MPEG-4)
+  GST_VAAPI_PICTURE_TYPE_SI,            // Switching Intra
+  GST_VAAPI_PICTURE_TYPE_SP,            // Switching Predicted
+  GST_VAAPI_PICTURE_TYPE_BI,            // BI type (VC-1)
+} GstVaapiPictureType;
+
+/**
+ * GstVaapiPictureFlags:
+ * @GST_VAAPI_PICTURE_FLAG_SKIPPED: skipped frame
+ * @GST_VAAPI_PICTURE_FLAG_REFERENCE: reference frame
+ * @GST_VAAPI_PICTURE_FLAG_OUTPUT: frame was output
+ * @GST_VAAPI_PICTURE_FLAG_INTERLACED: interlaced frame
+ * @GST_VAAPI_PICTURE_FLAG_FF: first-field
+ * @GST_VAAPI_PICTURE_FLAG_TFF: top-field-first
+ * @GST_VAAPI_PICTURE_FLAG_ONEFIELD: only one field is valid
+ * @GST_VAAPI_PICTURE_FLAG_MVC: multiview component
+ * @GST_VAAPI_PICTURE_FLAG_RFF: repeat-first-field
+ * @GST_VAAPI_PICTURE_FLAG_CORRUPTED: picture was reconstructed from
+ *   corrupted references
+ * @GST_VAAPI_PICTURE_FLAG_LAST: first flag that can be used by subclasses
+ *
+ * Enum values used for #GstVaapiPicture flags.
+ */
+typedef enum
+{
+  GST_VAAPI_PICTURE_FLAG_SKIPPED    = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 0),
+  GST_VAAPI_PICTURE_FLAG_REFERENCE  = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 1),
+  GST_VAAPI_PICTURE_FLAG_OUTPUT     = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 2),
+  GST_VAAPI_PICTURE_FLAG_INTERLACED = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 3),
+  GST_VAAPI_PICTURE_FLAG_FF         = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 4),
+  GST_VAAPI_PICTURE_FLAG_TFF        = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 5),
+  GST_VAAPI_PICTURE_FLAG_ONEFIELD   = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 6),
+  GST_VAAPI_PICTURE_FLAG_MVC        = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 7),
+  GST_VAAPI_PICTURE_FLAG_RFF        = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 8),
+  GST_VAAPI_PICTURE_FLAG_CORRUPTED  = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 9),
+  GST_VAAPI_PICTURE_FLAG_LAST       = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 10),
+} GstVaapiPictureFlags;
+
+#define GST_VAAPI_PICTURE_FLAGS         GST_VAAPI_MINI_OBJECT_FLAGS
+#define GST_VAAPI_PICTURE_FLAG_IS_SET   GST_VAAPI_MINI_OBJECT_FLAG_IS_SET
+#define GST_VAAPI_PICTURE_FLAG_SET      GST_VAAPI_MINI_OBJECT_FLAG_SET
+#define GST_VAAPI_PICTURE_FLAG_UNSET    GST_VAAPI_MINI_OBJECT_FLAG_UNSET
+
+#define GST_VAAPI_PICTURE_IS_SKIPPED(picture) \
+  GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED)
+
+#define GST_VAAPI_PICTURE_IS_REFERENCE(picture) \
+  GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE)
+
+#define GST_VAAPI_PICTURE_IS_OUTPUT(picture) \
+  GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_OUTPUT)
+
+#define GST_VAAPI_PICTURE_IS_INTERLACED(picture) \
+  GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_INTERLACED)
+
+#define GST_VAAPI_PICTURE_IS_FIRST_FIELD(picture) \
+  GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_FF)
+
+#define GST_VAAPI_PICTURE_IS_TFF(picture) \
+  GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_TFF)
+
+#define GST_VAAPI_PICTURE_IS_RFF(picture) \
+  GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_RFF)
+
+#define GST_VAAPI_PICTURE_IS_ONEFIELD(picture) \
+  GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_ONEFIELD)
+
+#define GST_VAAPI_PICTURE_IS_FRAME(picture) \
+  (GST_VAAPI_PICTURE (picture)->structure == GST_VAAPI_PICTURE_STRUCTURE_FRAME)
+
+#define GST_VAAPI_PICTURE_IS_COMPLETE(picture)          \
+  (GST_VAAPI_PICTURE_IS_FRAME (picture) ||              \
+   GST_VAAPI_PICTURE_IS_ONEFIELD (picture) ||           \
+   !GST_VAAPI_PICTURE_IS_FIRST_FIELD (picture))
+
+#define GST_VAAPI_PICTURE_IS_MVC(picture) \
+  (GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_MVC))
+
+#define GST_VAAPI_PICTURE_IS_CORRUPTED(picture) \
+  (GST_VAAPI_PICTURE_FLAG_IS_SET (picture, GST_VAAPI_PICTURE_FLAG_CORRUPTED))
+
+/**
+ * GstVaapiPicture:
+ *
+ * A #GstVaapiCodecObject holding a picture parameter.
+ */
+struct _GstVaapiPicture
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+  GstVaapiPicture *parent_picture;
+  GstVideoCodecFrame *frame;
+  GstVaapiSurface *surface;
+  GstVaapiSurfaceProxy *proxy;
+  VABufferID param_id;
+  guint param_size;
+
+  /*< public >*/
+  GstVaapiPictureType type;
+  VASurfaceID surface_id;
+  gpointer param;
+  GPtrArray *slices;
+  GstVaapiIqMatrix *iq_matrix;
+  GstVaapiHuffmanTable *huf_table;
+  GstVaapiBitPlane *bitplane;
+  GstVaapiProbabilityTable *prob_table;
+  GstClockTime pts;
+  gint32 poc;
+  guint16 voc;
+  guint16 view_id;
+  guint structure;
+  GstVaapiRectangle crop_rect;
+  guint has_crop_rect:1;
+};
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_picture_destroy (GstVaapiPicture * picture);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_picture_create (GstVaapiPicture * picture,
+    const GstVaapiCodecObjectConstructorArgs * args);
+
+G_GNUC_INTERNAL
+GstVaapiPicture *
+gst_vaapi_picture_new (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size);
+
+G_GNUC_INTERNAL
+GstVaapiPicture *
+gst_vaapi_picture_new_field (GstVaapiPicture * picture);
+
+G_GNUC_INTERNAL
+GstVaapiPicture *
+gst_vaapi_picture_new_clone (GstVaapiPicture * picture);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_picture_add_slice (GstVaapiPicture * picture, GstVaapiSlice * slice);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_picture_decode (GstVaapiPicture * picture);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_picture_decode_with_surface_id (GstVaapiPicture * picture,
+    VASurfaceID surface_id);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_picture_output (GstVaapiPicture * picture);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_picture_set_crop_rect (GstVaapiPicture * picture,
+    const GstVaapiRectangle * crop_rect);
+
+#define gst_vaapi_picture_ref(picture) \
+  gst_vaapi_codec_object_ref (picture)
+
+#define gst_vaapi_picture_unref(picture) \
+  gst_vaapi_codec_object_unref (picture)
+
+#define gst_vaapi_picture_replace(old_picture_ptr, new_picture) \
+  gst_vaapi_codec_object_replace (old_picture_ptr, new_picture)
+
+/* ------------------------------------------------------------------------- */
+/* --- Slices                                                            --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_SLICE_CAST(obj) \
+  ((GstVaapiSlice *) (obj))
+
+#define GST_VAAPI_SLICE(obj) \
+  GST_VAAPI_SLICE_CAST (obj)
+
+#define GST_VAAPI_IS_SLICE(obj) \
+  (GST_VAAPI_SLICE (obj) != NULL)
+
+/**
+ * GstVaapiSlice:
+ *
+ * A #GstVaapiCodecObject holding a slice parameter.
+ */
+struct _GstVaapiSlice
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+
+  /*< public >*/
+  VABufferID param_id;
+  VABufferID data_id;
+  gpointer param;
+
+  /* Per-slice overrides */
+  GstVaapiHuffmanTable *huf_table;
+};
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_slice_destroy (GstVaapiSlice * slice);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_slice_create (GstVaapiSlice * slice,
+    const GstVaapiCodecObjectConstructorArgs * args);
+
+G_GNUC_INTERNAL
+GstVaapiSlice *
+gst_vaapi_slice_new (GstVaapiDecoder * decoder, gconstpointer param,
+    guint param_size, const guchar * data, guint data_size);
+
+G_GNUC_INTERNAL
+GstVaapiSlice *
+gst_vaapi_slice_new_n_params (GstVaapiDecoder * decoder,
+    gconstpointer param, guint param_size, guint param_num, const guchar * data,
+    guint data_size);
+
+/* ------------------------------------------------------------------------- */
+/* --- Helpers to create codec-dependent objects                         --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_PICTURE_NEW(codec, decoder)                   \
+  gst_vaapi_picture_new (GST_VAAPI_DECODER_CAST (decoder),      \
+      NULL, sizeof (G_PASTE (VAPictureParameterBuffer, codec)))
+
+#define GST_VAAPI_SLICE_NEW(codec, decoder, buf, buf_size)      \
+  gst_vaapi_slice_new (GST_VAAPI_DECODER_CAST (decoder),        \
+      NULL, sizeof (G_PASTE (VASliceParameterBuffer, codec)),   \
+      buf, buf_size)
+
+#define GST_VAAPI_SLICE_NEW_N_PARAMS(codec, decoder, buf, buf_size, n) \
+  gst_vaapi_slice_new_n_params (GST_VAAPI_DECODER_CAST (decoder),    \
+      NULL, sizeof (G_PASTE (VASliceParameterBuffer, codec)), n,     \
+      buf, buf_size)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_OBJECTS_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_priv.h
new file mode 100644 (file)
index 0000000..10b8d2c
--- /dev/null
@@ -0,0 +1,275 @@
+/*
+ *  gstvaapidecoder_priv.h - VA decoder abstraction (private definitions)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_PRIV_H
+#define GST_VAAPI_DECODER_PRIV_H
+
+#include "sysdeps.h"
+#include <gst/vaapi/gstvaapidecoder.h>
+#include <gst/vaapi/gstvaapidecoder_unit.h>
+#include <gst/vaapi/gstvaapicontext.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_DECODER_CAST(decoder) \
+    ((GstVaapiDecoder *)(decoder))
+
+#define GST_VAAPI_DECODER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DECODER, GstVaapiDecoderClass))
+
+#define GST_VAAPI_IS_DECODER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_DECODER))
+
+#define GST_VAAPI_DECODER_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DECODER, GstVaapiDecoderClass))
+
+typedef struct _GstVaapiDecoderClass GstVaapiDecoderClass;
+
+/**
+ * GST_VAAPI_PARSER_STATE:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the #GstVaapiParserState of @decoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_PARSER_STATE
+#define GST_VAAPI_PARSER_STATE(decoder) \
+    (&GST_VAAPI_DECODER_CAST(decoder)->parser_state)
+
+/**
+ * GST_VAAPI_DECODER_DISPLAY:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the #GstVaapiDisplay of @decoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DECODER_DISPLAY
+#define GST_VAAPI_DECODER_DISPLAY(decoder) \
+    GST_VAAPI_DECODER_CAST(decoder)->display
+
+/**
+ * GST_VAAPI_DECODER_CONTEXT:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the #GstVaapiContext of @decoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DECODER_CONTEXT
+#define GST_VAAPI_DECODER_CONTEXT(decoder) \
+    GST_VAAPI_DECODER_CAST(decoder)->context
+
+/**
+ * GST_VAAPI_DECODER_CODEC:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the #GstVaapiCodec of @decoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DECODER_CODEC
+#define GST_VAAPI_DECODER_CODEC(decoder) \
+    GST_VAAPI_DECODER_CAST(decoder)->codec
+
+/**
+ * GST_VAAPI_DECODER_CODEC_STATE:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the #GstVideoCodecState holding codec state
+ * for @decoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DECODER_CODEC_STATE
+#define GST_VAAPI_DECODER_CODEC_STATE(decoder) \
+    GST_VAAPI_DECODER_CAST(decoder)->codec_state
+
+/**
+ * GST_VAAPI_DECODER_CODEC_DATA:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the #GstBuffer holding optional codec data
+ * for @decoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DECODER_CODEC_DATA
+#define GST_VAAPI_DECODER_CODEC_DATA(decoder) \
+    GST_VAAPI_DECODER_CODEC_STATE(decoder)->codec_data
+
+/**
+ * GST_VAAPI_DECODER_CODEC_FRAME:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the #GstVideoCodecFrame holding decoder
+ * units for the current frame.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DECODER_CODEC_FRAME
+#define GST_VAAPI_DECODER_CODEC_FRAME(decoder) \
+    GST_VAAPI_PARSER_STATE(decoder)->current_frame
+
+/**
+ * GST_VAAPI_DECODER_WIDTH:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the coded width of the picture
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DECODER_WIDTH
+#define GST_VAAPI_DECODER_WIDTH(decoder) \
+    GST_VAAPI_DECODER_CODEC_STATE(decoder)->info.width
+
+/**
+ * GST_VAAPI_DECODER_HEIGHT:
+ * @decoder: a #GstVaapiDecoder
+ *
+ * Macro that evaluates to the coded height of the picture
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DECODER_HEIGHT
+#define GST_VAAPI_DECODER_HEIGHT(decoder) \
+    GST_VAAPI_DECODER_CODEC_STATE(decoder)->info.height
+
+/* End-of-Stream buffer */
+#define GST_BUFFER_FLAG_EOS (GST_BUFFER_FLAG_LAST + 0)
+
+#define GST_BUFFER_IS_EOS(buffer) \
+    GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_EOS)
+
+#define GST_VAAPI_DECODER_GET_PRIVATE(obj)                      \
+    (G_TYPE_INSTANCE_GET_PRIVATE((obj),                         \
+                                 GST_VAAPI_TYPE_DECODER,        \
+                                 GstVaapiDecoderPrivate))
+
+typedef enum {
+  GST_VAAPI_DECODER_STATUS_DROP_FRAME = -2
+} GstVaapiDecoderStatusPrivate;
+
+typedef struct _GstVaapiParserState GstVaapiParserState;
+struct _GstVaapiParserState
+{
+  GstVideoCodecFrame *current_frame;
+  guint32 current_frame_number;
+  GstAdapter *current_adapter;
+  GstAdapter *input_adapter;
+  gint input_offset1;
+  gint input_offset2;
+  GstAdapter *output_adapter;
+  GstVaapiDecoderUnit next_unit;
+  guint next_unit_pending:1;
+  guint at_eos:1;
+};
+
+/**
+ * GstVaapiDecoder:
+ *
+ * A VA decoder base instance.
+ */
+struct _GstVaapiDecoder
+{
+  /*< private >*/
+  GstObject parent_instance;
+
+  gpointer user_data;
+  GstVaapiDisplay *display;
+  VADisplay va_display;
+  GstVaapiContext *context;
+  VAContextID va_context;
+  GstVaapiCodec codec;
+  GstVideoCodecState *codec_state;
+  GAsyncQueue *buffers;
+  GAsyncQueue *frames;
+  GstVaapiParserState parser_state;
+  GstVaapiDecoderStateChangedFunc codec_state_changed_func;
+  gpointer codec_state_changed_data;
+};
+
+/**
+ * GstVaapiDecoderClass:
+ *
+ * A VA decoder base class.
+ */
+struct _GstVaapiDecoderClass
+{
+  /*< private >*/
+  GstObjectClass parent_class;
+
+  GstVaapiDecoderStatus (*parse) (GstVaapiDecoder * decoder,
+      GstAdapter * adapter, gboolean at_eos,
+      struct _GstVaapiDecoderUnit * unit);
+  GstVaapiDecoderStatus (*decode) (GstVaapiDecoder * decoder,
+      struct _GstVaapiDecoderUnit * unit);
+  GstVaapiDecoderStatus (*start_frame) (GstVaapiDecoder * decoder,
+      struct _GstVaapiDecoderUnit * unit);
+  GstVaapiDecoderStatus (*end_frame) (GstVaapiDecoder * decoder);
+  GstVaapiDecoderStatus (*flush) (GstVaapiDecoder * decoder);
+  GstVaapiDecoderStatus (*reset) (GstVaapiDecoder * decoder);
+  GstVaapiDecoderStatus (*decode_codec_data) (GstVaapiDecoder * decoder,
+      const guchar * buf, guint buf_size);
+};
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_set_picture_size (GstVaapiDecoder * decoder,
+    guint width, guint height);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_set_framerate (GstVaapiDecoder * decoder,
+    guint fps_n, guint fps_d);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_set_pixel_aspect_ratio (GstVaapiDecoder * decoder,
+    guint par_n, guint par_d);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_set_interlace_mode (GstVaapiDecoder * decoder,
+    GstVideoInterlaceMode mode);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_set_interlaced (GstVaapiDecoder * decoder,
+    gboolean interlaced);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_set_multiview_mode (GstVaapiDecoder * decoder,
+    gint views, GstVideoMultiviewMode mv_mode, GstVideoMultiviewFlags mv_flags);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_decoder_ensure_context (GstVaapiDecoder * decoder,
+    GstVaapiContextInfo * cip);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_push_frame (GstVaapiDecoder * decoder,
+    GstVideoCodecFrame * frame);
+
+G_GNUC_INTERNAL
+GstVaapiDecoderStatus
+gst_vaapi_decoder_decode_codec_data (GstVaapiDecoder * decoder);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_unit.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_unit.c
new file mode 100644 (file)
index 0000000..fd08a83
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ *  gstvaapidecoder_unit.c - VA decoder units
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_unit
+ * @short_description: Decoder unit
+ */
+
+#include "sysdeps.h"
+#include "gstvaapidecoder_unit.h"
+
+/**
+ * gst_vaapi_decoder_unit_init:
+ * @unit: a #GstVaapiDecoderUnit
+ *
+ * Initializes internal resources bound to the supplied decoder @unit.
+ *
+ * @note This is an internal function used to implement lightweight
+ * sub-classes.
+ */
+void
+gst_vaapi_decoder_unit_init (GstVaapiDecoderUnit * unit)
+{
+  unit->flags = 0;
+  unit->size = 0;
+  unit->offset = 0;
+
+  unit->parsed_info = NULL;
+  unit->parsed_info_destroy_notify = NULL;
+}
+
+/**
+ * gst_vaapi_decoder_unit_clear:
+ * @unit: a #GstVaapiDecoderUnit
+ *
+ * Deallocates any internal resources bound to the supplied decoder
+ * @unit.
+ *
+ * @note This is an internal function used to implement lightweight
+ * sub-classes.
+ */
+void
+gst_vaapi_decoder_unit_clear (GstVaapiDecoderUnit * unit)
+{
+  gst_vaapi_decoder_unit_set_parsed_info (unit, NULL, NULL);
+}
+
+/**
+ * gst_vaapi_decoder_unit_set_parsed_info:
+ * @unit: a #GstVaapiDecoderUnit
+ * @parsed_info: parser info
+ * @destroy_notify: (closure parsed_info): a #GDestroyNotify
+ *
+ * Sets @parsed_info on the object and the #GDestroyNotify that will be
+ * called when the data is freed.
+ *
+ * If some @parsed_info was previously set, then the former @destroy_notify
+ * function will be called before the @parsed_info is replaced.
+ */
+void
+gst_vaapi_decoder_unit_set_parsed_info (GstVaapiDecoderUnit * unit,
+    gpointer parsed_info, GDestroyNotify destroy_notify)
+{
+  g_return_if_fail (GST_VAAPI_IS_DECODER_UNIT (unit));
+
+  if (unit->parsed_info && unit->parsed_info_destroy_notify)
+    unit->parsed_info_destroy_notify (unit->parsed_info);
+  unit->parsed_info = parsed_info;
+  unit->parsed_info_destroy_notify = destroy_notify;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_unit.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_unit.h
new file mode 100644 (file)
index 0000000..7ee77a0
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *  gstvaapidecoder_unit.h - VA decoder units
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_UNIT_H
+#define GST_VAAPI_DECODER_UNIT_H
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiDecoderUnit             GstVaapiDecoderUnit;
+
+#define GST_VAAPI_DECODER_UNIT(unit) \
+    ((GstVaapiDecoderUnit *)(unit))
+
+#define GST_VAAPI_IS_DECODER_UNIT(unit) \
+    (GST_VAAPI_DECODER_UNIT(unit) != NULL)
+
+/**
+ * GstVaapiDecoderUnitFlags:
+ * @GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START: marks the start of a frame.
+ * @GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END: marks the end of a frame.
+ * @GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END: marks the end of a stream.
+ * @GST_VAAPI_DECODER_UNIT_FLAG_SLICE: the unit contains slice data.
+ * @GST_VAAPI_DECODER_UNIT_FLAG_SKIP: marks the unit as unused/skipped.
+ *
+ * Flags for #GstVaapiDecoderUnit.
+ */
+typedef enum {
+    GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START = (1 << 0),
+    GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END   = (1 << 1),
+    GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END  = (1 << 2),
+    GST_VAAPI_DECODER_UNIT_FLAG_SLICE       = (1 << 3),
+    GST_VAAPI_DECODER_UNIT_FLAG_SKIP        = (1 << 4),
+    GST_VAAPI_DECODER_UNIT_FLAG_LAST        = (1 << 5)
+} GstVaapiDecoderUnitFlags;
+
+/**
+ * GST_VAAPI_DECODER_UNIT_FLAGS:
+ * @unit: a #GstVaapiDecoderUnit
+ *
+ * The entire set of flags for the @unit
+ */
+#define GST_VAAPI_DECODER_UNIT_FLAGS(unit) \
+    ((unit)->flags)
+
+/**
+ * GST_VAAPI_DECODER_UNIT_FLAG_IS_SET:
+ * @unit: a #GstVaapiDecoderUnit
+ * @flag: a flag to check for
+ *
+ * Checks whether the given @flag is set
+ */
+#define GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit, flag) \
+    ((GST_VAAPI_DECODER_UNIT_FLAGS(unit) & (flag)) != 0)
+
+/**
+ * GST_VAAPI_DECODER_UNIT_FLAG_SET:
+ * @unit: a #GstVaapiDecoderUnit
+ * @flags: flags to set
+ *
+ * This macro sets the given bits
+ */
+#define GST_VAAPI_DECODER_UNIT_FLAG_SET(unit, flags) \
+    (GST_VAAPI_DECODER_UNIT_FLAGS(unit) |= (flags))
+
+/**
+ * GST_VAAPI_DECODER_UNIT_FLAG_UNSET:
+ * @unit: a #GstVaapiDecoderUnit
+ * @flags: flags to unset
+ *
+ * This macro unsets the given bits.
+ */
+#define GST_VAAPI_DECODER_UNIT_FLAG_UNSET(unit, flags) \
+    (GST_VAAPI_DECODER_UNIT_FLAGS(unit) &= ~(flags))
+
+/**
+ * GST_VAAPI_DECODER_UNIT_IS_FRAME_START:
+ * @unit: a #GstVaapiDecoderUnit
+ *
+ * Tests if the decoder unit marks the start of a frame.
+ *
+ * The start of a frame is codec dependent but it may include any new
+ * sequence header.
+ */
+#define GST_VAAPI_DECODER_UNIT_IS_FRAME_START(unit) \
+    (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit,   \
+        GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START))
+
+/**
+ * GST_VAAPI_DECODER_UNIT_IS_FRAME_END:
+ * @unit: a #GstVaapiDecoderUnit
+ *
+ * Tests if the decoder unit marks the end of a frame.
+ *
+ * The end of a frame is codec dependent but it is usually represented
+ * by the last bitstream chunk that holds valid slice data.
+ */
+#define GST_VAAPI_DECODER_UNIT_IS_FRAME_END(unit) \
+    (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit,   \
+        GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END))
+
+/**
+ * GST_VAAPI_DECODER_UNIT_IS_STREAM_END:
+ * @unit: a #GstVaapiDecoderUnit
+ *
+ * Tests if the decoder unit marks the end of the stream.
+ */
+#define GST_VAAPI_DECODER_UNIT_IS_STREAM_END(unit) \
+    (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit,   \
+        GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END))
+
+/**
+ * GST_VAAPI_DECODER_UNIT_IS_SLICE:
+ * @unit: a #GstVaapiDecoderUnit
+ *
+ * Tests if the decoder unit contains slice data.
+ */
+#define GST_VAAPI_DECODER_UNIT_IS_SLICE(unit) \
+    (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit,   \
+        GST_VAAPI_DECODER_UNIT_FLAG_SLICE))
+
+/**
+ * GST_VAAPI_DECODER_UNIT_IS_SKIPPED:
+ * @unit: a #GstVaapiDecoderUnit
+ *
+ * Tests if the decoder unit is not needed for decoding an can be skipped.
+ * i.e. #GstVaapiDecoder sub-classes won't see this chunk of bitstream
+ * data.
+ */
+#define GST_VAAPI_DECODER_UNIT_IS_SKIPPED(unit) \
+    (GST_VAAPI_DECODER_UNIT_FLAG_IS_SET(unit,   \
+        GST_VAAPI_DECODER_UNIT_FLAG_SKIP))
+
+/**
+ * GstVaapiDecoderUnit:
+ * @size: size in bytes of this bitstream unit
+ * @offset: relative offset in bytes to bitstream unit within the
+ *    associated #GstVideoCodecFrame input_buffer
+ * @parsed_info: parser-specific data (this is codec specific)
+ * @parsed_info_destroy_notify: function used to release @parsed_info data
+ *
+ * A chunk of bitstream data that was parsed.
+ */
+struct _GstVaapiDecoderUnit {
+    guint               flags;
+    guint               size;
+    guint               offset;
+    gpointer            parsed_info;
+    GDestroyNotify      parsed_info_destroy_notify;
+};
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_unit_init(GstVaapiDecoderUnit *unit);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_unit_clear(GstVaapiDecoderUnit *unit);
+
+G_GNUC_INTERNAL
+GstVaapiDecoderUnit *
+gst_vaapi_decoder_unit_new(void);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_decoder_unit_set_parsed_info(GstVaapiDecoderUnit *unit,
+    gpointer parsed_info, GDestroyNotify destroy_notify);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_UNIT_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vc1.c
new file mode 100644 (file)
index 0000000..d8dcbce
--- /dev/null
@@ -0,0 +1,1484 @@
+/*
+ *  gstvaapidecoder_vc1.c - VC-1 decoder
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_vc1
+ * @short_description: VC-1 decoder
+ */
+
+#include "sysdeps.h"
+#include <gst/codecparsers/gstvc1parser.h>
+#include "gstvaapidecoder_vc1.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_dpb.h"
+#include "gstvaapidecoder_unit.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_DECODER_VC1_CAST(decoder) \
+    ((GstVaapiDecoderVC1 *)(decoder))
+
+typedef struct _GstVaapiDecoderVC1Private GstVaapiDecoderVC1Private;
+typedef struct _GstVaapiDecoderVC1Class GstVaapiDecoderVC1Class;
+
+/**
+ * GstVaapiDecoderVC1:
+ *
+ * A decoder based on VC1.
+ */
+struct _GstVaapiDecoderVC1Private
+{
+  GstVaapiProfile profile;
+  guint width;
+  guint height;
+  GstVC1SeqHdr seq_hdr;
+  GstVC1EntryPointHdr entrypoint_hdr;
+  GstVC1FrameHdr frame_hdr;
+  GstVC1BitPlanes *bitplanes;
+  GstVaapiPicture *current_picture;
+  GstVaapiPicture *last_non_b_picture;
+  GstVaapiDpb *dpb;
+  gint32 next_poc;
+  guint8 *rbdu_buffer;
+  guint8 rndctrl;
+  guint rbdu_buffer_size;
+  guint is_opened:1;
+  guint has_codec_data:1;
+  guint has_entrypoint:1;
+  guint size_changed:1;
+  guint profile_changed:1;
+  guint closed_entry:1;
+  guint broken_link:1;
+};
+
+/**
+ * GstVaapiDecoderVC1:
+ *
+ * A decoder based on VC1.
+ */
+struct _GstVaapiDecoderVC1
+{
+  /*< private > */
+  GstVaapiDecoder parent_instance;
+  GstVaapiDecoderVC1Private priv;
+};
+
+/**
+ * GstVaapiDecoderVC1Class:
+ *
+ * A decoder class based on VC1.
+ */
+struct _GstVaapiDecoderVC1Class
+{
+  /*< private > */
+  GstVaapiDecoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiDecoderVC1, gst_vaapi_decoder_vc1,
+    GST_TYPE_VAAPI_DECODER);
+
+static GstVaapiDecoderStatus
+get_status (GstVC1ParserResult result)
+{
+  GstVaapiDecoderStatus status;
+
+  switch (result) {
+    case GST_VC1_PARSER_OK:
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+    case GST_VC1_PARSER_NO_BDU_END:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+      break;
+    case GST_VC1_PARSER_ERROR:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+      break;
+    default:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+      break;
+  }
+  return status;
+}
+
+static void
+gst_vaapi_decoder_vc1_close (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+
+  gst_vaapi_picture_replace (&priv->last_non_b_picture, NULL);
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  gst_vaapi_dpb_replace (&priv->dpb, NULL);
+
+  if (priv->bitplanes) {
+    gst_vc1_bitplanes_free (priv->bitplanes);
+    priv->bitplanes = NULL;
+  }
+  priv->is_opened = FALSE;
+}
+
+static gboolean
+gst_vaapi_decoder_vc1_open (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_vc1_close (decoder);
+
+  priv->dpb = gst_vaapi_dpb_new (2);
+  if (!priv->dpb)
+    return FALSE;
+
+  priv->bitplanes = gst_vc1_bitplanes_new ();
+  if (!priv->bitplanes)
+    return FALSE;
+
+  memset (&priv->seq_hdr, 0, sizeof (GstVC1SeqHdr));
+  memset (&priv->entrypoint_hdr, 0, sizeof (GstVC1EntryPointHdr));
+  memset (&priv->frame_hdr, 0, sizeof (GstVC1FrameHdr));
+
+  return TRUE;
+}
+
+static void
+gst_vaapi_decoder_vc1_destroy (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder);
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_vc1_close (decoder);
+
+  if (priv->rbdu_buffer) {
+    g_clear_pointer (&priv->rbdu_buffer, g_free);
+    priv->rbdu_buffer_size = 0;
+  }
+}
+
+static gboolean
+gst_vaapi_decoder_vc1_create (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder);
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+
+  priv->has_codec_data = priv->has_entrypoint =
+      priv->size_changed = priv->profile_changed =
+      priv->closed_entry = priv->broken_link = FALSE;
+
+  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  priv->rndctrl = 0;
+  priv->width = priv->height = 0;
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vc1_reset (GstVaapiDecoder * base_decoder)
+{
+  gst_vaapi_decoder_vc1_destroy (base_decoder);
+  gst_vaapi_decoder_vc1_create (base_decoder);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+ensure_context (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVaapiProfile profiles[2];
+  GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+  guint i, n_profiles = 0;
+  gboolean reset_context = FALSE;
+
+  if (priv->profile_changed) {
+    GST_DEBUG ("profile changed");
+    priv->profile_changed = FALSE;
+    reset_context = TRUE;
+
+    profiles[n_profiles++] = priv->profile;
+    if (priv->profile == GST_VAAPI_PROFILE_VC1_SIMPLE)
+      profiles[n_profiles++] = GST_VAAPI_PROFILE_VC1_MAIN;
+
+    for (i = 0; i < n_profiles; i++) {
+      if (gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
+              profiles[i], entrypoint))
+        break;
+    }
+    if (i == n_profiles)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+    priv->profile = profiles[i];
+  }
+
+  if (priv->size_changed) {
+    GST_DEBUG ("size changed");
+    priv->size_changed = FALSE;
+    reset_context = TRUE;
+  }
+
+  if (reset_context) {
+    GstVaapiContextInfo info;
+
+    info.profile = priv->profile;
+    info.entrypoint = entrypoint;
+    info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+    info.width = priv->width;
+    info.height = priv->height;
+    info.ref_frames = 2;
+    reset_context =
+        gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info);
+    if (!reset_context)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_current_picture (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->current_picture;
+
+  if (!picture)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (!gst_vaapi_picture_decode (picture))
+    goto error;
+  if (GST_VAAPI_PICTURE_IS_COMPLETE (picture)) {
+    if (!gst_vaapi_dpb_add (priv->dpb, picture))
+      goto error;
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    /* XXX: fix for cases where first field failed to be decoded */
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+}
+
+static GstVaapiDecoderStatus
+decode_sequence (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu,
+    GstVC1BDU * ebdu)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr;
+  GstVC1AdvancedSeqHdr *const adv_hdr = &seq_hdr->advanced;
+  GstVC1SeqStructC *const structc = &seq_hdr->struct_c;
+  GstVC1ParserResult result;
+  GstVaapiProfile profile;
+  guint width, height, fps_n, fps_d, par_n, par_d;
+
+  result = gst_vc1_parse_sequence_header (rbdu->data + rbdu->offset,
+      rbdu->size, seq_hdr);
+  if (result != GST_VC1_PARSER_OK) {
+    GST_ERROR ("failed to parse sequence layer");
+    return get_status (result);
+  }
+
+  priv->has_entrypoint = FALSE;
+
+  /* Reset POC */
+  if (priv->last_non_b_picture) {
+    if (priv->last_non_b_picture->poc == priv->next_poc)
+      priv->next_poc++;
+    gst_vaapi_picture_replace (&priv->last_non_b_picture, NULL);
+  }
+
+  /* Validate profile */
+  switch (seq_hdr->profile) {
+    case GST_VC1_PROFILE_SIMPLE:
+    case GST_VC1_PROFILE_MAIN:
+    case GST_VC1_PROFILE_ADVANCED:
+      break;
+    default:
+      GST_ERROR ("unsupported profile %d", seq_hdr->profile);
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  fps_n = 0;
+  fps_d = 0;
+  par_n = 0;
+  par_d = 0;
+  switch (seq_hdr->profile) {
+    case GST_VC1_PROFILE_SIMPLE:
+    case GST_VC1_PROFILE_MAIN:
+      if (structc->wmvp) {
+        fps_n = structc->framerate;
+        fps_d = 1;
+      }
+      break;
+    case GST_VC1_PROFILE_ADVANCED:
+      fps_n = adv_hdr->fps_n;
+      fps_d = adv_hdr->fps_d;
+      par_n = adv_hdr->par_n;
+      par_d = adv_hdr->par_d;
+      break;
+    default:
+      g_assert (0 && "XXX: we already validated the profile above");
+      break;
+  }
+
+  if (fps_n && fps_d)
+    gst_vaapi_decoder_set_framerate (base_decoder, fps_n, fps_d);
+
+  if (par_n > 0 && par_d > 0)
+    gst_vaapi_decoder_set_pixel_aspect_ratio (base_decoder, par_n, par_d);
+
+  width = 0;
+  height = 0;
+  switch (seq_hdr->profile) {
+    case GST_VC1_PROFILE_SIMPLE:
+    case GST_VC1_PROFILE_MAIN:
+      width = seq_hdr->struct_c.coded_width;
+      height = seq_hdr->struct_c.coded_height;
+      break;
+    case GST_VC1_PROFILE_ADVANCED:
+      width = seq_hdr->advanced.max_coded_width;
+      height = seq_hdr->advanced.max_coded_height;
+      break;
+    default:
+      g_assert (0 && "XXX: we already validated the profile above");
+      break;
+  }
+
+  if (priv->width != width) {
+    priv->width = width;
+    priv->size_changed = TRUE;
+  }
+
+  if (priv->height != height) {
+    priv->height = height;
+    priv->size_changed = TRUE;
+  }
+
+  profile = GST_VAAPI_PROFILE_UNKNOWN;
+  switch (seq_hdr->profile) {
+    case GST_VC1_PROFILE_SIMPLE:
+      profile = GST_VAAPI_PROFILE_VC1_SIMPLE;
+      break;
+    case GST_VC1_PROFILE_MAIN:
+      profile = GST_VAAPI_PROFILE_VC1_MAIN;
+      break;
+    case GST_VC1_PROFILE_ADVANCED:
+      profile = GST_VAAPI_PROFILE_VC1_ADVANCED;
+      break;
+    default:
+      g_assert (0 && "XXX: we already validated the profile above");
+      break;
+  }
+  if (priv->profile != profile) {
+    priv->profile = profile;
+    priv->profile_changed = TRUE;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_sequence_end (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+
+  status = decode_current_picture (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  gst_vaapi_dpb_flush (priv->dpb);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_entry_point (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu,
+    GstVC1BDU * ebdu)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr;
+  GstVC1EntryPointHdr *const entrypoint_hdr = &priv->entrypoint_hdr;
+  GstVC1ParserResult result;
+
+  result = gst_vc1_parse_entry_point_header (rbdu->data + rbdu->offset,
+      rbdu->size, entrypoint_hdr, seq_hdr);
+  if (result != GST_VC1_PARSER_OK) {
+    GST_ERROR ("failed to parse entrypoint layer");
+    return get_status (result);
+  }
+
+  if (entrypoint_hdr->coded_size_flag) {
+    priv->width = entrypoint_hdr->coded_width;
+    priv->height = entrypoint_hdr->coded_height;
+    priv->size_changed = TRUE;
+  }
+
+  priv->has_entrypoint = TRUE;
+  priv->closed_entry = entrypoint_hdr->closed_entry;
+  priv->broken_link = entrypoint_hdr->broken_link;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+/* Reconstruct bitstream PTYPE (7.1.1.4, index into Table-35) */
+static guint
+get_PTYPE (guint ptype)
+{
+  switch (ptype) {
+    case GST_VC1_PICTURE_TYPE_I:
+      return 0;
+    case GST_VC1_PICTURE_TYPE_P:
+      return 1;
+    case GST_VC1_PICTURE_TYPE_B:
+      return 2;
+    case GST_VC1_PICTURE_TYPE_BI:
+      return 3;
+  }
+  return 4;                     /* skipped P-frame */
+}
+
+/* Reconstruct bitstream BFRACTION (7.1.1.14, index into Table-40) */
+static guint
+get_BFRACTION (guint bfraction)
+{
+  guint i;
+
+  static const struct
+  {
+    guint16 index;
+    guint16 value;
+  }
+  bfraction_map[] = {
+    {
+    0, GST_VC1_BFRACTION_BASIS / 2}, {
+    1, GST_VC1_BFRACTION_BASIS / 3}, {
+    2, (GST_VC1_BFRACTION_BASIS * 2) / 3}, {
+    3, GST_VC1_BFRACTION_BASIS / 4}, {
+    4, (GST_VC1_BFRACTION_BASIS * 3) / 4}, {
+    5, GST_VC1_BFRACTION_BASIS / 5}, {
+    6, (GST_VC1_BFRACTION_BASIS * 2) / 5}, {
+    7, (GST_VC1_BFRACTION_BASIS * 3) / 5}, {
+    8, (GST_VC1_BFRACTION_BASIS * 4) / 5}, {
+    9, GST_VC1_BFRACTION_BASIS / 6}, {
+    10, (GST_VC1_BFRACTION_BASIS * 5) / 6}, {
+    11, GST_VC1_BFRACTION_BASIS / 7}, {
+    12, (GST_VC1_BFRACTION_BASIS * 2) / 7}, {
+    13, (GST_VC1_BFRACTION_BASIS * 3) / 7}, {
+    14, (GST_VC1_BFRACTION_BASIS * 4) / 7}, {
+    15, (GST_VC1_BFRACTION_BASIS * 5) / 7}, {
+    16, (GST_VC1_BFRACTION_BASIS * 6) / 7}, {
+    17, GST_VC1_BFRACTION_BASIS / 8}, {
+    18, (GST_VC1_BFRACTION_BASIS * 3) / 8}, {
+    19, (GST_VC1_BFRACTION_BASIS * 5) / 8}, {
+    20, (GST_VC1_BFRACTION_BASIS * 7) / 8}, {
+    21, GST_VC1_BFRACTION_RESERVED}, {
+    22, GST_VC1_BFRACTION_PTYPE_BI}
+  };
+
+  if (!bfraction)
+    return 0;
+
+  for (i = 0; i < G_N_ELEMENTS (bfraction_map); i++) {
+    if (bfraction_map[i].value == bfraction)
+      return bfraction_map[i].index;
+  }
+  return 21;                    /* RESERVED */
+}
+
+/* Translate GStreamer MV modes to VA-API */
+static guint
+get_VAMvModeVC1 (guint mvmode)
+{
+  switch (mvmode) {
+    case GST_VC1_MVMODE_1MV_HPEL_BILINEAR:
+      return VAMvMode1MvHalfPelBilinear;
+    case GST_VC1_MVMODE_1MV:
+      return VAMvMode1Mv;
+    case GST_VC1_MVMODE_1MV_HPEL:
+      return VAMvMode1MvHalfPel;
+    case GST_VC1_MVMODE_MIXED_MV:
+      return VAMvModeMixedMv;
+    case GST_VC1_MVMODE_INTENSITY_COMP:
+      return VAMvModeIntensityCompensation;
+  }
+  return 0;
+}
+
+/* Reconstruct bitstream MVMODE (7.1.1.32) */
+static guint
+get_MVMODE (GstVC1FrameHdr * frame_hdr)
+{
+  guint mvmode;
+
+  if (frame_hdr->profile == GST_VC1_PROFILE_ADVANCED)
+    mvmode = frame_hdr->pic.advanced.mvmode;
+  else
+    mvmode = frame_hdr->pic.simple.mvmode;
+
+  if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P ||
+      frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B)
+    return get_VAMvModeVC1 (mvmode);
+  return 0;
+}
+
+/* Reconstruct bitstream MVMODE2 (7.1.1.33) */
+static guint
+get_MVMODE2 (GstVC1FrameHdr * frame_hdr)
+{
+  guint mvmode, mvmode2;
+
+  if (frame_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
+    mvmode = frame_hdr->pic.advanced.mvmode;
+    mvmode2 = frame_hdr->pic.advanced.mvmode2;
+  } else {
+    mvmode = frame_hdr->pic.simple.mvmode;
+    mvmode2 = frame_hdr->pic.simple.mvmode2;
+  }
+
+  if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P &&
+      mvmode == GST_VC1_MVMODE_INTENSITY_COMP)
+    return get_VAMvModeVC1 (mvmode2);
+  return 0;
+}
+
+static inline int
+has_MVTYPEMB_bitplane (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr;
+  GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr;
+  guint mvmode, mvmode2;
+
+  if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
+    GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced;
+    if (pic->mvtypemb)
+      return 0;
+    mvmode = pic->mvmode;
+    mvmode2 = pic->mvmode2;
+  } else {
+    GstVC1PicSimpleMain *const pic = &frame_hdr->pic.simple;
+    if (pic->mvtypemb)
+      return 0;
+    mvmode = pic->mvmode;
+    mvmode2 = pic->mvmode2;
+  }
+  return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P &&
+      (mvmode == GST_VC1_MVMODE_MIXED_MV ||
+          (mvmode == GST_VC1_MVMODE_INTENSITY_COMP &&
+              mvmode2 == GST_VC1_MVMODE_MIXED_MV)));
+}
+
+static inline int
+has_SKIPMB_bitplane (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr;
+  GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr;
+
+  if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
+    GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced;
+    if (pic->skipmb)
+      return 0;
+  } else {
+    GstVC1PicSimpleMain *const pic = &frame_hdr->pic.simple;
+    if (pic->skipmb)
+      return 0;
+  }
+  return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P ||
+      frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B);
+}
+
+static inline int
+has_DIRECTMB_bitplane (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr;
+  GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr;
+
+  if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
+    GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced;
+    if (pic->directmb)
+      return 0;
+  } else {
+    GstVC1PicSimpleMain *const pic = &frame_hdr->pic.simple;
+    if (pic->directmb)
+      return 0;
+  }
+  return frame_hdr->ptype == GST_VC1_PICTURE_TYPE_B;
+}
+
+static inline int
+has_ACPRED_bitplane (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr;
+  GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced;
+
+  if (seq_hdr->profile != GST_VC1_PROFILE_ADVANCED)
+    return 0;
+  if (pic->acpred)
+    return 0;
+  return (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I ||
+      frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI);
+}
+
+static inline int
+has_OVERFLAGS_bitplane (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr;
+  GstVC1EntryPointHdr *const entrypoint_hdr = &priv->entrypoint_hdr;
+  GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced;
+
+  if (seq_hdr->profile != GST_VC1_PROFILE_ADVANCED)
+    return 0;
+  if (pic->overflags)
+    return 0;
+  return ((frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I ||
+          frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI) &&
+      (entrypoint_hdr->overlap && frame_hdr->pquant <= 8) &&
+      pic->condover == GST_VC1_CONDOVER_SELECT);
+}
+
+static inline void
+pack_bitplanes (GstVaapiBitPlane * bitplane, guint n,
+    const guint8 * bitplanes[3], guint x, guint y, guint stride)
+{
+  const guint dst_index = n / 2;
+  const guint src_index = y * stride + x;
+  guint8 v = 0;
+
+  if (bitplanes[0])
+    v |= bitplanes[0][src_index];
+  if (bitplanes[1])
+    v |= bitplanes[1][src_index] << 1;
+  if (bitplanes[2])
+    v |= bitplanes[2][src_index] << 2;
+  bitplane->data[dst_index] = (bitplane->data[dst_index] << 4) | v;
+}
+
+static gboolean
+fill_picture_structc (GstVaapiDecoderVC1 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  VAPictureParameterBufferVC1 *const pic_param = picture->param;
+  GstVC1SeqStructC *const structc = &priv->seq_hdr.struct_c;
+  GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVC1PicSimpleMain *const pic = &frame_hdr->pic.simple;
+
+  /* Fill in VAPictureParameterBufferVC1 (simple/main profile bits) */
+  pic_param->sequence_fields.bits.finterpflag = structc->finterpflag;
+  pic_param->sequence_fields.bits.multires = structc->multires;
+  pic_param->sequence_fields.bits.overlap = structc->overlap;
+  pic_param->sequence_fields.bits.syncmarker = structc->syncmarker;
+  pic_param->sequence_fields.bits.rangered = structc->rangered;
+  pic_param->sequence_fields.bits.max_b_frames = structc->maxbframes;
+  pic_param->conditional_overlap_flag = 0;      /* advanced profile only */
+  pic_param->fast_uvmc_flag = structc->fastuvmc;
+  pic_param->b_picture_fraction = get_BFRACTION (pic->bfraction);
+  pic_param->cbp_table = pic->cbptab;
+  pic_param->mb_mode_table = 0; /* XXX: interlaced frame */
+  pic_param->range_reduction_frame = pic->rangeredfrm;
+  pic_param->post_processing = 0;       /* advanced profile only */
+  pic_param->picture_resolution_index = pic->respic;
+  pic_param->luma_scale = pic->lumscale;
+  pic_param->luma_shift = pic->lumshift;
+  pic_param->raw_coding.flags.mv_type_mb = pic->mvtypemb;
+  pic_param->raw_coding.flags.direct_mb = pic->directmb;
+  pic_param->raw_coding.flags.skip_mb = pic->skipmb;
+  pic_param->bitplane_present.flags.bp_mv_type_mb =
+      has_MVTYPEMB_bitplane (decoder);
+  pic_param->bitplane_present.flags.bp_direct_mb =
+      has_DIRECTMB_bitplane (decoder);
+  pic_param->bitplane_present.flags.bp_skip_mb = has_SKIPMB_bitplane (decoder);
+  pic_param->mv_fields.bits.mv_table = pic->mvtab;
+  pic_param->mv_fields.bits.extended_mv_flag = structc->extended_mv;
+  pic_param->mv_fields.bits.extended_mv_range = pic->mvrange;
+  pic_param->transform_fields.bits.variable_sized_transform_flag =
+      structc->vstransform;
+  pic_param->transform_fields.bits.mb_level_transform_type_flag = pic->ttmbf;
+  pic_param->transform_fields.bits.frame_level_transform_type = pic->ttfrm;
+  pic_param->transform_fields.bits.transform_ac_codingset_idx2 =
+      pic->transacfrm2;
+
+  /* Refer to 8.3.7 Rounding control for Simple and Main Profile  */
+  if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_I ||
+      frame_hdr->ptype == GST_VC1_PICTURE_TYPE_BI)
+    priv->rndctrl = 1;
+  else if (frame_hdr->ptype == GST_VC1_PICTURE_TYPE_P)
+    priv->rndctrl ^= 1;
+
+  pic_param->rounding_control = priv->rndctrl;
+
+  return TRUE;
+}
+
+static gboolean
+fill_picture_advanced (GstVaapiDecoderVC1 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  VAPictureParameterBufferVC1 *const pic_param = picture->param;
+  GstVC1AdvancedSeqHdr *const adv_hdr = &priv->seq_hdr.advanced;
+  GstVC1EntryPointHdr *const entrypoint_hdr = &priv->entrypoint_hdr;
+  GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVC1PicAdvanced *const pic = &frame_hdr->pic.advanced;
+
+  if (!priv->has_entrypoint)
+    return FALSE;
+
+  /* Fill in VAPictureParameterBufferVC1 (advanced profile bits) */
+  pic_param->sequence_fields.bits.pulldown = adv_hdr->pulldown;
+  pic_param->sequence_fields.bits.interlace = adv_hdr->interlace;
+  pic_param->sequence_fields.bits.tfcntrflag = adv_hdr->tfcntrflag;
+  pic_param->sequence_fields.bits.finterpflag = adv_hdr->finterpflag;
+  pic_param->sequence_fields.bits.psf = adv_hdr->psf;
+  pic_param->sequence_fields.bits.overlap = entrypoint_hdr->overlap;
+  pic_param->entrypoint_fields.bits.broken_link = entrypoint_hdr->broken_link;
+  pic_param->entrypoint_fields.bits.closed_entry = entrypoint_hdr->closed_entry;
+  pic_param->entrypoint_fields.bits.panscan_flag = entrypoint_hdr->panscan_flag;
+  pic_param->entrypoint_fields.bits.loopfilter = entrypoint_hdr->loopfilter;
+  pic_param->conditional_overlap_flag = pic->condover;
+  pic_param->fast_uvmc_flag = entrypoint_hdr->fastuvmc;
+  pic_param->range_mapping_fields.bits.luma_flag =
+      entrypoint_hdr->range_mapy_flag;
+  pic_param->range_mapping_fields.bits.luma = entrypoint_hdr->range_mapy;
+  pic_param->range_mapping_fields.bits.chroma_flag =
+      entrypoint_hdr->range_mapuv_flag;
+  pic_param->range_mapping_fields.bits.chroma = entrypoint_hdr->range_mapuv;
+  pic_param->b_picture_fraction = get_BFRACTION (pic->bfraction);
+  pic_param->cbp_table = pic->cbptab;
+  pic_param->mb_mode_table = 0; /* XXX: interlaced frame */
+  pic_param->range_reduction_frame = 0; /* simple/main profile only */
+  pic_param->rounding_control = pic->rndctrl;
+  pic_param->post_processing = pic->postproc;
+  pic_param->picture_resolution_index = 0;      /* simple/main profile only */
+  pic_param->luma_scale = pic->lumscale;
+  pic_param->luma_shift = pic->lumshift;
+  pic_param->picture_fields.bits.frame_coding_mode = pic->fcm;
+  pic_param->picture_fields.bits.top_field_first = pic->tff;
+  pic_param->picture_fields.bits.is_first_field = pic->fcm == 0;        /* XXX: interlaced frame */
+  pic_param->picture_fields.bits.intensity_compensation =
+      pic->mvmode == GST_VC1_MVMODE_INTENSITY_COMP;
+  pic_param->raw_coding.flags.mv_type_mb = pic->mvtypemb;
+  pic_param->raw_coding.flags.direct_mb = pic->directmb;
+  pic_param->raw_coding.flags.skip_mb = pic->skipmb;
+  pic_param->raw_coding.flags.ac_pred = pic->acpred;
+  pic_param->raw_coding.flags.overflags = pic->overflags;
+  pic_param->bitplane_present.flags.bp_mv_type_mb =
+      has_MVTYPEMB_bitplane (decoder);
+  pic_param->bitplane_present.flags.bp_direct_mb =
+      has_DIRECTMB_bitplane (decoder);
+  pic_param->bitplane_present.flags.bp_skip_mb = has_SKIPMB_bitplane (decoder);
+  pic_param->bitplane_present.flags.bp_ac_pred = has_ACPRED_bitplane (decoder);
+  pic_param->bitplane_present.flags.bp_overflags =
+      has_OVERFLAGS_bitplane (decoder);
+  pic_param->reference_fields.bits.reference_distance_flag =
+      entrypoint_hdr->refdist_flag;
+  pic_param->mv_fields.bits.mv_table = pic->mvtab;
+  pic_param->mv_fields.bits.extended_mv_flag = entrypoint_hdr->extended_mv;
+  pic_param->mv_fields.bits.extended_mv_range = pic->mvrange;
+  pic_param->mv_fields.bits.extended_dmv_flag = entrypoint_hdr->extended_dmv;
+  pic_param->pic_quantizer_fields.bits.dquant = entrypoint_hdr->dquant;
+  pic_param->pic_quantizer_fields.bits.quantizer = entrypoint_hdr->quantizer;
+  pic_param->transform_fields.bits.variable_sized_transform_flag =
+      entrypoint_hdr->vstransform;
+  pic_param->transform_fields.bits.mb_level_transform_type_flag = pic->ttmbf;
+  pic_param->transform_fields.bits.frame_level_transform_type = pic->ttfrm;
+  pic_param->transform_fields.bits.transform_ac_codingset_idx2 =
+      pic->transacfrm2;
+  return TRUE;
+}
+
+static gboolean
+fill_picture (GstVaapiDecoderVC1 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  VAPictureParameterBufferVC1 *const pic_param = picture->param;
+  GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr;
+  GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVC1VopDquant *const vopdquant = &frame_hdr->vopdquant;
+  GstVaapiPicture *prev_picture, *next_picture;
+
+  /* Fill in VAPictureParameterBufferVC1 (common fields) */
+  pic_param->forward_reference_picture = VA_INVALID_ID;
+  pic_param->backward_reference_picture = VA_INVALID_ID;
+  pic_param->inloop_decoded_picture = VA_INVALID_ID;
+  pic_param->sequence_fields.value = 0;
+  pic_param->sequence_fields.bits.profile = seq_hdr->profile;
+  pic_param->coded_width = priv->width;
+  pic_param->coded_height = priv->height;
+  pic_param->entrypoint_fields.value = 0;
+  pic_param->range_mapping_fields.value = 0;
+  pic_param->picture_fields.value = 0;
+  pic_param->picture_fields.bits.picture_type = get_PTYPE (frame_hdr->ptype);
+  pic_param->raw_coding.value = 0;
+  pic_param->bitplane_present.value = 0;
+  pic_param->reference_fields.value = 0;
+  pic_param->mv_fields.value = 0;
+  pic_param->mv_fields.bits.mv_mode = get_MVMODE (frame_hdr);
+  pic_param->mv_fields.bits.mv_mode2 = get_MVMODE2 (frame_hdr);
+  pic_param->pic_quantizer_fields.value = 0;
+  pic_param->pic_quantizer_fields.bits.half_qp = frame_hdr->halfqp;
+  pic_param->pic_quantizer_fields.bits.pic_quantizer_scale = frame_hdr->pquant;
+  pic_param->pic_quantizer_fields.bits.pic_quantizer_type =
+      frame_hdr->pquantizer;
+  pic_param->pic_quantizer_fields.bits.dq_frame = vopdquant->dquantfrm;
+  pic_param->pic_quantizer_fields.bits.dq_profile = vopdquant->dqprofile;
+  pic_param->pic_quantizer_fields.bits.dq_sb_edge =
+      vopdquant->dqprofile ==
+      GST_VC1_DQPROFILE_SINGLE_EDGE ? vopdquant->dqbedge : 0;
+  pic_param->pic_quantizer_fields.bits.dq_db_edge =
+      vopdquant->dqprofile ==
+      GST_VC1_DQPROFILE_DOUBLE_EDGES ? vopdquant->dqbedge : 0;
+  pic_param->pic_quantizer_fields.bits.dq_binary_level = vopdquant->dqbilevel;
+  pic_param->pic_quantizer_fields.bits.alt_pic_quantizer = vopdquant->altpquant;
+  pic_param->transform_fields.value = 0;
+  pic_param->transform_fields.bits.transform_ac_codingset_idx1 =
+      frame_hdr->transacfrm;
+  pic_param->transform_fields.bits.intra_transform_dc_table =
+      frame_hdr->transdctab;
+
+  if (seq_hdr->profile == GST_VC1_PROFILE_ADVANCED) {
+    if (!fill_picture_advanced (decoder, picture))
+      return FALSE;
+  } else {
+    if (!fill_picture_structc (decoder, picture))
+      return FALSE;
+  }
+
+  gst_vaapi_dpb_get_neighbours (priv->dpb, picture,
+      &prev_picture, &next_picture);
+
+  switch (picture->type) {
+    case GST_VAAPI_PICTURE_TYPE_B:
+      if (next_picture)
+        pic_param->backward_reference_picture = next_picture->surface_id;
+      if (prev_picture)
+        pic_param->forward_reference_picture = prev_picture->surface_id;
+      else if (!priv->closed_entry)
+        GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
+      break;
+    case GST_VAAPI_PICTURE_TYPE_P:
+      if (prev_picture)
+        pic_param->forward_reference_picture = prev_picture->surface_id;
+      break;
+    default:
+      break;
+  }
+
+  if (pic_param->bitplane_present.value) {
+    const guint8 *bitplanes[3];
+    guint x, y, n;
+
+    switch (picture->type) {
+      case GST_VAAPI_PICTURE_TYPE_P:
+        bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb ?
+            priv->bitplanes->directmb : NULL;
+        bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb ?
+            priv->bitplanes->skipmb : NULL;
+        bitplanes[2] = pic_param->bitplane_present.flags.bp_mv_type_mb ?
+            priv->bitplanes->mvtypemb : NULL;
+        break;
+      case GST_VAAPI_PICTURE_TYPE_B:
+        bitplanes[0] = pic_param->bitplane_present.flags.bp_direct_mb ?
+            priv->bitplanes->directmb : NULL;
+        bitplanes[1] = pic_param->bitplane_present.flags.bp_skip_mb ?
+            priv->bitplanes->skipmb : NULL;
+        bitplanes[2] = NULL;    /* XXX: interlaced frame (FORWARD plane) */
+        break;
+      case GST_VAAPI_PICTURE_TYPE_BI:
+      case GST_VAAPI_PICTURE_TYPE_I:
+        bitplanes[0] = NULL;    /* XXX: interlaced frame (FIELDTX plane) */
+        bitplanes[1] = pic_param->bitplane_present.flags.bp_ac_pred ?
+            priv->bitplanes->acpred : NULL;
+        bitplanes[2] = pic_param->bitplane_present.flags.bp_overflags ?
+            priv->bitplanes->overflags : NULL;
+        break;
+      default:
+        bitplanes[0] = NULL;
+        bitplanes[1] = NULL;
+        bitplanes[2] = NULL;
+        break;
+    }
+
+    picture->bitplane = GST_VAAPI_BITPLANE_NEW (decoder,
+        (seq_hdr->mb_width * seq_hdr->mb_height + 1) / 2);
+    if (!picture->bitplane)
+      return FALSE;
+
+    n = 0;
+    for (y = 0; y < seq_hdr->mb_height; y++)
+      for (x = 0; x < seq_hdr->mb_width; x++, n++)
+        pack_bitplanes (picture->bitplane, n, bitplanes, x, y,
+            seq_hdr->mb_stride);
+    if (n & 1)                  /* move last nibble to the high order */
+      picture->bitplane->data[n / 2] <<= 4;
+  }
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_slice_chunk (GstVaapiDecoderVC1 * decoder, GstVC1BDU * ebdu,
+    guint slice_addr, guint header_size)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->current_picture;
+  GstVaapiSlice *slice;
+  VASliceParameterBufferVC1 *slice_param;
+
+  slice = GST_VAAPI_SLICE_NEW (VC1, decoder,
+      ebdu->data + ebdu->sc_offset,
+      ebdu->size + ebdu->offset - ebdu->sc_offset);
+  if (!slice) {
+    GST_ERROR ("failed to allocate slice");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  gst_vaapi_picture_add_slice (picture, slice);
+
+  /* Fill in VASliceParameterBufferVC1 */
+  slice_param = slice->param;
+  slice_param->macroblock_offset = 8 * (ebdu->offset - ebdu->sc_offset) +
+      header_size;
+  slice_param->slice_vertical_position = slice_addr;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_frame (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu, GstVC1BDU * ebdu)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVC1ParserResult result;
+  GstVaapiPicture *const picture = priv->current_picture;
+
+  memset (frame_hdr, 0, sizeof (*frame_hdr));
+  result = gst_vc1_parse_frame_header (rbdu->data + rbdu->offset,
+      rbdu->size, frame_hdr, &priv->seq_hdr, priv->bitplanes);
+  if (result != GST_VC1_PARSER_OK) {
+    GST_ERROR ("failed to parse frame layer");
+    return get_status (result);
+  }
+
+  /* @FIXME: intel-driver cannot handle interlaced frames */
+  if (priv->profile == GST_VAAPI_PROFILE_VC1_ADVANCED
+      && frame_hdr->pic.advanced.fcm != GST_VC1_FRAME_PROGRESSIVE) {
+    GST_ERROR ("interlaced video not supported");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  switch (frame_hdr->ptype) {
+    case GST_VC1_PICTURE_TYPE_I:
+      picture->type = GST_VAAPI_PICTURE_TYPE_I;
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
+      break;
+    case GST_VC1_PICTURE_TYPE_SKIPPED:
+    case GST_VC1_PICTURE_TYPE_P:
+      picture->type = GST_VAAPI_PICTURE_TYPE_P;
+      GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_REFERENCE);
+      break;
+    case GST_VC1_PICTURE_TYPE_B:
+      picture->type = GST_VAAPI_PICTURE_TYPE_B;
+      break;
+    case GST_VC1_PICTURE_TYPE_BI:
+      picture->type = GST_VAAPI_PICTURE_TYPE_BI;
+      break;
+    default:
+      GST_ERROR ("unsupported picture type %d", frame_hdr->ptype);
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  /* Update presentation time */
+  if (GST_VAAPI_PICTURE_IS_REFERENCE (picture)) {
+    picture->poc = priv->last_non_b_picture ?
+        (priv->last_non_b_picture->poc + 1) : priv->next_poc;
+    priv->next_poc = picture->poc + 1;
+    gst_vaapi_picture_replace (&priv->last_non_b_picture, picture);
+  } else if (!priv->last_non_b_picture)
+    picture->poc = priv->next_poc++;
+  else {                        /* B or BI */
+    picture->poc = priv->last_non_b_picture->poc++;
+    priv->next_poc = priv->last_non_b_picture->poc + 1;
+  }
+  picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
+
+  if (!fill_picture (decoder, picture))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  return decode_slice_chunk (decoder, ebdu, 0, frame_hdr->header_size);
+}
+
+static GstVaapiDecoderStatus
+decode_slice (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu, GstVC1BDU * ebdu)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1SliceHdr slice_hdr;
+  GstVC1ParserResult result;
+
+  memset (&slice_hdr, 0, sizeof (slice_hdr));
+  result = gst_vc1_parse_slice_header (rbdu->data + rbdu->offset,
+      rbdu->size, &slice_hdr, &priv->seq_hdr);
+  if (result != GST_VC1_PARSER_OK) {
+    GST_ERROR ("failed to parse slice layer");
+    return get_status (result);
+  }
+  return decode_slice_chunk (decoder, ebdu, slice_hdr.slice_addr,
+      slice_hdr.header_size);
+}
+
+static gboolean
+decode_rbdu (GstVaapiDecoderVC1 * decoder, GstVC1BDU * rbdu, GstVC1BDU * ebdu)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  guint8 *rbdu_buffer;
+  guint i, j, rbdu_buffer_size;
+
+  /* BDU are encapsulated in advanced profile mode only */
+  if (priv->profile != GST_VAAPI_PROFILE_VC1_ADVANCED) {
+    memcpy (rbdu, ebdu, sizeof (*rbdu));
+    return TRUE;
+  }
+
+  /* Reallocate unescaped bitstream buffer */
+  rbdu_buffer = priv->rbdu_buffer;
+  if (!rbdu_buffer || ebdu->size > priv->rbdu_buffer_size) {
+    rbdu_buffer = g_realloc (priv->rbdu_buffer, ebdu->size);
+    if (!rbdu_buffer)
+      return FALSE;
+    priv->rbdu_buffer = rbdu_buffer;
+    priv->rbdu_buffer_size = ebdu->size;
+  }
+
+  /* Unescape bitstream buffer */
+  if (ebdu->size < 4) {
+    memcpy (rbdu_buffer, ebdu->data + ebdu->offset, ebdu->size);
+    rbdu_buffer_size = ebdu->size;
+  } else {
+    guint8 *const bdu_buffer = ebdu->data + ebdu->offset;
+    for (i = 0, j = 0; i < ebdu->size; i++) {
+      if (i >= 2 && i < ebdu->size - 1 &&
+          bdu_buffer[i - 1] == 0x00 &&
+          bdu_buffer[i - 2] == 0x00 &&
+          bdu_buffer[i] == 0x03 && bdu_buffer[i + 1] <= 0x03)
+        i++;
+      rbdu_buffer[j++] = bdu_buffer[i];
+    }
+    rbdu_buffer_size = j;
+  }
+
+  /* Reconstruct RBDU */
+  rbdu->type = ebdu->type;
+  rbdu->size = rbdu_buffer_size;
+  rbdu->sc_offset = 0;
+  rbdu->offset = 0;
+  rbdu->data = rbdu_buffer;
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_ebdu (GstVaapiDecoderVC1 * decoder, GstVC1BDU * ebdu)
+{
+  GstVaapiDecoderStatus status;
+  GstVC1BDU rbdu;
+
+  if (!decode_rbdu (decoder, &rbdu, ebdu))
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+
+  switch (ebdu->type) {
+    case GST_VC1_SEQUENCE:
+      status = decode_sequence (decoder, &rbdu, ebdu);
+      break;
+    case GST_VC1_ENTRYPOINT:
+      status = decode_entry_point (decoder, &rbdu, ebdu);
+      break;
+    case GST_VC1_FRAME:
+      status = decode_frame (decoder, &rbdu, ebdu);
+      break;
+    case GST_VC1_SLICE:
+      status = decode_slice (decoder, &rbdu, ebdu);
+      break;
+    case GST_VC1_END_OF_SEQ:
+      status = decode_sequence_end (decoder);
+      break;
+    case GST_VC1_FIELD_USER:
+    case GST_VC1_FRAME_USER:
+    case GST_VC1_ENTRY_POINT_USER:
+    case GST_VC1_SEQUENCE_USER:
+      /* Let's just ignore them */
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+    default:
+      GST_WARNING ("unsupported BDU type %d", ebdu->type);
+      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+      break;
+  }
+  return status;
+}
+
+static GstVaapiDecoderStatus
+decode_buffer (GstVaapiDecoderVC1 * decoder, guchar * buf, guint buf_size)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1BDU ebdu;
+
+  if (priv->has_codec_data) {
+    ebdu.type = GST_VC1_FRAME;
+    ebdu.sc_offset = 0;
+    ebdu.offset = 0;
+  } else {
+    ebdu.type = buf[3];
+    ebdu.sc_offset = 0;
+    ebdu.offset = 4;
+  }
+  ebdu.data = buf;
+  ebdu.size = buf_size - ebdu.offset;
+  return decode_ebdu (decoder, &ebdu);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vc1_decode_codec_data (GstVaapiDecoder * base_decoder,
+    const guchar * buf, guint buf_size)
+{
+  GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder);
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVC1SeqHdr *const seq_hdr = &priv->seq_hdr;
+  GstVaapiDecoderStatus status;
+  GstVC1ParserResult result;
+  GstVC1BDU ebdu;
+  GstCaps *caps;
+  GstStructure *structure;
+  guint ofs;
+  gint width, height;
+  guint32 format;
+  gint version;
+  const gchar *s;
+
+  priv->has_codec_data = TRUE;
+
+  width = GST_VAAPI_DECODER_WIDTH (decoder);
+  height = GST_VAAPI_DECODER_HEIGHT (decoder);
+  if (!width || !height) {
+    GST_ERROR ("failed to parse size from codec-data");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  caps = GST_VAAPI_DECODER_CODEC_STATE (decoder)->caps;
+  structure = gst_caps_get_structure (caps, 0);
+  s = gst_structure_get_string (structure, "format");
+  if (s && strlen (s) == 4) {
+    format = GST_MAKE_FOURCC (s[0], s[1], s[2], s[3]);
+  } else {
+    /* Try to determine format from "wmvversion" property */
+    if (gst_structure_get_int (structure, "wmvversion", &version))
+      format = (version >= 1 && version <= 3) ?
+          GST_MAKE_FOURCC ('W', 'M', 'V', ('0' + version)) : 0;
+    else
+      format = 0;
+  }
+  if (!format) {
+    GST_ERROR ("failed to parse profile from codec-data");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
+  }
+
+  /* WMV3 -- expecting sequence header */
+  if (format == GST_MAKE_FOURCC ('W', 'M', 'V', '3')) {
+    seq_hdr->struct_c.coded_width = width;
+    seq_hdr->struct_c.coded_height = height;
+    ebdu.type = GST_VC1_SEQUENCE;
+    ebdu.size = buf_size;
+    ebdu.sc_offset = 0;
+    ebdu.offset = 0;
+    ebdu.data = (guint8 *) buf;
+    return decode_ebdu (decoder, &ebdu);
+  }
+
+  /* WVC1 -- expecting bitstream data units */
+  if (format != GST_MAKE_FOURCC ('W', 'V', 'C', '1'))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  seq_hdr->advanced.max_coded_width = width;
+  seq_hdr->advanced.max_coded_height = height;
+
+  ofs = 0;
+  do {
+    result = gst_vc1_identify_next_bdu (buf + ofs, buf_size - ofs, &ebdu);
+
+    switch (result) {
+      case GST_VC1_PARSER_NO_BDU_END:
+        /* Assume the EBDU is complete within codec-data bounds */
+        ebdu.size = buf_size - ofs - ebdu.offset;
+        // fall-through
+      case GST_VC1_PARSER_OK:
+        status = decode_ebdu (decoder, &ebdu);
+        ofs += ebdu.offset + ebdu.size;
+        break;
+      default:
+        status = get_status (result);
+        break;
+    }
+  } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS && ofs < buf_size);
+  return status;
+}
+
+static GstVaapiDecoderStatus
+ensure_decoder (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+
+  if (!priv->is_opened) {
+    priv->is_opened = gst_vaapi_decoder_vc1_open (decoder);
+    if (!priv->is_opened)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC;
+
+    status =
+        gst_vaapi_decoder_decode_codec_data (GST_VAAPI_DECODER_CAST (decoder));
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      return status;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static inline gint
+scan_for_start_code (GstAdapter * adapter, guint ofs, guint size, guint32 * scp)
+{
+  return (gint) gst_adapter_masked_scan_uint32_peek (adapter,
+      0xffffff00, 0x00000100, ofs, size, scp);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vc1_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder);
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+  guint8 bdu_type;
+  guint size, buf_size, flags = 0;
+  gint ofs;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  size = gst_adapter_available (adapter);
+
+  if (priv->has_codec_data) {
+    // Assume demuxer sends out plain frames
+    if (size < 1)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    buf_size = size;
+    bdu_type = GST_VC1_FRAME;
+  } else {
+    if (size < 4)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+    ofs = scan_for_start_code (adapter, 0, size, NULL);
+    if (ofs < 0)
+      return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+    gst_adapter_flush (adapter, ofs);
+    size -= ofs;
+
+    ofs = G_UNLIKELY (size < 8) ? -1 :
+        scan_for_start_code (adapter, 4, size - 4, NULL);
+    if (ofs < 0) {
+      // Assume the whole packet is present if end-of-stream
+      if (!at_eos)
+        return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+      ofs = size;
+    }
+    buf_size = ofs;
+    gst_adapter_copy (adapter, &bdu_type, 3, 1);
+  }
+
+  unit->size = buf_size;
+
+  /* Check for new picture layer */
+  switch (bdu_type) {
+    case GST_VC1_END_OF_SEQ:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_STREAM_END;
+      break;
+    case GST_VC1_SEQUENCE:
+    case GST_VC1_ENTRYPOINT:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      break;
+    case GST_VC1_FRAME:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      break;
+    case GST_VC1_SLICE:
+      flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+      break;
+    case GST_VC1_FIELD:
+      /* @FIXME: intel-driver cannot handle interlaced frames */
+      GST_ERROR ("interlaced video not supported");
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vc1_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder);
+  GstVaapiDecoderStatus status;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  status = decode_buffer (decoder, map_info.data + unit->offset, unit->size);
+  gst_buffer_unmap (buffer, &map_info);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vc1_start_frame (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder);
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+  GstVaapiPicture *picture;
+
+  status = ensure_context (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    GST_ERROR ("failed to reset context");
+    return status;
+  }
+  status = ensure_decoder (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  picture = GST_VAAPI_PICTURE_NEW (VC1, decoder);
+  if (!picture) {
+    GST_ERROR ("failed to allocate picture");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  gst_vaapi_picture_replace (&priv->current_picture, picture);
+  gst_vaapi_picture_unref (picture);
+
+  /* Update cropping rectangle */
+  do {
+    GstVC1AdvancedSeqHdr *adv_hdr;
+    GstVaapiRectangle crop_rect;
+
+    if (priv->profile != GST_VAAPI_PROFILE_VC1_ADVANCED)
+      break;
+
+    adv_hdr = &priv->seq_hdr.advanced;
+    if (!adv_hdr->display_ext)
+      break;
+
+    crop_rect.x = 0;
+    crop_rect.y = 0;
+    crop_rect.width = adv_hdr->disp_horiz_size;
+    crop_rect.height = adv_hdr->disp_vert_size;
+    if (crop_rect.width <= priv->width && crop_rect.height <= priv->height)
+      gst_vaapi_picture_set_crop_rect (picture, &crop_rect);
+  } while (0);
+
+  if (!gst_vc1_bitplanes_ensure_size (priv->bitplanes, &priv->seq_hdr)) {
+    GST_ERROR ("failed to allocate bitplanes");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vc1_end_frame (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder);
+
+  return decode_current_picture (decoder);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vc1_flush (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVC1 *const decoder = GST_VAAPI_DECODER_VC1_CAST (base_decoder);
+  GstVaapiDecoderVC1Private *const priv = &decoder->priv;
+
+  if (priv->is_opened)
+    gst_vaapi_dpb_flush (priv->dpb);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+gst_vaapi_decoder_vc1_finalize (GObject * object)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
+
+  gst_vaapi_decoder_vc1_destroy (base_decoder);
+  G_OBJECT_CLASS (gst_vaapi_decoder_vc1_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_vc1_class_init (GstVaapiDecoderVC1Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_decoder_vc1_finalize;
+
+  decoder_class->reset = gst_vaapi_decoder_vc1_reset;
+  decoder_class->parse = gst_vaapi_decoder_vc1_parse;
+  decoder_class->decode = gst_vaapi_decoder_vc1_decode;
+  decoder_class->start_frame = gst_vaapi_decoder_vc1_start_frame;
+  decoder_class->end_frame = gst_vaapi_decoder_vc1_end_frame;
+  decoder_class->flush = gst_vaapi_decoder_vc1_flush;
+
+  decoder_class->decode_codec_data = gst_vaapi_decoder_vc1_decode_codec_data;
+}
+
+static void
+gst_vaapi_decoder_vc1_init (GstVaapiDecoderVC1 * decoder)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+
+  gst_vaapi_decoder_vc1_create (base_decoder);
+}
+
+/**
+ * gst_vaapi_decoder_vc1_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for VC-1 decoding.  The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_vc1_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return g_object_new (GST_TYPE_VAAPI_DECODER_VC1, "display", display,
+      "caps", caps, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vc1.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vc1.h
new file mode 100644 (file)
index 0000000..034681f
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  gstvaapidecoder_vc1.h - VC-1 decoder
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_VC1_H
+#define GST_VAAPI_DECODER_VC1_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER_VC1 \
+    (gst_vaapi_decoder_vc1_get_type ())
+#define GST_VAAPI_DECODER_VC1(decoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_VC1, GstVaapiDecoderVC1))
+#define GST_VAAPI_IS_DECODER_VC1(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_VC1))
+
+typedef struct _GstVaapiDecoderVC1              GstVaapiDecoderVC1;
+
+GType
+gst_vaapi_decoder_vc1_get_type (void) G_GNUC_CONST;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_vc1_new (GstVaapiDisplay *display, GstCaps *caps);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderVC1, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_VC1_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp8.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp8.c
new file mode 100644 (file)
index 0000000..b61a0a9
--- /dev/null
@@ -0,0 +1,677 @@
+/*
+ *  gstvaapidecoder_vp8.c - VP8 decoder
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Halley Zhao <halley.zhao@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_vp8
+ * @short_description: VP8 decoder
+ */
+
+#include "sysdeps.h"
+#include <gst/codecparsers/gstvp8parser.h>
+#include "gstvaapidecoder_vp8.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+
+#include "gstvaapicompat.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_DECODER_VP8_CAST(decoder) \
+  ((GstVaapiDecoderVp8 *)(decoder))
+
+typedef struct _GstVaapiDecoderVp8Private GstVaapiDecoderVp8Private;
+typedef struct _GstVaapiDecoderVp8Class GstVaapiDecoderVp8Class;
+
+struct _GstVaapiDecoderVp8Private
+{
+  GstVaapiProfile profile;
+  guint width;
+  guint height;
+  GstVp8Parser parser;
+  GstVp8FrameHdr frame_hdr;
+  GstVaapiPicture *last_picture;
+  GstVaapiPicture *golden_ref_picture;
+  GstVaapiPicture *alt_ref_picture;
+  GstVaapiPicture *current_picture;
+  guint size_changed:1;
+};
+
+/**
+ * GstVaapiDecoderVp8:
+ *
+ * A decoder based on Vp8.
+ */
+struct _GstVaapiDecoderVp8
+{
+  /*< private > */
+  GstVaapiDecoder parent_instance;
+
+  GstVaapiDecoderVp8Private priv;
+};
+
+/**
+ * GstVaapiDecoderVp8Class:
+ *
+ * A decoder class based on Vp8.
+ */
+struct _GstVaapiDecoderVp8Class
+{
+  /*< private > */
+  GstVaapiDecoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiDecoderVp8, gst_vaapi_decoder_vp8,
+    GST_TYPE_VAAPI_DECODER);
+
+static GstVaapiDecoderStatus
+get_status (GstVp8ParserResult result)
+{
+  GstVaapiDecoderStatus status;
+
+  switch (result) {
+    case GST_VP8_PARSER_OK:
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+    case GST_VP8_PARSER_ERROR:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+      break;
+    default:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+      break;
+  }
+  return status;
+}
+
+static void
+gst_vaapi_decoder_vp8_close (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+
+  gst_vaapi_picture_replace (&priv->last_picture, NULL);
+  gst_vaapi_picture_replace (&priv->golden_ref_picture, NULL);
+  gst_vaapi_picture_replace (&priv->alt_ref_picture, NULL);
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+}
+
+static gboolean
+gst_vaapi_decoder_vp8_open (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_vp8_close (decoder);
+  gst_vp8_parser_init (&priv->parser);
+  return TRUE;
+}
+
+static void
+gst_vaapi_decoder_vp8_destroy (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
+
+  gst_vaapi_decoder_vp8_close (decoder);
+}
+
+static gboolean
+gst_vaapi_decoder_vp8_create (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+
+  if (!gst_vaapi_decoder_vp8_open (decoder))
+    return FALSE;
+
+  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp8_reset (GstVaapiDecoder * base_decoder)
+{
+  gst_vaapi_decoder_vp8_destroy (base_decoder);
+  if (gst_vaapi_decoder_vp8_create (base_decoder))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+}
+
+static GstVaapiDecoderStatus
+ensure_context (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  const GstVaapiProfile profile = GST_VAAPI_PROFILE_VP8;
+  const GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+  gboolean reset_context = FALSE;
+
+  if (priv->profile != profile) {
+    if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
+            profile, entrypoint))
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+    priv->profile = profile;
+    reset_context = TRUE;
+  }
+
+  if (priv->size_changed) {
+    GST_DEBUG ("size changed");
+    priv->size_changed = FALSE;
+    reset_context = TRUE;
+  }
+
+  if (reset_context) {
+    GstVaapiContextInfo info;
+
+    info.profile = priv->profile;
+    info.entrypoint = entrypoint;
+    info.chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+    info.width = priv->width;
+    info.height = priv->height;
+    info.ref_frames = 3;
+    reset_context =
+        gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info);
+
+    if (!reset_context)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+ensure_quant_matrix (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVp8Segmentation *const seg = &priv->parser.segmentation;
+  VAIQMatrixBufferVP8 *iq_matrix;
+  const gint8 QI_MAX = 127;
+  gint8 qi, qi_base;
+  gint i;
+
+  picture->iq_matrix = GST_VAAPI_IQ_MATRIX_NEW (VP8, decoder);
+  if (!picture->iq_matrix) {
+    GST_ERROR ("failed to allocate IQ matrix");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  iq_matrix = picture->iq_matrix->param;
+
+  /* Fill in VAIQMatrixBufferVP8 */
+  for (i = 0; i < 4; i++) {
+    if (seg->segmentation_enabled) {
+      qi_base = seg->quantizer_update_value[i];
+      if (!seg->segment_feature_mode)   // 0 means delta update
+        qi_base += frame_hdr->quant_indices.y_ac_qi;
+    } else
+      qi_base = frame_hdr->quant_indices.y_ac_qi;
+
+    qi = qi_base;
+    iq_matrix->quantization_index[i][0] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.y_dc_delta;
+    iq_matrix->quantization_index[i][1] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.y2_dc_delta;
+    iq_matrix->quantization_index[i][2] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.y2_ac_delta;
+    iq_matrix->quantization_index[i][3] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.uv_dc_delta;
+    iq_matrix->quantization_index[i][4] = CLAMP (qi, 0, QI_MAX);
+    qi = qi_base + frame_hdr->quant_indices.uv_ac_delta;
+    iq_matrix->quantization_index[i][5] = CLAMP (qi, 0, QI_MAX);
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+ensure_probability_table (GstVaapiDecoderVp8 * decoder,
+    GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+  VAProbabilityDataBufferVP8 *prob_table;
+
+  picture->prob_table = GST_VAAPI_PROBABILITY_TABLE_NEW (VP8, decoder);
+  if (!picture->prob_table) {
+    GST_ERROR ("failed to allocate probality table");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  prob_table = picture->prob_table->param;
+
+  /* Fill in VAProbabilityDataBufferVP8 */
+  memcpy (prob_table->dct_coeff_probs, frame_hdr->token_probs.prob,
+      sizeof (frame_hdr->token_probs.prob));
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+init_picture (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+
+  picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+  picture->type = frame_hdr->key_frame ? GST_VAAPI_PICTURE_TYPE_I :
+      GST_VAAPI_PICTURE_TYPE_P;
+  picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
+
+  if (!frame_hdr->show_frame)
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
+}
+
+static gboolean
+fill_picture (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  VAPictureParameterBufferVP8 *const pic_param = picture->param;
+  GstVp8Parser *const parser = &priv->parser;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+  GstVp8Segmentation *const seg = &parser->segmentation;
+  gint i;
+
+  /* Fill in VAPictureParameterBufferVP8 */
+  pic_param->frame_width = priv->width;
+  pic_param->frame_height = priv->height;
+
+  pic_param->last_ref_frame = VA_INVALID_SURFACE;
+  pic_param->golden_ref_frame = VA_INVALID_SURFACE;
+  pic_param->alt_ref_frame = VA_INVALID_SURFACE;
+  if (!frame_hdr->key_frame) {
+    if (priv->last_picture)
+      pic_param->last_ref_frame = priv->last_picture->surface_id;
+    if (priv->golden_ref_picture)
+      pic_param->golden_ref_frame = priv->golden_ref_picture->surface_id;
+    if (priv->alt_ref_picture)
+      pic_param->alt_ref_frame = priv->alt_ref_picture->surface_id;
+  }
+  pic_param->out_of_loop_frame = VA_INVALID_SURFACE;    // not used currently
+
+  pic_param->pic_fields.value = 0;
+  pic_param->pic_fields.bits.key_frame = !frame_hdr->key_frame;
+  pic_param->pic_fields.bits.version = frame_hdr->version;
+  pic_param->pic_fields.bits.segmentation_enabled = seg->segmentation_enabled;
+  pic_param->pic_fields.bits.update_mb_segmentation_map =
+      seg->update_mb_segmentation_map;
+  pic_param->pic_fields.bits.update_segment_feature_data =
+      seg->update_segment_feature_data;
+  pic_param->pic_fields.bits.filter_type = frame_hdr->filter_type;
+  pic_param->pic_fields.bits.sharpness_level = frame_hdr->sharpness_level;
+  pic_param->pic_fields.bits.loop_filter_adj_enable =
+      parser->mb_lf_adjust.loop_filter_adj_enable;
+  pic_param->pic_fields.bits.mode_ref_lf_delta_update =
+      parser->mb_lf_adjust.mode_ref_lf_delta_update;
+  pic_param->pic_fields.bits.sign_bias_golden = frame_hdr->sign_bias_golden;
+  pic_param->pic_fields.bits.sign_bias_alternate =
+      frame_hdr->sign_bias_alternate;
+  pic_param->pic_fields.bits.mb_no_coeff_skip = frame_hdr->mb_no_skip_coeff;
+
+  for (i = 0; i < 3; i++)
+    pic_param->mb_segment_tree_probs[i] = seg->segment_prob[i];
+
+  for (i = 0; i < 4; i++) {
+    gint8 level;
+    if (seg->segmentation_enabled) {
+      level = seg->lf_update_value[i];
+      if (!seg->segment_feature_mode)   // 0 means delta update
+        level += frame_hdr->loop_filter_level;
+    } else
+      level = frame_hdr->loop_filter_level;
+    pic_param->loop_filter_level[i] = CLAMP (level, 0, 63);
+
+    pic_param->loop_filter_deltas_ref_frame[i] =
+        parser->mb_lf_adjust.ref_frame_delta[i];
+    pic_param->loop_filter_deltas_mode[i] =
+        parser->mb_lf_adjust.mb_mode_delta[i];
+  }
+
+  /* In decoding, the only loop filter settings that matter are those
+     in the frame header (9.1) */
+  pic_param->pic_fields.bits.loop_filter_disable =
+      frame_hdr->loop_filter_level == 0;
+
+  pic_param->prob_skip_false = frame_hdr->prob_skip_false;
+  pic_param->prob_intra = frame_hdr->prob_intra;
+  pic_param->prob_last = frame_hdr->prob_last;
+  pic_param->prob_gf = frame_hdr->prob_gf;
+
+  memcpy (pic_param->y_mode_probs, frame_hdr->mode_probs.y_prob,
+      sizeof (frame_hdr->mode_probs.y_prob));
+  memcpy (pic_param->uv_mode_probs, frame_hdr->mode_probs.uv_prob,
+      sizeof (frame_hdr->mode_probs.uv_prob));
+  memcpy (pic_param->mv_probs, frame_hdr->mv_probs.prob,
+      sizeof (frame_hdr->mv_probs));
+
+  pic_param->bool_coder_ctx.range = frame_hdr->rd_range;
+  pic_param->bool_coder_ctx.value = frame_hdr->rd_value;
+  pic_param->bool_coder_ctx.count = frame_hdr->rd_count;
+
+  return TRUE;
+}
+
+static gboolean
+fill_slice (GstVaapiDecoderVp8 * decoder, GstVaapiSlice * slice)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  VASliceParameterBufferVP8 *const slice_param = slice->param;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+  gint i;
+
+  /* Fill in VASliceParameterBufferVP8 */
+  slice_param->slice_data_offset = frame_hdr->data_chunk_size;
+  slice_param->macroblock_offset = frame_hdr->header_size;
+  slice_param->num_of_partitions =
+      (1 << frame_hdr->log2_nbr_of_dct_partitions) + 1;
+
+  slice_param->partition_size[0] =
+      frame_hdr->first_part_size - ((slice_param->macroblock_offset + 7) >> 3);
+  for (i = 1; i < slice_param->num_of_partitions; i++)
+    slice_param->partition_size[i] = frame_hdr->partition_size[i - 1];
+  for (; i < G_N_ELEMENTS (slice_param->partition_size); i++)
+    slice_param->partition_size[i] = 0;
+
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_slice (GstVaapiDecoderVp8 * decoder, GstVaapiPicture * picture,
+    const guchar * buf, guint buf_size)
+{
+  GstVaapiSlice *slice;
+
+  slice = GST_VAAPI_SLICE_NEW (VP8, decoder, buf, buf_size);
+  if (!slice) {
+    GST_ERROR ("failed to allocate slice");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  if (!fill_slice (decoder, slice)) {
+    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice));
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_picture (GstVaapiDecoderVp8 * decoder, const guchar * buf,
+    guint buf_size)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVaapiPicture *picture;
+  GstVaapiDecoderStatus status;
+
+  status = ensure_context (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  /* Create new picture */
+  picture = GST_VAAPI_PICTURE_NEW (VP8, decoder);
+  if (!picture) {
+    GST_ERROR ("failed to allocate picture");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  gst_vaapi_picture_replace (&priv->current_picture, picture);
+  gst_vaapi_picture_unref (picture);
+
+  status = ensure_quant_matrix (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  status = ensure_probability_table (decoder, picture);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  init_picture (decoder, picture);
+  if (!fill_picture (decoder, picture))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  return decode_slice (decoder, picture, buf, buf_size);
+}
+
+static void
+update_ref_frames (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVaapiPicture *picture = priv->current_picture;
+  GstVp8FrameHdr *const frame_hdr = &priv->frame_hdr;
+
+  // update picture reference
+  if (frame_hdr->key_frame) {
+    gst_vaapi_picture_replace (&priv->golden_ref_picture, picture);
+    gst_vaapi_picture_replace (&priv->alt_ref_picture, picture);
+  } else {
+    // process refresh_alternate_frame/copy_buffer_to_alternate first
+    if (frame_hdr->refresh_alternate_frame) {
+      gst_vaapi_picture_replace (&priv->alt_ref_picture, picture);
+    } else {
+      switch (frame_hdr->copy_buffer_to_alternate) {
+        case 0:
+          // do nothing
+          break;
+        case 1:
+          gst_vaapi_picture_replace (&priv->alt_ref_picture,
+              priv->last_picture);
+          break;
+        case 2:
+          gst_vaapi_picture_replace (&priv->alt_ref_picture,
+              priv->golden_ref_picture);
+          break;
+        default:
+          GST_WARNING
+              ("WARNING: VP8 decoder: unrecognized copy_buffer_to_alternate");
+      }
+    }
+
+    if (frame_hdr->refresh_golden_frame) {
+      gst_vaapi_picture_replace (&priv->golden_ref_picture, picture);
+    } else {
+      switch (frame_hdr->copy_buffer_to_golden) {
+        case 0:
+          // do nothing
+          break;
+        case 1:
+          gst_vaapi_picture_replace (&priv->golden_ref_picture,
+              priv->last_picture);
+          break;
+        case 2:
+          gst_vaapi_picture_replace (&priv->golden_ref_picture,
+              priv->alt_ref_picture);
+          break;
+        default:
+          GST_WARNING
+              ("WARNING: VP8 decoder: unrecognized copy_buffer_to_golden");
+      }
+    }
+  }
+  if (frame_hdr->key_frame || frame_hdr->refresh_last)
+    gst_vaapi_picture_replace (&priv->last_picture, picture);
+}
+
+static GstVaapiDecoderStatus
+decode_current_picture (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->current_picture;
+
+  if (!picture)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  update_ref_frames (decoder);
+  if (!gst_vaapi_picture_decode (picture))
+    goto error;
+  if (!gst_vaapi_picture_output (picture))
+    goto error;
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    /* XXX: fix for cases where first field failed to be decoded */
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+}
+
+static GstVaapiDecoderStatus
+parse_frame_header (GstVaapiDecoderVp8 * decoder, const guchar * buf,
+    guint buf_size, GstVp8FrameHdr * frame_hdr)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVp8ParserResult result;
+
+  memset (frame_hdr, 0, sizeof (*frame_hdr));
+  result = gst_vp8_parser_parse_frame_header (&priv->parser, frame_hdr,
+      buf, buf_size);
+  if (result != GST_VP8_PARSER_OK)
+    return get_status (result);
+
+  if (frame_hdr->key_frame &&
+      (frame_hdr->width != priv->width || frame_hdr->height != priv->height)) {
+    priv->width = frame_hdr->width;
+    priv->height = frame_hdr->height;
+    priv->size_changed = TRUE;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp8_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  guint flags = 0;
+
+  unit->size = gst_adapter_available (adapter);
+
+  /* The whole frame is available */
+  flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+  flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+  flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+}
+
+static GstVaapiDecoderStatus
+decode_buffer (GstVaapiDecoderVp8 * decoder, const guchar * buf, guint buf_size)
+{
+  GstVaapiDecoderVp8Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+
+  status = parse_frame_header (decoder, buf, buf_size, &priv->frame_hdr);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  return decode_picture (decoder, buf, buf_size);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp8_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
+  GstVaapiDecoderStatus status;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  status = decode_buffer (decoder, map_info.data + unit->offset, unit->size);
+  gst_buffer_unmap (buffer, &map_info);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp8_start_frame (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * base_unit)
+{
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp8_end_frame (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVp8 *const decoder = GST_VAAPI_DECODER_VP8_CAST (base_decoder);
+
+  return decode_current_picture (decoder);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp8_flush (GstVaapiDecoder * base_decoder)
+{
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+gst_vaapi_decoder_vp8_finalize (GObject * object)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
+
+  gst_vaapi_decoder_vp8_destroy (base_decoder);
+  G_OBJECT_CLASS (gst_vaapi_decoder_vp8_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_vp8_class_init (GstVaapiDecoderVp8Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_decoder_vp8_finalize;
+
+  decoder_class->reset = gst_vaapi_decoder_vp8_reset;
+  decoder_class->parse = gst_vaapi_decoder_vp8_parse;
+  decoder_class->decode = gst_vaapi_decoder_vp8_decode;
+  decoder_class->start_frame = gst_vaapi_decoder_vp8_start_frame;
+  decoder_class->end_frame = gst_vaapi_decoder_vp8_end_frame;
+  decoder_class->flush = gst_vaapi_decoder_vp8_flush;
+}
+
+static void
+gst_vaapi_decoder_vp8_init (GstVaapiDecoderVp8 * decoder)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+
+  gst_vaapi_decoder_vp8_create (base_decoder);
+}
+
+/**
+ * gst_vaapi_decoder_vp8_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for VP8 decoding.  The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_vp8_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return g_object_new (GST_TYPE_VAAPI_DECODER_VP8, "display", display,
+      "caps", caps, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp8.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp8.h
new file mode 100644 (file)
index 0000000..9ba2647
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  gstvaapidecoder_vp8.h - VP8 decoder
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Halley Zhao <halley.zhao@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_VP8_H
+#define GST_VAAPI_DECODER_VP8_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER_VP8 \
+    (gst_vaapi_decoder_vp8_get_type ())
+#define GST_VAAPI_DECODER_VP8(decoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_VP8, GstVaapiDecoderVp8))
+#define GST_VAAPI_IS_DECODER_VP8(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_VP8))
+
+typedef struct _GstVaapiDecoderVp8              GstVaapiDecoderVp8;
+
+GType
+gst_vaapi_decoder_vp8_get_type (void) G_GNUC_CONST;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_vp8_new (GstVaapiDisplay * display, GstCaps * caps);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderVp8, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_VP8_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp9.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp9.c
new file mode 100644 (file)
index 0000000..3862cc2
--- /dev/null
@@ -0,0 +1,833 @@
+/*
+ *  gstvaapidecoder_vp9.c - VP9 decoder
+ *
+ *  Copyright (C) 2014-2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidecoder_vp9
+ * @short_description: VP9 decoder
+ */
+
+#include "sysdeps.h"
+#include <gst/codecparsers/gstvp9parser.h>
+#include "gstvaapidecoder_vp9.h"
+#include "gstvaapidecoder_objects.h"
+#include "gstvaapidecoder_priv.h"
+#include "gstvaapidisplay_priv.h"
+
+#include "gstvaapicompat.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_DECODER_VP9_CAST(decoder) \
+  ((GstVaapiDecoderVp9 *)(decoder))
+
+typedef struct _GstVaapiDecoderVp9Private GstVaapiDecoderVp9Private;
+typedef struct _GstVaapiDecoderVp9Class GstVaapiDecoderVp9Class;
+
+struct _GstVaapiDecoderVp9Private
+{
+  GstVaapiProfile profile;
+  guint width;
+  guint height;
+  GstVp9Parser *parser;
+  GstVp9FrameHdr frame_hdr;
+  GstVaapiPicture *current_picture;
+  GstVaapiPicture *ref_frames[GST_VP9_REF_FRAMES];      /* reference frames in ref_slots[max_ref] */
+
+  guint num_frames;             /* number of frames in a super frame */
+  guint frame_sizes[8];         /* size of frames in a super frame */
+  guint frame_cnt;              /* frame count variable for super frame */
+  guint total_idx_size;         /* super frame index size (full block size) */
+  guint had_superframe_hdr:1;   /* indicate the presense of super frame */
+
+  guint size_changed:1;
+};
+
+/**
+ * GstVaapiDecoderVp9:
+ *
+ * A decoder based on Vp9.
+ */
+struct _GstVaapiDecoderVp9
+{
+  /*< private > */
+  GstVaapiDecoder parent_instance;
+
+  GstVaapiDecoderVp9Private priv;
+};
+
+/**
+ * GstVaapiDecoderVp9Class:
+ *
+ * A decoder class based on Vp9.
+ */
+struct _GstVaapiDecoderVp9Class
+{
+  /*< private > */
+  GstVaapiDecoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiDecoderVp9, gst_vaapi_decoder_vp9,
+    GST_TYPE_VAAPI_DECODER);
+
+static GstVaapiDecoderStatus
+get_status (GstVp9ParserResult result)
+{
+  GstVaapiDecoderStatus status;
+
+  switch (result) {
+    case GST_VP9_PARSER_OK:
+      status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+      break;
+    case GST_VP9_PARSER_ERROR:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+      break;
+    default:
+      status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+      break;
+  }
+  return status;
+}
+
+static void
+gst_vaapi_decoder_vp9_close (GstVaapiDecoderVp9 * decoder)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  guint i;
+
+  for (i = 0; i < GST_VP9_REF_FRAMES; i++)
+    gst_vaapi_picture_replace (&priv->ref_frames[i], NULL);
+
+  g_clear_pointer (&priv->parser, gst_vp9_parser_free);
+}
+
+static gboolean
+gst_vaapi_decoder_vp9_open (GstVaapiDecoderVp9 * decoder)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+
+  gst_vaapi_decoder_vp9_close (decoder);
+  priv->parser = gst_vp9_parser_new ();
+  return TRUE;
+}
+
+static void
+gst_vaapi_decoder_vp9_destroy (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder);
+
+  gst_vaapi_decoder_vp9_close (decoder);
+}
+
+static gboolean
+gst_vaapi_decoder_vp9_create (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder);
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+
+  if (!gst_vaapi_decoder_vp9_open (decoder))
+    return FALSE;
+
+  priv->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp9_reset (GstVaapiDecoder * base_decoder)
+{
+  gst_vaapi_decoder_vp9_destroy (base_decoder);
+  if (gst_vaapi_decoder_vp9_create (base_decoder))
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+  return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+}
+
+/* Returns GstVaapiProfile from VP9 frame_hdr profile value */
+static GstVaapiProfile
+get_profile (guint profile_idc)
+{
+  GstVaapiProfile profile;
+
+  switch (profile_idc) {
+    case GST_VP9_PROFILE_0:
+      profile = GST_VAAPI_PROFILE_VP9_0;
+      break;
+    case GST_VP9_PROFILE_1:
+      profile = GST_VAAPI_PROFILE_VP9_1;
+      break;
+    case GST_VP9_PROFILE_2:
+      profile = GST_VAAPI_PROFILE_VP9_2;
+      break;
+    case GST_VP9_PROFILE_3:
+      profile = GST_VAAPI_PROFILE_VP9_3;
+      break;
+    default:
+      GST_DEBUG ("unsupported profile_idc value");
+      profile = GST_VAAPI_PROFILE_UNKNOWN;
+      break;
+  }
+  return profile;
+}
+
+static gboolean
+get_chroma_type (GstVp9FrameHdr * frame_hdr, GstVp9Parser * parser,
+    GstVaapiContextInfo * info)
+{
+  switch (frame_hdr->profile) {
+    case GST_VP9_PROFILE_0:
+      info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+      break;
+    case GST_VP9_PROFILE_1:
+      if (parser->subsampling_x == 1 && parser->subsampling_y == 0)
+        info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422;
+      else if (parser->subsampling_x == 0 && parser->subsampling_y == 0)
+        info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444;
+      else
+        return FALSE;
+      break;
+    case GST_VP9_PROFILE_2:
+      if (parser->bit_depth == 10)
+        info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420_10BPP;
+      else
+        info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420_12BPP;
+      break;
+    case GST_VP9_PROFILE_3:
+      if (parser->subsampling_x == 1 && parser->subsampling_y == 0) {
+        if (parser->bit_depth == 10)
+          info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422_10BPP;
+        else
+          info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422_12BPP;
+      } else if (parser->subsampling_x == 0 && parser->subsampling_y == 0) {
+        if (parser->bit_depth == 10)
+          info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444_10BPP;
+        else
+          info->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444_12BPP;
+      } else
+        return FALSE;
+      break;
+    default:
+      return FALSE;
+      break;
+  }
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+ensure_context (GstVaapiDecoderVp9 * decoder)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  GstVp9FrameHdr *frame_hdr = &priv->frame_hdr;
+  GstVp9Parser *parser = priv->parser;
+  GstVaapiProfile profile;
+  const GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_VLD;
+  gboolean reset_context = FALSE;
+
+  profile = get_profile (frame_hdr->profile);
+
+  if (priv->profile != profile) {
+    if (!gst_vaapi_display_has_decoder (GST_VAAPI_DECODER_DISPLAY (decoder),
+            profile, entrypoint))
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+    priv->profile = profile;
+    reset_context = TRUE;
+  }
+
+  if (priv->size_changed) {
+    GST_DEBUG ("size changed");
+    priv->size_changed = FALSE;
+    reset_context = TRUE;
+  }
+
+  if (reset_context) {
+    GstVaapiContextInfo info;
+
+    info.profile = priv->profile;
+    info.entrypoint = entrypoint;
+    info.width = priv->width;
+    info.height = priv->height;
+    info.ref_frames = 8;
+    if (!get_chroma_type (frame_hdr, parser, &info))
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT;
+
+    reset_context =
+        gst_vaapi_decoder_ensure_context (GST_VAAPI_DECODER (decoder), &info);
+
+    if (!reset_context)
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+    gst_vaapi_context_reset_on_resize (GST_VAAPI_DECODER_CONTEXT (decoder),
+        FALSE);
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+init_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr;
+
+  picture->structure = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+  picture->type =
+      (frame_hdr->frame_type ==
+      GST_VP9_KEY_FRAME) ? GST_VAAPI_PICTURE_TYPE_I : GST_VAAPI_PICTURE_TYPE_P;
+  picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
+
+  if (!frame_hdr->show_frame)
+    GST_VAAPI_PICTURE_FLAG_SET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
+}
+
+static void
+vaapi_fill_ref_frames (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture,
+    GstVp9FrameHdr * frame_hdr, VADecPictureParameterBufferVP9 * pic_param)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  guint i;
+
+  if (frame_hdr->frame_type != GST_VP9_KEY_FRAME) {
+    pic_param->pic_fields.bits.last_ref_frame =
+        frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_LAST - 1];
+    pic_param->pic_fields.bits.last_ref_frame_sign_bias =
+        frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_LAST - 1];
+    pic_param->pic_fields.bits.golden_ref_frame =
+        frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_GOLDEN - 1];
+    pic_param->pic_fields.bits.golden_ref_frame_sign_bias =
+        frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_GOLDEN - 1];
+    pic_param->pic_fields.bits.alt_ref_frame =
+        frame_hdr->ref_frame_indices[GST_VP9_REF_FRAME_ALTREF - 1];
+    pic_param->pic_fields.bits.alt_ref_frame_sign_bias =
+        frame_hdr->ref_frame_sign_bias[GST_VP9_REF_FRAME_ALTREF - 1];
+  }
+
+  for (i = 0; i < G_N_ELEMENTS (priv->ref_frames); i++) {
+    pic_param->reference_frames[i] = priv->ref_frames[i] ?
+        priv->ref_frames[i]->surface_id : VA_INVALID_SURFACE;
+  }
+}
+
+static gboolean
+fill_picture (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture)
+{
+  GstVaapiDecoderVp9Private *priv = &decoder->priv;
+  VADecPictureParameterBufferVP9 *pic_param = picture->param;
+  GstVp9Parser *parser = priv->parser;
+  GstVp9FrameHdr *frame_hdr = &priv->frame_hdr;
+
+  /* Fill in VAPictureParameterBufferVP9 */
+  pic_param->frame_width = frame_hdr->width;
+  pic_param->frame_height = frame_hdr->height;
+
+  /* Fill in ReferenceFrames */
+  vaapi_fill_ref_frames (decoder, picture, frame_hdr, pic_param);
+
+#define COPY_FIELD(s, f) \
+    pic_param->f = (s)->f
+#define COPY_BFM(a, s, f) \
+    pic_param->a.bits.f = (s)->f
+
+  COPY_BFM (pic_fields, parser, subsampling_x);
+  COPY_BFM (pic_fields, parser, subsampling_y);
+  COPY_BFM (pic_fields, frame_hdr, frame_type);
+  COPY_BFM (pic_fields, frame_hdr, show_frame);
+  COPY_BFM (pic_fields, frame_hdr, error_resilient_mode);
+  COPY_BFM (pic_fields, frame_hdr, intra_only);
+  COPY_BFM (pic_fields, frame_hdr, allow_high_precision_mv);
+  COPY_BFM (pic_fields, frame_hdr, mcomp_filter_type);
+  COPY_BFM (pic_fields, frame_hdr, frame_parallel_decoding_mode);
+  COPY_BFM (pic_fields, frame_hdr, reset_frame_context);
+  COPY_BFM (pic_fields, frame_hdr, refresh_frame_context);
+  COPY_BFM (pic_fields, frame_hdr, frame_context_idx);
+  COPY_BFM (pic_fields, frame_hdr, lossless_flag);
+
+  pic_param->pic_fields.bits.segmentation_enabled =
+      frame_hdr->segmentation.enabled;
+  pic_param->pic_fields.bits.segmentation_temporal_update =
+      frame_hdr->segmentation.temporal_update;
+  pic_param->pic_fields.bits.segmentation_update_map =
+      frame_hdr->segmentation.update_map;
+
+  COPY_FIELD (&frame_hdr->loopfilter, filter_level);
+  COPY_FIELD (&frame_hdr->loopfilter, sharpness_level);
+  COPY_FIELD (frame_hdr, log2_tile_rows);
+  COPY_FIELD (frame_hdr, log2_tile_columns);
+  COPY_FIELD (frame_hdr, frame_header_length_in_bytes);
+  COPY_FIELD (frame_hdr, first_partition_size);
+  COPY_FIELD (frame_hdr, profile);
+#if VA_CHECK_VERSION (0, 39, 0)
+  COPY_FIELD (parser, bit_depth);
+#endif
+
+  g_assert (G_N_ELEMENTS (pic_param->mb_segment_tree_probs) ==
+      G_N_ELEMENTS (parser->mb_segment_tree_probs));
+  g_assert (G_N_ELEMENTS (pic_param->segment_pred_probs) ==
+      G_N_ELEMENTS (parser->segment_pred_probs));
+
+  memcpy (pic_param->mb_segment_tree_probs, parser->mb_segment_tree_probs,
+      sizeof (parser->mb_segment_tree_probs));
+
+  if (frame_hdr->segmentation.temporal_update) {
+    memcpy (pic_param->segment_pred_probs, parser->segment_pred_probs,
+        sizeof (parser->segment_pred_probs));
+  } else {
+    memset (pic_param->segment_pred_probs, 255,
+        sizeof (pic_param->segment_pred_probs));
+  }
+
+  return TRUE;
+}
+
+static gboolean
+fill_slice (GstVaapiDecoderVp9 * decoder, GstVaapiSlice * slice)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  GstVp9Parser *parser = priv->parser;
+  VASliceParameterBufferVP9 *const slice_param = slice->param;
+  guint i;
+
+#define COPY_SEG_FIELD(s, f) \
+    seg_param->f = (s)->f
+
+  /* Fill in VASliceParameterBufferVP9 */
+  for (i = 0; i < GST_VP9_MAX_SEGMENTS; i++) {
+    VASegmentParameterVP9 *seg_param = &slice_param->seg_param[i];
+    GstVp9Segmentation *seg = &parser->segmentation[i];
+
+    memcpy (seg_param->filter_level, seg->filter_level,
+        sizeof (seg->filter_level));
+    COPY_SEG_FIELD (seg, luma_ac_quant_scale);
+    COPY_SEG_FIELD (seg, luma_dc_quant_scale);
+    COPY_SEG_FIELD (seg, chroma_ac_quant_scale);
+    COPY_SEG_FIELD (seg, chroma_dc_quant_scale);
+
+    seg_param->segment_flags.fields.segment_reference_skipped =
+        seg->reference_skip;
+    seg_param->segment_flags.fields.segment_reference_enabled =
+        seg->reference_frame_enabled;
+    seg_param->segment_flags.fields.segment_reference = seg->reference_frame;
+
+  }
+  /* Fixme: When segmentation is disabled, only seg_param[0] has valid values,
+   * all other entries should be populated with 0  ? */
+
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+decode_slice (GstVaapiDecoderVp9 * decoder, GstVaapiPicture * picture,
+    const guchar * buf, guint buf_size)
+{
+  GstVaapiSlice *slice;
+
+  slice = GST_VAAPI_SLICE_NEW (VP9, decoder, buf, buf_size);
+  if (!slice) {
+    GST_ERROR ("failed to allocate slice");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  if (!fill_slice (decoder, slice)) {
+    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (slice));
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  gst_vaapi_picture_add_slice (GST_VAAPI_PICTURE_CAST (picture), slice);
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+update_ref_frames (GstVaapiDecoderVp9 * decoder)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  GstVaapiPicture *picture = priv->current_picture;
+  GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr;
+  guint8 refresh_frame_flags, mask, i = 0;
+
+  if (frame_hdr->frame_type == GST_VP9_KEY_FRAME)
+    refresh_frame_flags = (1 << GST_VP9_REF_FRAMES) - 1;
+  else
+    refresh_frame_flags = frame_hdr->refresh_frame_flags;
+
+  for (mask = refresh_frame_flags; mask; mask >>= 1, ++i) {
+    if (mask & 1)
+      gst_vaapi_picture_replace (&priv->ref_frames[i], picture);
+  }
+}
+
+#ifdef GST_VAAPI_PICTURE_NEW
+#undef GST_VAAPI_PICTURE_NEW
+#endif
+
+#define GST_VAAPI_PICTURE_NEW(codec, decoder)                   \
+  gst_vaapi_picture_new (GST_VAAPI_DECODER_CAST (decoder),      \
+      NULL, sizeof (G_PASTE (VADecPictureParameterBuffer, codec)))
+
+static GstVaapiDecoderStatus
+decode_picture (GstVaapiDecoderVp9 * decoder, const guchar * buf,
+    guint buf_size)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  GstVp9FrameHdr *frame_hdr = &priv->frame_hdr;
+  GstVaapiPicture *picture;
+  GstVaapiDecoderStatus status;
+  guint crop_width = 0, crop_height = 0;
+  gboolean is_clone_pic = FALSE;
+
+  status = ensure_context (decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  /* if show_exising_frame flag is true, we just need to return
+   * the existing frame in ref frame array, so creating a clone
+   * of already decoded frame */
+  if (frame_hdr->show_existing_frame) {
+    GstVaapiPicture *existing_frame =
+        priv->ref_frames[frame_hdr->frame_to_show];
+
+    if (!existing_frame) {
+      GST_ERROR ("Failed to get the existing frame from dpb");
+      return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+    }
+
+    picture = gst_vaapi_picture_new_clone (existing_frame);
+    if (!picture) {
+      GST_ERROR ("Failed to create clone picture");
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+    is_clone_pic = TRUE;
+
+    /* for cloned picture we should always unset the skip flag since
+     * the previously decoded frame might be decode-only but repeat-frame
+     * should make it ready for display */
+    GST_VAAPI_PICTURE_FLAG_UNSET (picture, GST_VAAPI_PICTURE_FLAG_SKIPPED);
+
+    /* reset picture pts with whatever set in VideoCodecFrame */
+    picture->pts = GST_VAAPI_DECODER_CODEC_FRAME (decoder)->pts;
+  } else {
+    /* Create new picture */
+    picture = GST_VAAPI_PICTURE_NEW (VP9, decoder);
+    if (!picture) {
+      GST_ERROR ("failed to allocate picture");
+      return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+    }
+  }
+  gst_vaapi_picture_replace (&priv->current_picture, picture);
+  gst_vaapi_picture_unref (picture);
+
+  if (is_clone_pic)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (priv->width > frame_hdr->width || priv->height > frame_hdr->height) {
+    crop_width = frame_hdr->width;
+    crop_height = frame_hdr->height;
+  }
+  if (crop_width || crop_height) {
+    GstVaapiRectangle crop_rect;
+    crop_rect.x = 0;
+    crop_rect.y = 0;
+    crop_rect.width = crop_width;
+    crop_rect.height = crop_height;
+    gst_vaapi_picture_set_crop_rect (picture, &crop_rect);
+  }
+
+  init_picture (decoder, picture);
+  if (!fill_picture (decoder, picture))
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+
+  return decode_slice (decoder, picture, buf, buf_size);
+}
+
+
+static GstVaapiDecoderStatus
+decode_current_picture (GstVaapiDecoderVp9 * decoder)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  GstVaapiPicture *const picture = priv->current_picture;
+  GstVp9FrameHdr *const frame_hdr = &priv->frame_hdr;
+
+  if (!picture)
+    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  if (frame_hdr->show_existing_frame)
+    goto ret;
+
+  if (!gst_vaapi_picture_decode (picture))
+    goto error;
+
+  update_ref_frames (decoder);
+
+ret:
+  if (!gst_vaapi_picture_output (picture))
+    goto error;
+
+  gst_vaapi_picture_replace (&priv->current_picture, NULL);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    /* XXX: fix for cases where first field failed to be decoded */
+    gst_vaapi_picture_replace (&priv->current_picture, NULL);
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+}
+
+static gboolean
+parse_super_frame (const guchar * data, guint data_size,
+    guint * frame_sizes, guint * frame_count, guint * total_idx_size)
+{
+  guint8 marker;
+  guint32 num_frames = 1, frame_size_length, total_index_size;
+  guint i, j;
+
+  if (data_size <= 0)
+    return FALSE;
+
+  marker = data[data_size - 1];
+
+  if ((marker & 0xe0) == 0xc0) {
+
+    GST_DEBUG ("Got VP9-Super Frame, size %d", data_size);
+
+    num_frames = (marker & 0x7) + 1;
+    frame_size_length = ((marker >> 3) & 0x3) + 1;
+    total_index_size = 2 + num_frames * frame_size_length;
+
+    if ((data_size >= total_index_size)
+        && (data[data_size - total_index_size] == marker)) {
+      const guint8 *x = &data[data_size - total_index_size + 1];
+
+      for (i = 0; i < num_frames; i++) {
+        guint32 cur_frame_size = 0;
+
+        for (j = 0; j < frame_size_length; j++)
+          cur_frame_size |= (*x++) << (j * 8);
+
+        frame_sizes[i] = cur_frame_size;
+      }
+
+      *frame_count = num_frames;
+      *total_idx_size = total_index_size;
+    } else {
+      GST_ERROR ("Failed to parse Super-frame");
+      return FALSE;
+    }
+  } else {
+    *frame_count = num_frames;
+    frame_sizes[0] = data_size;
+    *total_idx_size = 0;
+  }
+
+  return TRUE;
+}
+
+static GstVaapiDecoderStatus
+parse_frame_header (GstVaapiDecoderVp9 * decoder, const guchar * buf,
+    guint buf_size, GstVp9FrameHdr * frame_hdr)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  GstVp9ParserResult result;
+  guint width, height;
+
+  result = gst_vp9_parser_parse_frame_header (priv->parser, frame_hdr,
+      buf, buf_size);
+  if (result != GST_VP9_PARSER_OK)
+    return get_status (result);
+
+  /* Unlike other decoders, vp9 decoder doesn't need to reset the
+   * whole context and surfaces for each resolution change. Calling
+   * ensure_context() again is only needed if the resolution of any frame
+   * is greater than what was previously configured, so that new, larger
+   * surfaces can be allocated. There are streams where a bigger
+   * resolution set in ivf header or webm header but actual resolution
+   * of all frames are less. Also it is possible to have inter-prediction
+   * between these multi resolution frames */
+  width = GST_VAAPI_DECODER_WIDTH (decoder);
+  height = GST_VAAPI_DECODER_HEIGHT (decoder);
+  if (priv->width < width || priv->height < height) {
+    priv->width = GST_VAAPI_DECODER_WIDTH (decoder);
+    priv->height = GST_VAAPI_DECODER_HEIGHT (decoder);
+    priv->size_changed = TRUE;
+  }
+  if ((frame_hdr->width > priv->width || frame_hdr->height > priv->height)) {
+    priv->width = frame_hdr->width;
+    priv->height = frame_hdr->height;
+    priv->size_changed = TRUE;
+  }
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp9_parse (GstVaapiDecoder * base_decoder,
+    GstAdapter * adapter, gboolean at_eos, GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder);
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  guchar *buf;
+  guint buf_size, flags = 0;
+
+  buf_size = gst_adapter_available (adapter);
+  if (!buf_size)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+  buf = (guchar *) gst_adapter_map (adapter, buf_size);
+  if (!buf)
+    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+
+  if (!priv->had_superframe_hdr) {
+    if (!parse_super_frame (buf, buf_size, priv->frame_sizes, &priv->num_frames,
+            &priv->total_idx_size))
+      return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+
+    if (priv->num_frames > 1)
+      priv->had_superframe_hdr = TRUE;
+  }
+
+  unit->size = priv->frame_sizes[priv->frame_cnt++];
+
+  if (priv->frame_cnt == priv->num_frames) {
+    priv->num_frames = 0;
+    priv->frame_cnt = 0;
+    priv->had_superframe_hdr = FALSE;
+    unit->size += priv->total_idx_size;
+  }
+
+  /* The whole frame is available */
+  flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+  flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
+  flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+
+  GST_VAAPI_DECODER_UNIT_FLAG_SET (unit, flags);
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+decode_buffer (GstVaapiDecoderVp9 * decoder, const guchar * buf, guint buf_size)
+{
+  GstVaapiDecoderVp9Private *const priv = &decoder->priv;
+  GstVaapiDecoderStatus status;
+  guint size = buf_size;
+
+  if (priv->total_idx_size && !priv->had_superframe_hdr) {
+    size -= priv->total_idx_size;
+    priv->total_idx_size = 0;
+  }
+
+  status = parse_frame_header (decoder, buf, size, &priv->frame_hdr);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  return decode_picture (decoder, buf, size);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp9_decode (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * unit)
+{
+  GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder);
+  GstVaapiDecoderStatus status;
+  GstBuffer *const buffer =
+      GST_VAAPI_DECODER_CODEC_FRAME (decoder)->input_buffer;
+  GstMapInfo map_info;
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_READ)) {
+    GST_ERROR ("failed to map buffer");
+    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  status = decode_buffer (decoder, map_info.data + unit->offset, unit->size);
+  gst_buffer_unmap (buffer, &map_info);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    return status;
+
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp9_start_frame (GstVaapiDecoder * base_decoder,
+    GstVaapiDecoderUnit * base_unit)
+{
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp9_end_frame (GstVaapiDecoder * base_decoder)
+{
+  GstVaapiDecoderVp9 *const decoder = GST_VAAPI_DECODER_VP9_CAST (base_decoder);
+
+  return decode_current_picture (decoder);
+}
+
+static GstVaapiDecoderStatus
+gst_vaapi_decoder_vp9_flush (GstVaapiDecoder * base_decoder)
+{
+  return GST_VAAPI_DECODER_STATUS_SUCCESS;
+}
+
+static void
+gst_vaapi_decoder_vp9_finalize (GObject * object)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (object);
+
+  gst_vaapi_decoder_vp9_destroy (base_decoder);
+  G_OBJECT_CLASS (gst_vaapi_decoder_vp9_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_decoder_vp9_class_init (GstVaapiDecoderVp9Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDecoderClass *const decoder_class = GST_VAAPI_DECODER_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_decoder_vp9_finalize;
+
+  decoder_class->reset = gst_vaapi_decoder_vp9_reset;
+  decoder_class->parse = gst_vaapi_decoder_vp9_parse;
+  decoder_class->decode = gst_vaapi_decoder_vp9_decode;
+  decoder_class->start_frame = gst_vaapi_decoder_vp9_start_frame;
+  decoder_class->end_frame = gst_vaapi_decoder_vp9_end_frame;
+  decoder_class->flush = gst_vaapi_decoder_vp9_flush;
+}
+
+static void
+gst_vaapi_decoder_vp9_init (GstVaapiDecoderVp9 * decoder)
+{
+  GstVaapiDecoder *const base_decoder = GST_VAAPI_DECODER (decoder);
+
+  gst_vaapi_decoder_vp9_create (base_decoder);
+}
+
+/**
+ * gst_vaapi_decoder_vp9_new:
+ * @display: a #GstVaapiDisplay
+ * @caps: a #GstCaps holding codec information
+ *
+ * Creates a new #GstVaapiDecoder for VP9 decoding.  The @caps can
+ * hold extra information like codec-data and pictured coded size.
+ *
+ * Return value: the newly allocated #GstVaapiDecoder object
+ */
+GstVaapiDecoder *
+gst_vaapi_decoder_vp9_new (GstVaapiDisplay * display, GstCaps * caps)
+{
+  return g_object_new (GST_TYPE_VAAPI_DECODER_VP9, "display", display,
+      "caps", caps, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp9.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidecoder_vp9.h
new file mode 100644 (file)
index 0000000..f00ce73
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  gstvaapidecoder_vp9.h - VP9 decoder
+ *
+ *  Copyright (C) 2015-2016 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODER_VP9_H
+#define GST_VAAPI_DECODER_VP9_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODER_VP9 \
+    (gst_vaapi_decoder_vp9_get_type ())
+#define GST_VAAPI_DECODER_VP9(decoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODER_VP9, GstVaapiDecoderVp9))
+#define GST_VAAPI_IS_DECODER_VP9(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODER_VP9))
+
+typedef struct _GstVaapiDecoderVp9              GstVaapiDecoderVp9;
+
+GType
+gst_vaapi_decoder_vp9_get_type (void) G_GNUC_CONST;
+
+GstVaapiDecoder *
+gst_vaapi_decoder_vp9_new (GstVaapiDisplay * display, GstCaps * caps);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDecoderVp9, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODER_VP9_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay.c
new file mode 100644 (file)
index 0000000..acbc6af
--- /dev/null
@@ -0,0 +1,2192 @@
+/*
+ *  gstvaapidisplay.c - VA display abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidisplay
+ * @short_description: VA display abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiutils.h"
+#include "gstvaapivalue.h"
+#include "gstvaapidisplay.h"
+#include "gstvaapitexturemap.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapiworkarounds.h"
+
+/* Debug category for all vaapi libs */
+GST_DEBUG_CATEGORY (gst_debug_vaapi);
+
+/* Debug category for VaapiDisplay */
+GST_DEBUG_CATEGORY (gst_debug_vaapi_display);
+#define GST_CAT_DEFAULT gst_debug_vaapi_display
+
+#define _do_init                                        \
+    G_ADD_PRIVATE (GstVaapiDisplay);                    \
+    GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_display,   \
+        "vaapidisplay", 0, "VA-API Display");           \
+    GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi, "vaapi", 0, "VA-API helper");
+
+G_DEFINE_TYPE_WITH_CODE (GstVaapiDisplay, gst_vaapi_display, GST_TYPE_OBJECT,
+    _do_init);
+
+typedef struct _GstVaapiProfileConfig GstVaapiProfileConfig;
+struct _GstVaapiProfileConfig
+{
+  GstVaapiProfile profile;
+  guint32 entrypoints;          /* bits map of GstVaapiEntrypoint */
+};
+
+typedef struct _GstVaapiProperty GstVaapiProperty;
+struct _GstVaapiProperty
+{
+  const gchar *name;
+  VADisplayAttribute attribute;
+  gint old_value;
+};
+
+typedef struct _GstVaapiFormatInfo GstVaapiFormatInfo;
+struct _GstVaapiFormatInfo
+{
+  GstVideoFormat format;
+  guint flags;
+};
+
+#define DEFAULT_RENDER_MODE     GST_VAAPI_RENDER_MODE_TEXTURE
+#define DEFAULT_ROTATION        GST_VAAPI_ROTATION_0
+
+#define ENTRY_POINT_FLAG(entry) (1U << G_PASTE(GST_VAAPI_ENTRYPOINT_, entry))
+
+enum
+{
+  PROP_RENDER_MODE = 1,
+  PROP_ROTATION,
+  PROP_HUE,
+  PROP_SATURATION,
+  PROP_BRIGHTNESS,
+  PROP_CONTRAST,
+  PROP_VA_DISPLAY,
+
+  N_PROPERTIES
+};
+
+static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
+
+static gboolean
+get_attribute (GstVaapiDisplay * display, VADisplayAttribType type,
+    gint * value);
+
+static gboolean
+set_attribute (GstVaapiDisplay * display, VADisplayAttribType type, gint value);
+
+static gboolean
+get_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat * v);
+
+static gboolean
+set_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat v);
+
+/* GstVaapiDisplayType enumerations */
+GType
+gst_vaapi_display_type_get_type (void)
+{
+  static GType g_type = 0;
+
+  static const GEnumValue display_types[] = {
+    {GST_VAAPI_DISPLAY_TYPE_ANY,
+        "Auto detection", "any"},
+#if GST_VAAPI_USE_X11
+    {GST_VAAPI_DISPLAY_TYPE_X11,
+        "VA/X11 display", "x11"},
+#endif
+#if GST_VAAPI_USE_GLX
+    {GST_VAAPI_DISPLAY_TYPE_GLX,
+        "VA/GLX display", "glx"},
+#endif
+#if GST_VAAPI_USE_EGL
+    {GST_VAAPI_DISPLAY_TYPE_EGL,
+        "VA/EGL display", "egl"},
+#endif
+#if GST_VAAPI_USE_WAYLAND
+    {GST_VAAPI_DISPLAY_TYPE_WAYLAND,
+        "VA/Wayland display", "wayland"},
+#endif
+#if GST_VAAPI_USE_DRM
+    {GST_VAAPI_DISPLAY_TYPE_DRM,
+        "VA/DRM display", "drm"},
+#endif
+    {0, NULL, NULL},
+  };
+
+  if (!g_type)
+    g_type = g_enum_register_static ("GstVaapiDisplayType", display_types);
+  return g_type;
+}
+
+/**
+ * gst_vaapi_display_type_is_compatible:
+ * @type1: the #GstVaapiDisplayType to test
+ * @type2: the reference #GstVaapiDisplayType
+ *
+ * Compares whether #GstVaapiDisplay @type1 is compatible with @type2.
+ * That is, if @type2 is in "any" category, or derived from @type1.
+ *
+ * Returns: %TRUE if @type1 is compatible with @type2, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_display_type_is_compatible (GstVaapiDisplayType type1,
+    GstVaapiDisplayType type2)
+{
+  if (type1 == type2)
+    return TRUE;
+
+  switch (type1) {
+    case GST_VAAPI_DISPLAY_TYPE_GLX:
+      if (type2 == GST_VAAPI_DISPLAY_TYPE_X11)
+        return TRUE;
+      break;
+    default:
+      break;
+  }
+  return type2 == GST_VAAPI_DISPLAY_TYPE_ANY;
+}
+
+/* Append GstVideoFormat to formats array */
+static inline void
+append_format (GArray * formats, GstVideoFormat format, guint flags)
+{
+  GstVaapiFormatInfo fi;
+
+  fi.format = format;
+  fi.flags = flags;
+  g_array_append_val (formats, fi);
+}
+
+/* Append VAImageFormats to formats array */
+static void
+append_formats (GArray * formats, const VAImageFormat * va_formats,
+    guint * flags, guint n)
+{
+  GstVideoFormat format;
+  int YV12_idx = -1;
+  int I420_idx = -1;
+  const GstVaapiFormatInfo *fip;
+  guint i;
+
+  for (i = 0; i < n; i++) {
+    const VAImageFormat *const va_format = &va_formats[i];
+
+    format = gst_vaapi_video_format_from_va_format (va_format);
+    if (format == GST_VIDEO_FORMAT_UNKNOWN) {
+      GST_DEBUG ("unsupported format %" GST_FOURCC_FORMAT,
+          GST_FOURCC_ARGS (va_format->fourcc));
+      continue;
+    }
+    append_format (formats, format, flags ? flags[i] : 0);
+
+    switch (format) {
+      case GST_VIDEO_FORMAT_YV12:
+        YV12_idx = formats->len - 1;
+        break;
+      case GST_VIDEO_FORMAT_I420:
+        I420_idx = formats->len - 1;
+        break;
+      default:
+        break;
+    }
+  }
+
+  /* Append I420 (resp. YV12) format if YV12 (resp. I420) is not
+     supported by the underlying driver */
+  if ((YV12_idx != -1) && (I420_idx == -1)) {
+    fip = &g_array_index (formats, GstVaapiFormatInfo, YV12_idx);
+    append_format (formats, GST_VIDEO_FORMAT_I420, fip->flags);
+  } else if ((I420_idx != -1) && (YV12_idx == -1)) {
+    fip = &g_array_index (formats, GstVaapiFormatInfo, I420_idx);
+    append_format (formats, GST_VIDEO_FORMAT_YV12, fip->flags);
+  }
+}
+
+/* Sort image formats. Prefer YUV formats first */
+static gint
+compare_yuv_formats (gconstpointer a, gconstpointer b)
+{
+  const GstVideoFormat fmt1 = ((GstVaapiFormatInfo *) a)->format;
+  const GstVideoFormat fmt2 = ((GstVaapiFormatInfo *) b)->format;
+
+  const gboolean is_fmt1_yuv = gst_vaapi_video_format_is_yuv (fmt1);
+  const gboolean is_fmt2_yuv = gst_vaapi_video_format_is_yuv (fmt2);
+
+  if (is_fmt1_yuv != is_fmt2_yuv)
+    return is_fmt1_yuv ? -1 : 1;
+
+  return ((gint) gst_vaapi_video_format_get_score (fmt1) -
+      (gint) gst_vaapi_video_format_get_score (fmt2));
+}
+
+/* Sort subpicture formats. Prefer RGB formats first */
+static gint
+compare_rgb_formats (gconstpointer a, gconstpointer b)
+{
+  const GstVideoFormat fmt1 = ((GstVaapiFormatInfo *) a)->format;
+  const GstVideoFormat fmt2 = ((GstVaapiFormatInfo *) b)->format;
+
+  const gboolean is_fmt1_rgb = gst_vaapi_video_format_is_rgb (fmt1);
+  const gboolean is_fmt2_rgb = gst_vaapi_video_format_is_rgb (fmt2);
+
+  if (is_fmt1_rgb != is_fmt2_rgb)
+    return is_fmt1_rgb ? -1 : 1;
+
+  return ((gint) gst_vaapi_video_format_get_score (fmt1) -
+      (gint) gst_vaapi_video_format_get_score (fmt2));
+}
+
+/* Check if configs array contains profile at entrypoint */
+static inline gboolean
+find_config (GPtrArray * configs, GstVaapiProfile profile,
+    GstVaapiEntrypoint entrypoint)
+{
+  GstVaapiProfileConfig *config;
+  guint i;
+
+  if (!configs)
+    return FALSE;
+
+  for (i = 0; i < configs->len; i++) {
+    config = g_ptr_array_index (configs, i);
+    if (config->profile == profile
+        && (config->entrypoints & (1U << entrypoint)))
+      return TRUE;
+  }
+  return FALSE;
+}
+
+/* HACK: append H.263 Baseline profile if MPEG-4:2 Simple profile is supported */
+static void
+append_h263_config (GArray * configs, GPtrArray * decoders)
+{
+  GstVaapiProfileConfig *config, tmp_config;
+  GstVaapiProfileConfig *mpeg4_simple_config = NULL;
+  GstVaapiProfileConfig *h263_baseline_config = NULL;
+  guint i;
+
+  if (!WORKAROUND_H263_BASELINE_DECODE_PROFILE)
+    return;
+
+  if (!decoders)
+    return;
+
+  for (i = 0; i < decoders->len; i++) {
+    config = g_ptr_array_index (decoders, i);
+    if (config->profile == GST_VAAPI_PROFILE_MPEG4_SIMPLE)
+      mpeg4_simple_config = config;
+    else if (config->profile == GST_VAAPI_PROFILE_H263_BASELINE)
+      h263_baseline_config = config;
+  }
+
+  if (mpeg4_simple_config && !h263_baseline_config) {
+    tmp_config = *mpeg4_simple_config;
+    tmp_config.profile = GST_VAAPI_PROFILE_H263_BASELINE;
+    tmp_config.entrypoints = ENTRY_POINT_FLAG (VLD);
+    g_array_append_val (configs, tmp_config);
+    g_ptr_array_add (decoders, &g_array_index (configs,
+            GstVaapiProfileConfig, configs->len - 1));
+  }
+}
+
+/* Sort profiles. Group per codec */
+static gint
+compare_profiles (gconstpointer a, gconstpointer b)
+{
+  const GstVaapiProfileConfig *const config1 = (GstVaapiProfileConfig *) a;
+  const GstVaapiProfileConfig *const config2 = (GstVaapiProfileConfig *) b;
+
+  g_assert (config1->profile != config2->profile);
+  return config1->profile - config2->profile;
+}
+
+/* Convert configs array to profiles as GstCaps */
+static GArray *
+get_profiles (GPtrArray * configs, GstVaapiCodec codec)
+{
+  GstVaapiProfileConfig *config;
+  GArray *out_profiles;
+  guint i;
+
+  if (!configs)
+    return NULL;
+
+  out_profiles = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile));
+  if (!out_profiles)
+    return NULL;
+
+  for (i = 0; i < configs->len; i++) {
+    config = g_ptr_array_index (configs, i);
+    if (!codec || (codec == gst_vaapi_profile_get_codec (config->profile)))
+      g_array_append_val (out_profiles, config->profile);
+  }
+  return out_profiles;
+}
+
+/* Find format info */
+static const GstVaapiFormatInfo *
+find_format_info (GArray * formats, GstVideoFormat format)
+{
+  const GstVaapiFormatInfo *fip;
+  guint i;
+
+  for (i = 0; i < formats->len; i++) {
+    fip = &g_array_index (formats, GstVaapiFormatInfo, i);
+    if (fip->format == format)
+      return fip;
+  }
+  return NULL;
+}
+
+/* Check if formats array contains format */
+static inline gboolean
+find_format (GArray * formats, GstVideoFormat format)
+{
+  return find_format_info (formats, format) != NULL;
+}
+
+/* Convert formats array to GstCaps */
+static GArray *
+get_formats (GArray * formats)
+{
+  const GstVaapiFormatInfo *fip;
+  GArray *out_formats;
+  guint i;
+
+  out_formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
+  if (!out_formats)
+    return NULL;
+
+  for (i = 0; i < formats->len; i++) {
+    fip = &g_array_index (formats, GstVaapiFormatInfo, i);
+    g_array_append_val (out_formats, fip->format);
+  }
+  return out_formats;
+}
+
+/* Find display attribute */
+static const GstVaapiProperty *
+find_property (GArray * properties, const gchar * name)
+{
+  GstVaapiProperty *prop;
+  guint i;
+
+  if (!name)
+    return NULL;
+
+  for (i = 0; i < properties->len; i++) {
+    prop = &g_array_index (properties, GstVaapiProperty, i);
+    if (strcmp (prop->name, name) == 0)
+      return prop;
+  }
+  return NULL;
+}
+
+#if 0
+static const GstVaapiProperty *
+find_property_by_type (GArray * properties, VADisplayAttribType type)
+{
+  GstVaapiProperty *prop;
+  guint i;
+
+  for (i = 0; i < properties->len; i++) {
+    prop = &g_array_index (properties, GstVaapiProperty, i);
+    if (prop->attribute.type == type)
+      return prop;
+  }
+  return NULL;
+}
+#endif
+
+static inline const GstVaapiProperty *
+find_property_by_pspec (GstVaapiDisplay * display, GParamSpec * pspec)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+
+  return find_property (priv->properties, pspec->name);
+}
+
+static guint
+find_property_id (const gchar * name)
+{
+  typedef struct
+  {
+    const gchar *name;
+    guint id;
+  } property_map;
+
+  static const property_map g_property_map[] = {
+    {GST_VAAPI_DISPLAY_PROP_RENDER_MODE, PROP_RENDER_MODE},
+    {GST_VAAPI_DISPLAY_PROP_ROTATION, PROP_ROTATION},
+    {GST_VAAPI_DISPLAY_PROP_HUE, PROP_HUE},
+    {GST_VAAPI_DISPLAY_PROP_SATURATION, PROP_SATURATION},
+    {GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, PROP_BRIGHTNESS},
+    {GST_VAAPI_DISPLAY_PROP_CONTRAST, PROP_CONTRAST},
+    {NULL,}
+  };
+
+  const property_map *m;
+  for (m = g_property_map; m->name != NULL; m++) {
+    if (strcmp (m->name, name) == 0)
+      return m->id;
+  }
+  return 0;
+}
+
+/* Initialize VA profiles (decoders, encoders) */
+static gboolean
+ensure_profiles (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  VAProfile *profiles = NULL;
+  VAEntrypoint *entrypoints = NULL;
+  gint i, j, n, num_entrypoints;
+  VAStatus status;
+  gboolean success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+
+  if (priv->has_profiles) {
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+    return TRUE;
+  }
+
+  priv->codecs = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfileConfig));
+  if (!priv->codecs)
+    goto cleanup;
+
+  priv->decoders = g_ptr_array_new ();
+  if (!priv->decoders)
+    goto cleanup;
+  priv->encoders = g_ptr_array_new ();
+  if (!priv->encoders)
+    goto cleanup;
+  priv->has_profiles = TRUE;
+
+  /* VA profiles */
+  profiles = g_new (VAProfile, vaMaxNumProfiles (priv->display));
+  if (!profiles)
+    goto cleanup;
+  entrypoints = g_new (VAEntrypoint, vaMaxNumEntrypoints (priv->display));
+  if (!entrypoints)
+    goto cleanup;
+
+  n = 0;
+  status = vaQueryConfigProfiles (priv->display, profiles, &n);
+  if (!vaapi_check_status (status, "vaQueryConfigProfiles()"))
+    goto cleanup;
+
+  GST_DEBUG ("%d profiles", n);
+  for (i = 0; i < n; i++) {
+    if (profiles[i] == VAProfileNone)
+      continue;
+    GST_DEBUG ("  %s", string_of_VAProfile (profiles[i]));
+  }
+
+  for (i = 0; i < n; i++) {
+    GstVaapiProfileConfig config = { 0, };
+
+    config.profile = gst_vaapi_profile (profiles[i]);
+    if (!config.profile)
+      continue;
+
+    status = vaQueryConfigEntrypoints (priv->display,
+        profiles[i], entrypoints, &num_entrypoints);
+    if (!vaapi_check_status (status, "vaQueryConfigEntrypoints()"))
+      continue;
+
+    for (j = 0; j < num_entrypoints; j++)
+      config.entrypoints |= (1U << gst_vaapi_entrypoint (entrypoints[j]));
+
+    priv->codecs = g_array_append_val (priv->codecs, config);
+  }
+
+  for (i = 0; i < priv->codecs->len; i++) {
+    GstVaapiProfileConfig *cfg;
+
+    cfg = &g_array_index (priv->codecs, GstVaapiProfileConfig, i);
+
+    if ((cfg->entrypoints & ENTRY_POINT_FLAG (VLD))
+        || (cfg->entrypoints & ENTRY_POINT_FLAG (IDCT))
+        || (cfg->entrypoints & ENTRY_POINT_FLAG (MOCO)))
+      g_ptr_array_add (priv->decoders, cfg);
+    if ((cfg->entrypoints & ENTRY_POINT_FLAG (SLICE_ENCODE))
+        || (cfg->entrypoints & ENTRY_POINT_FLAG (PICTURE_ENCODE))
+        || (cfg->entrypoints & ENTRY_POINT_FLAG (SLICE_ENCODE_LP)))
+      g_ptr_array_add (priv->encoders, cfg);
+  }
+
+  append_h263_config (priv->codecs, priv->decoders);
+
+  g_ptr_array_sort (priv->decoders, compare_profiles);
+  g_ptr_array_sort (priv->encoders, compare_profiles);
+
+  /* Video processing API */
+  status = vaQueryConfigEntrypoints (priv->display, VAProfileNone,
+      entrypoints, &num_entrypoints);
+  if (vaapi_check_status (status, "vaQueryEntrypoints() [VAProfileNone]")) {
+    for (j = 0; j < num_entrypoints; j++) {
+      if (entrypoints[j] == VAEntrypointVideoProc)
+        priv->has_vpp = TRUE;
+    }
+  }
+  success = TRUE;
+
+  if (priv->encoders->len == 0)
+    g_clear_pointer (&priv->encoders, g_ptr_array_unref);
+  if (priv->decoders->len == 0)
+    g_clear_pointer (&priv->decoders, g_ptr_array_unref);
+  if (priv->codecs->len == 0)
+    g_clear_pointer (&priv->codecs, g_array_unref);
+
+cleanup:
+  g_free (profiles);
+  g_free (entrypoints);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  return success;
+}
+
+/* Initialize VA display attributes */
+static gboolean
+ensure_properties (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  VADisplayAttribute *display_attrs = NULL;
+  VAStatus status;
+  gint i, n;
+  gboolean success = FALSE;
+
+  if (priv->properties)
+    return TRUE;
+
+  priv->properties = g_array_new (FALSE, FALSE, sizeof (GstVaapiProperty));
+  if (!priv->properties)
+    goto cleanup;
+
+  /* VA display attributes */
+  display_attrs =
+      g_new (VADisplayAttribute, vaMaxNumDisplayAttributes (priv->display));
+  if (!display_attrs)
+    goto cleanup;
+
+  n = 0;
+  status = vaQueryDisplayAttributes (priv->display, display_attrs, &n);
+  if (!vaapi_check_status (status, "vaQueryDisplayAttributes()"))
+    goto cleanup;
+
+  GST_DEBUG ("%d display attributes", n);
+  for (i = 0; i < n; i++) {
+    VADisplayAttribute *const attr = &display_attrs[i];
+    GstVaapiProperty prop;
+    gint value;
+
+    GST_DEBUG ("  %s", string_of_VADisplayAttributeType (attr->type));
+
+    switch (attr->type) {
+      case VADisplayAttribRenderMode:
+        prop.name = GST_VAAPI_DISPLAY_PROP_RENDER_MODE;
+        break;
+      case VADisplayAttribRotation:
+        prop.name = GST_VAAPI_DISPLAY_PROP_ROTATION;
+        break;
+      case VADisplayAttribHue:
+        prop.name = GST_VAAPI_DISPLAY_PROP_HUE;
+        break;
+      case VADisplayAttribSaturation:
+        prop.name = GST_VAAPI_DISPLAY_PROP_SATURATION;
+        break;
+      case VADisplayAttribBrightness:
+        prop.name = GST_VAAPI_DISPLAY_PROP_BRIGHTNESS;
+        break;
+      case VADisplayAttribContrast:
+        prop.name = GST_VAAPI_DISPLAY_PROP_CONTRAST;
+        break;
+      default:
+        prop.name = NULL;
+        break;
+    }
+    if (!prop.name)
+      continue;
+
+    /* Assume the attribute is really supported if we can get the
+     * actual and current value */
+    if (!get_attribute (display, attr->type, &value))
+      continue;
+
+    /* Some drivers (e.g. EMGD) have completely random initial
+     * values */
+    if (value < attr->min_value || value > attr->max_value)
+      continue;
+
+    prop.attribute = *attr;
+    prop.old_value = value;
+    g_array_append_val (priv->properties, prop);
+  }
+  success = TRUE;
+
+cleanup:
+  g_free (display_attrs);
+  return success;
+}
+
+/* Initialize VA image formats */
+static gboolean
+ensure_image_formats (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  VAImageFormat *formats = NULL;
+  VAStatus status;
+  gint i, n, max_images;
+  gboolean success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  if (priv->image_formats) {
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+    return TRUE;
+  }
+
+  priv->image_formats = g_array_new (FALSE, FALSE, sizeof (GstVaapiFormatInfo));
+  if (!priv->image_formats)
+    goto cleanup;
+
+  /* VA image formats */
+  max_images = vaMaxNumImageFormats (priv->display);
+  formats = g_new (VAImageFormat, max_images);
+  if (!formats)
+    goto cleanup;
+
+  n = 0;
+  status = vaQueryImageFormats (priv->display, formats, &n);
+  if (!vaapi_check_status (status, "vaQueryImageFormats()"))
+    goto cleanup;
+
+  /* XXX(victor): Force RGBA in i965 display formats.
+   *
+   * This is required for GLTextureUploadMeta since it only negotiates
+   * RGBA, nevertheless i965 driver only reports RGBx breaking back
+   * compatibility.
+   *
+   * Side effects are not expected since it worked before commit
+   * 32bf6f1e */
+  if (gst_vaapi_display_has_driver_quirks (display,
+          GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT)) {
+    formats = g_renew (VAImageFormat, formats, max_images + 1);
+
+    formats[n].fourcc = VA_FOURCC_RGBA;
+    formats[n].byte_order = VA_LSB_FIRST;
+    formats[n].bits_per_pixel = 32;
+    formats[n].depth = 32;
+    formats[n].red_mask = 0x000000ff;
+    formats[n].green_mask = 0x0000ff00;
+    formats[n].blue_mask = 0x00ff0000;
+    formats[n].alpha_mask = 0xff000000;
+    n++;
+  }
+
+  GST_DEBUG ("%d image formats", n);
+  for (i = 0; i < n; i++)
+    GST_DEBUG ("  %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (formats[i].fourcc));
+
+  if (!gst_vaapi_video_format_create_map (formats, n)) {
+    GST_ERROR ("fail to create map between gst video format and vaImageFormat");
+    goto cleanup;
+  }
+
+  append_formats (priv->image_formats, formats, NULL, n);
+  g_array_sort (priv->image_formats, compare_yuv_formats);
+  success = TRUE;
+
+cleanup:
+  g_free (formats);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  return success;
+}
+
+/* Initialize VA subpicture formats */
+static gboolean
+ensure_subpicture_formats (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  VAImageFormat *formats = NULL;
+  unsigned int *flags = NULL;
+  VAStatus status;
+  guint i, n;
+  gboolean success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  if (priv->subpicture_formats) {
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+    return TRUE;
+  }
+
+  priv->subpicture_formats =
+      g_array_new (FALSE, FALSE, sizeof (GstVaapiFormatInfo));
+  if (!priv->subpicture_formats)
+    goto cleanup;
+
+  /* VA subpicture formats */
+  n = vaMaxNumSubpictureFormats (priv->display);
+  formats = g_new (VAImageFormat, n);
+  if (!formats)
+    goto cleanup;
+  flags = g_new (guint, n);
+  if (!flags)
+    goto cleanup;
+
+  n = 0;
+  status = vaQuerySubpictureFormats (priv->display, formats, flags, &n);
+  if (!vaapi_check_status (status, "vaQuerySubpictureFormats()"))
+    goto cleanup;
+
+  GST_DEBUG ("%d subpicture formats", n);
+  for (i = 0; i < n; i++) {
+    GST_DEBUG ("  %" GST_FOURCC_FORMAT, GST_FOURCC_ARGS (formats[i].fourcc));
+    flags[i] = to_GstVaapiSubpictureFlags (flags[i]);
+  }
+
+  append_formats (priv->subpicture_formats, formats, flags, n);
+  g_array_sort (priv->subpicture_formats, compare_rgb_formats);
+  success = TRUE;
+
+cleanup:
+  g_free (formats);
+  g_free (flags);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  return success;
+}
+
+/* Ensures the VA driver vendor string was copied */
+static gboolean
+ensure_vendor_string (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  const gchar *vendor_string;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  if (!priv->vendor_string) {
+    vendor_string = vaQueryVendorString (priv->display);
+    if (vendor_string)
+      priv->vendor_string = g_strdup (vendor_string);
+    GST_INFO_OBJECT (display, "vendor: %s", priv->vendor_string);
+  }
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  return priv->vendor_string != NULL;
+}
+
+static void
+set_driver_quirks (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  guint i;
+
+  /* *INDENT-OFF* */
+  static const struct
+  {
+    const char *match_string;
+    guint quirks;
+  } vaapi_driver_quirks_table[] = {
+    /* @XXX(victor): is this string enough to identify it */
+    { "AMD", GST_VAAPI_DRIVER_QUIRK_NO_CHECK_SURFACE_PUT_IMAGE },
+    { "i965", GST_VAAPI_DRIVER_QUIRK_NO_CHECK_VPP_COLOR_STD },
+    { "i965", GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT },
+    { "iHD", GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50 },
+    { "iHD", GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE },
+    { "i965", GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS },
+  };
+  /* *INDENT-ON* */
+
+  if (!ensure_vendor_string (display))
+    return;
+
+  for (i = 0; i < G_N_ELEMENTS (vaapi_driver_quirks_table); i++) {
+    const char *match_str = vaapi_driver_quirks_table[i].match_string;
+    if (g_strstr_len (priv->vendor_string, strlen (priv->vendor_string),
+            match_str) != NULL) {
+      priv->driver_quirks |= vaapi_driver_quirks_table[i].quirks;
+    }
+  }
+
+  GST_INFO_OBJECT (display, "Matched driver string \"%s\", setting quirks "
+      "(%#x)", priv->vendor_string, priv->driver_quirks);
+}
+
+static void
+gst_vaapi_display_calculate_pixel_aspect_ratio (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  gdouble ratio, delta;
+  gint i, j, index, windex;
+
+  static const gint par[][2] = {
+    {1, 1},                     /* regular screen            */
+    {16, 15},                   /* PAL TV                    */
+    {11, 10},                   /* 525 line Rec.601 video    */
+    {54, 59},                   /* 625 line Rec.601 video    */
+    {64, 45},                   /* 1280x1024 on 16:9 display */
+    {5, 3},                     /* 1280x1024 on  4:3 display */
+    {4, 3}                      /*  800x600  on 16:9 display */
+  };
+
+  /* First, calculate the "real" ratio based on the X values;
+   * which is the "physical" w/h divided by the w/h in pixels of the
+   * display */
+  if (!priv->width || !priv->height || !priv->width_mm || !priv->height_mm)
+    ratio = 1.0;
+  else
+    ratio = (gdouble) (priv->width_mm * priv->height) /
+        (priv->height_mm * priv->width);
+  GST_DEBUG ("calculated pixel aspect ratio: %f", ratio);
+
+  /* Now, find the one from par[][2] with the lowest delta to the real one */
+#define DELTA(idx, w) (ABS(ratio - ((gdouble)par[idx][w] / par[idx][!(w)])))
+  delta = DELTA (0, 0);
+  index = 0;
+  windex = 0;
+
+  for (i = 1; i < G_N_ELEMENTS (par); i++) {
+    for (j = 0; j < 2; j++) {
+      const gdouble this_delta = DELTA (i, j);
+      if (this_delta < delta) {
+        index = i;
+        windex = j;
+        delta = this_delta;
+      }
+    }
+  }
+#undef DELTA
+
+  priv->par_n = par[index][windex];
+  priv->par_d = par[index][windex ^ 1];
+}
+
+static void
+gst_vaapi_display_ensure_screen_resolution (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  const GstVaapiDisplayClass *const klass =
+      GST_VAAPI_DISPLAY_GET_CLASS (display);
+
+  if (priv->got_scrres)
+    return;
+
+  if (klass->get_size)
+    klass->get_size (display, &priv->width, &priv->height);
+  if (klass->get_size_mm)
+    klass->get_size_mm (display, &priv->width_mm, &priv->height_mm);
+
+  gst_vaapi_display_calculate_pixel_aspect_ratio (display);
+  priv->got_scrres = TRUE;
+}
+
+static void
+gst_vaapi_display_destroy (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  GstVaapiDisplayClass *klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
+
+  g_clear_pointer (&priv->decoders, g_ptr_array_unref);
+  g_clear_pointer (&priv->encoders, g_ptr_array_unref);
+  g_clear_pointer (&priv->codecs, g_array_unref);
+  g_clear_pointer (&priv->image_formats, g_array_unref);
+  g_clear_pointer (&priv->subpicture_formats, g_array_unref);
+  g_clear_pointer (&priv->properties, g_array_unref);
+
+  if (priv->display) {
+    if (!priv->parent)
+      vaTerminate (priv->display);
+    priv->display = NULL;
+  }
+
+  if (klass->close_display)
+    klass->close_display (display);
+
+  g_clear_pointer (&priv->display_name, g_free);
+  g_clear_pointer (&priv->vendor_string, g_free);
+
+  gst_vaapi_display_replace (&priv->parent, NULL);
+}
+
+static gboolean
+gst_vaapi_display_create (GstVaapiDisplay * display,
+    GstVaapiDisplayInitType init_type, gpointer data)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  const GstVaapiDisplayClass *const klass =
+      GST_VAAPI_DISPLAY_GET_CLASS (display);
+  GstVaapiDisplayInfo info = {
+    .display = display,
+  };
+
+  switch (init_type) {
+    case GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY:{
+      GstVaapiDisplayInfo *p_info = data;
+
+      info.va_display = p_info->va_display;
+      priv->display = p_info->va_display;
+      priv->use_foreign_display = TRUE;
+
+      if (!klass->bind_display)
+        break;
+
+      data = p_info->native_display;
+      goto bind_display;
+    }
+    case GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME:
+      if (klass->open_display && !klass->open_display (display, data))
+        return FALSE;
+      goto create_display;
+    case GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY:
+    bind_display:
+      if (klass->bind_display && !klass->bind_display (display, data))
+        return FALSE;
+      // fall-through
+    create_display:
+      if (!klass->get_display || !klass->get_display (display, &info))
+        return FALSE;
+      priv->display = info.va_display;
+      priv->native_display = info.native_display;
+      break;
+  }
+  if (!priv->display)
+    return FALSE;
+
+  if (!priv->parent) {
+    if (!vaapi_initialize (priv->display))
+      return FALSE;
+  }
+
+  GST_INFO_OBJECT (display, "new display addr=%p", display);
+  g_free (priv->display_name);
+  priv->display_name = g_strdup (info.display_name);
+
+  set_driver_quirks (display);
+
+  if (!ensure_image_formats (display)) {
+    gst_vaapi_display_destroy (display);
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static void
+gst_vaapi_display_lock_default (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+
+  if (priv->parent)
+    priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent);
+  g_rec_mutex_lock (&priv->mutex);
+}
+
+static void
+gst_vaapi_display_unlock_default (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+
+  if (priv->parent)
+    priv = GST_VAAPI_DISPLAY_GET_PRIVATE (priv->parent);
+  g_rec_mutex_unlock (&priv->mutex);
+}
+
+static void
+gst_vaapi_display_init (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayPrivate *const priv =
+      gst_vaapi_display_get_instance_private (display);
+
+  display->priv = priv;
+  priv->par_n = 1;
+  priv->par_d = 1;
+
+  g_rec_mutex_init (&priv->mutex);
+}
+
+static gboolean
+_set_property (GstVaapiDisplay * display, const GstVaapiProperty * prop,
+    const GValue * value)
+{
+  switch (prop->attribute.type) {
+    case VADisplayAttribRenderMode:{
+      GstVaapiRenderMode mode;
+      if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_RENDER_MODE))
+        return FALSE;
+      mode = g_value_get_enum (value);
+      return gst_vaapi_display_set_render_mode (display, mode);
+    }
+    case VADisplayAttribRotation:{
+      GstVaapiRotation rotation;
+      if (!G_VALUE_HOLDS (value, GST_VAAPI_TYPE_ROTATION))
+        return FALSE;
+      rotation = g_value_get_enum (value);
+      return gst_vaapi_display_set_rotation (display, rotation);
+    }
+    case VADisplayAttribHue:
+    case VADisplayAttribSaturation:
+    case VADisplayAttribBrightness:
+    case VADisplayAttribContrast:{
+      gfloat v;
+      if (!G_VALUE_HOLDS (value, G_TYPE_FLOAT))
+        return FALSE;
+      v = g_value_get_float (value);
+      return set_color_balance (display, find_property_id (prop->name), v);
+    }
+    default:
+      break;
+  }
+
+  GST_WARNING ("unsupported property '%s'", prop->name);
+  return FALSE;
+}
+
+static void
+gst_vaapi_display_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDisplay *display = GST_VAAPI_DISPLAY (object);
+  const GstVaapiProperty *prop;
+
+  if (!ensure_properties (display))
+    return;
+
+  prop = find_property_by_pspec (display, pspec);
+  if (!prop) {
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    return;
+  }
+
+  _set_property (display, prop, value);
+}
+
+static gboolean
+_get_property (GstVaapiDisplay * display, const GstVaapiProperty * prop,
+    GValue * value)
+{
+  switch (prop->attribute.type) {
+    case VADisplayAttribRenderMode:{
+      GstVaapiRenderMode mode;
+      if (!gst_vaapi_display_get_render_mode (display, &mode))
+        return FALSE;
+      if (!G_IS_VALUE (value))
+        g_value_init (value, GST_VAAPI_TYPE_RENDER_MODE);
+      g_value_set_enum (value, mode);
+      break;
+    }
+    case VADisplayAttribRotation:{
+      GstVaapiRotation rotation;
+      rotation = gst_vaapi_display_get_rotation (display);
+      if (!G_IS_VALUE (value))
+        g_value_init (value, GST_VAAPI_TYPE_ROTATION);
+      g_value_set_enum (value, rotation);
+      break;
+    }
+    case VADisplayAttribHue:
+    case VADisplayAttribSaturation:
+    case VADisplayAttribBrightness:
+    case VADisplayAttribContrast:{
+      gfloat val;
+      if (!get_color_balance (display, find_property_id (prop->name), &val))
+        return FALSE;
+      if (!G_IS_VALUE (value))
+        g_value_init (value, G_TYPE_FLOAT);
+      g_value_set_float (value, val);
+      break;
+    }
+    default:
+      GST_WARNING ("unsupported property '%s'", prop->name);
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static void
+gst_vaapi_display_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDisplay *display = GST_VAAPI_DISPLAY (object);
+  const GstVaapiProperty *prop;
+
+  if (property_id == PROP_VA_DISPLAY) {
+    g_value_set_pointer (value, gst_vaapi_display_get_display (display));
+    return;
+  }
+
+  if (!ensure_properties (display))
+    return;
+
+  prop = find_property_by_pspec (display, pspec);
+  if (!prop) {
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    return;
+  }
+
+  _get_property (display, prop, value);
+}
+
+static void
+gst_vaapi_display_finalize (GObject * object)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_DISPLAY (object);
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+
+  gst_vaapi_display_destroy (display);
+  g_rec_mutex_clear (&priv->mutex);
+
+  G_OBJECT_CLASS (gst_vaapi_display_parent_class)->finalize (object);
+}
+
+void
+gst_vaapi_display_class_init (GstVaapiDisplayClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_display_finalize;
+  object_class->set_property = gst_vaapi_display_set_property;
+  object_class->get_property = gst_vaapi_display_get_property;
+
+  klass->lock = gst_vaapi_display_lock_default;
+  klass->unlock = gst_vaapi_display_unlock_default;
+
+  /**
+   * GstVaapiDisplay:render-mode:
+   *
+   * The VA display rendering mode, expressed as a #GstVaapiRenderMode.
+   */
+  g_properties[PROP_RENDER_MODE] =
+      g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_RENDER_MODE,
+      "render mode",
+      "The display rendering mode",
+      GST_VAAPI_TYPE_RENDER_MODE, DEFAULT_RENDER_MODE, G_PARAM_READWRITE);
+
+  /**
+   * GstVaapiDisplay:rotation:
+   *
+   * The VA display rotation mode, expressed as a #GstVaapiRotation.
+   */
+  g_properties[PROP_ROTATION] =
+      g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_ROTATION,
+      "rotation",
+      "The display rotation mode",
+      GST_VAAPI_TYPE_ROTATION, DEFAULT_ROTATION, G_PARAM_READWRITE);
+
+  /**
+   * GstVaapiDisplay:hue:
+   *
+   * The VA display hue, expressed as a float value. Range is -180.0
+   * to 180.0. Default value is 0.0 and represents no modification.
+   */
+  g_properties[PROP_HUE] =
+      g_param_spec_float (GST_VAAPI_DISPLAY_PROP_HUE,
+      "hue", "The display hue value", -180.0, 180.0, 0.0, G_PARAM_READWRITE);
+
+  /**
+   * GstVaapiDisplay:saturation:
+   *
+   * The VA display saturation, expressed as a float value. Range is
+   * 0.0 to 2.0. Default value is 1.0 and represents no modification.
+   */
+  g_properties[PROP_SATURATION] =
+      g_param_spec_float (GST_VAAPI_DISPLAY_PROP_SATURATION,
+      "saturation",
+      "The display saturation value", 0.0, 2.0, 1.0, G_PARAM_READWRITE);
+
+  /**
+   * GstVaapiDisplay:brightness:
+   *
+   * The VA display brightness, expressed as a float value. Range is
+   * -1.0 to 1.0. Default value is 0.0 and represents no modification.
+   */
+  g_properties[PROP_BRIGHTNESS] =
+      g_param_spec_float (GST_VAAPI_DISPLAY_PROP_BRIGHTNESS,
+      "brightness",
+      "The display brightness value", -1.0, 1.0, 0.0, G_PARAM_READWRITE);
+
+  /**
+   * GstVaapiDisplay:contrast:
+   *
+   * The VA display contrast, expressed as a float value. Range is 0.0
+   * to 2.0. Default value is 1.0 and represents no modification.
+   */
+  g_properties[PROP_CONTRAST] =
+      g_param_spec_float (GST_VAAPI_DISPLAY_PROP_CONTRAST,
+      "contrast",
+      "The display contrast value", 0.0, 2.0, 1.0, G_PARAM_READWRITE);
+
+  /**
+   * GstVaapiDisplay:va-display:
+   *
+   * The VA display handle, expressed as a #VADisplay.
+   */
+  g_properties[PROP_VA_DISPLAY] =
+      g_param_spec_pointer ("va-display", "VADisplay",
+      "VA Display handler", G_PARAM_READABLE | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (object_class, N_PROPERTIES, g_properties);
+  gst_type_mark_as_plugin_api (gst_vaapi_display_type_get_type (), 0);
+}
+
+/**
+ * gst_vaapi_display_config:
+ * @display: instance of #GstVaapiDisplay
+ * @init_type: type of initialization #GstVaapiDisplayInitType
+ * @init_value: a pointer to the structure with the initialization
+ * parameters
+ *
+ * Binds @display to the VA layer; otherwise it is just an empty
+ * structure.
+ *
+ * Returns: the configured @display if it was configured correctly;
+ * otherwise unrefs @display and returns %NULL.
+ **/
+GstVaapiDisplay *
+gst_vaapi_display_config (GstVaapiDisplay * display,
+    GstVaapiDisplayInitType init_type, gpointer init_value)
+{
+  g_return_val_if_fail (display && GST_VAAPI_IS_DISPLAY (display), NULL);
+
+  if (!gst_vaapi_display_create (display, init_type, init_value))
+    goto error;
+  return display;
+
+  /* ERRORS */
+error:
+  {
+    gst_object_unref (display);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_display_new_with_display:
+ * @va_display: a #VADisplay
+ *
+ * Creates a new #GstVaapiDisplay, using @va_display as the VA
+ * display.
+ *
+ * Return value: the newly created #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_new_with_display (VADisplay va_display)
+{
+  GstVaapiDisplayInfo info = {
+    .va_display = va_display,
+  };
+
+  return gst_vaapi_display_config (g_object_new (GST_TYPE_VAAPI_DISPLAY, NULL),
+      GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info);
+}
+
+/**
+ * gst_vaapi_display_replace:
+ * @old_display_ptr: a pointer to a #GstVaapiDisplay
+ * @new_display: a #GstVaapiDisplay
+ *
+ * Atomically replaces the display display held in @old_display_ptr
+ * with @new_display. This means that @old_display_ptr shall reference
+ * a valid display. However, @new_display can be NULL.
+ */
+void
+gst_vaapi_display_replace (GstVaapiDisplay ** old_display_ptr,
+    GstVaapiDisplay * new_display)
+{
+  gst_object_replace ((GstObject **) old_display_ptr,
+      (GstObject *) new_display);
+}
+
+/**
+ * gst_vaapi_display_lock:
+ * @display: a #GstVaapiDisplay
+ *
+ * Locks @display. If @display is already locked by another thread,
+ * the current thread will block until @display is unlocked by the
+ * other thread.
+ */
+void
+gst_vaapi_display_lock (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayClass *klass;
+
+  g_return_if_fail (display != NULL);
+
+  klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  if (klass->lock)
+    klass->lock (display);
+}
+
+/**
+ * gst_vaapi_display_unlock:
+ * @display: a #GstVaapiDisplay
+ *
+ * Unlocks @display. If another thread is blocked in a
+ * gst_vaapi_display_lock() call for @display, it will be woken and
+ * can lock @display itself.
+ */
+void
+gst_vaapi_display_unlock (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayClass *klass;
+
+  g_return_if_fail (display != NULL);
+
+  klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  if (klass->unlock)
+    klass->unlock (display);
+}
+
+/**
+ * gst_vaapi_display_sync:
+ * @display: a #GstVaapiDisplay
+ *
+ * Flushes any requests queued for the windowing system and waits until
+ * all requests have been handled. This is often used for making sure
+ * that the display is synchronized with the current state of the program.
+ *
+ * This is most useful for X11. On windowing systems where requests are
+ * handled synchronously, this function will do nothing.
+ */
+void
+gst_vaapi_display_sync (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayClass *klass;
+
+  g_return_if_fail (display != NULL);
+
+  klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  if (klass->sync)
+    klass->sync (display);
+  else if (klass->flush)
+    klass->flush (display);
+}
+
+/**
+ * gst_vaapi_display_flush:
+ * @display: a #GstVaapiDisplay
+ *
+ * Flushes any requests queued for the windowing system.
+ *
+ * This is most useful for X11. On windowing systems where requests
+ * are handled synchronously, this function will do nothing.
+ */
+void
+gst_vaapi_display_flush (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayClass *klass;
+
+  g_return_if_fail (display != NULL);
+
+  klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  if (klass->flush)
+    klass->flush (display);
+}
+
+/**
+ * gst_vaapi_display_get_class_type:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the #GstVaapiDisplayType of @display. This is the type of
+ * the object, thus the associated class, not the type of the VA
+ * display.
+ *
+ * Return value: the #GstVaapiDisplayType
+ */
+GstVaapiDisplayType
+gst_vaapi_display_get_class_type (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY);
+
+  return GST_VAAPI_DISPLAY_GET_CLASS_TYPE (display);
+}
+
+/**
+ * gst_vaapi_display_get_display_type:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the #GstVaapiDisplayType of the VA display bound to
+ * @display. This is not the type of the @display object.
+ *
+ * Return value: the #GstVaapiDisplayType
+ */
+GstVaapiDisplayType
+gst_vaapi_display_get_display_type (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, GST_VAAPI_DISPLAY_TYPE_ANY);
+
+  return GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display);
+}
+
+/**
+ * gst_vaapi_display_get_display_type:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the @display name.
+ *
+ * Return value: the display name
+ */
+const gchar *
+gst_vaapi_display_get_display_name (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, NULL);
+
+  return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display_name;
+}
+
+/**
+ * gst_vaapi_display_get_display:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the #VADisplay bound to @display.
+ *
+ * Return value: the #VADisplay
+ */
+VADisplay
+gst_vaapi_display_get_display (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, NULL);
+
+  return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->display;
+}
+
+/**
+ * gst_vaapi_display_get_width:
+ * @display: a #GstVaapiDisplay
+ *
+ * Retrieves the width of a #GstVaapiDisplay.
+ *
+ * Return value: the width of the @display, in pixels
+ */
+guint
+gst_vaapi_display_get_width (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, 0);
+
+  gst_vaapi_display_ensure_screen_resolution (display);
+
+  return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width;
+}
+
+/**
+ * gst_vaapi_display_get_height:
+ * @display: a #GstVaapiDisplay
+ *
+ * Retrieves the height of a #GstVaapiDisplay
+ *
+ * Return value: the height of the @display, in pixels
+ */
+guint
+gst_vaapi_display_get_height (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, 0);
+
+  gst_vaapi_display_ensure_screen_resolution (display);
+
+  return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height;
+}
+
+/**
+ * gst_vaapi_display_get_size:
+ * @display: a #GstVaapiDisplay
+ * @pwidth: return location for the width, or %NULL
+ * @pheight: return location for the height, or %NULL
+ *
+ * Retrieves the dimensions of a #GstVaapiDisplay.
+ */
+void
+gst_vaapi_display_get_size (GstVaapiDisplay * display, guint * pwidth,
+    guint * pheight)
+{
+  g_return_if_fail (GST_VAAPI_DISPLAY (display));
+
+  gst_vaapi_display_ensure_screen_resolution (display);
+
+  if (pwidth)
+    *pwidth = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->width;
+
+  if (pheight)
+    *pheight = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->height;
+}
+
+/**
+ * gst_vaapi_display_get_pixel_aspect_ratio:
+ * @display: a #GstVaapiDisplay
+ * @par_n: return location for the numerator of pixel aspect ratio, or %NULL
+ * @par_d: return location for the denominator of pixel aspect ratio, or %NULL
+ *
+ * Retrieves the pixel aspect ratio of a #GstVaapiDisplay.
+ */
+void
+gst_vaapi_display_get_pixel_aspect_ratio (GstVaapiDisplay * display,
+    guint * par_n, guint * par_d)
+{
+  g_return_if_fail (display != NULL);
+
+  gst_vaapi_display_ensure_screen_resolution (display);
+
+  if (par_n)
+    *par_n = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_n;
+
+  if (par_d)
+    *par_d = GST_VAAPI_DISPLAY_GET_PRIVATE (display)->par_d;
+}
+
+/**
+ * gst_vaapi_display_has_video_processing:
+ * @display: a #GstVaapiDisplay
+ *
+ * Checks whether the underlying VA driver implementation supports
+ * video processing (VPP) acceleration.
+ *
+ * Returns: %TRUE if some VPP features are available
+ */
+gboolean
+gst_vaapi_display_has_video_processing (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  if (!ensure_profiles (display))
+    return FALSE;
+  return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->has_vpp;
+}
+
+/**
+ * gst_vaapi_display_get_decode_profiles:
+ * @display: a #GstVaapiDisplay
+ *
+ * Gets the supported profiles for decoding. The caller owns an extra
+ * reference to the resulting array of #GstVaapiProfile elements, so
+ * it shall be released with g_array_unref() after usage.
+ *
+ * Return value: a newly allocated #GArray, or %NULL if error or if
+ *   decoding is not supported at all
+ */
+GArray *
+gst_vaapi_display_get_decode_profiles (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, NULL);
+
+  if (!ensure_profiles (display))
+    return NULL;
+  return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders, 0);
+}
+
+/**
+ * gst_vaapi_display_has_decoder:
+ * @display: a #GstVaapiDisplay
+ * @profile: a #VAProfile
+ * @entrypoint: a #GstVaaiEntrypoint
+ *
+ * Returns whether VA @display supports @profile for decoding at the
+ * specified @entrypoint.
+ *
+ * Return value: %TRUE if VA @display supports @profile for decoding.
+ */
+gboolean
+gst_vaapi_display_has_decoder (GstVaapiDisplay * display,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
+{
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  if (!ensure_profiles (display))
+    return FALSE;
+  return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->decoders,
+      profile, entrypoint);
+}
+
+/**
+ * gst_vaapi_display_get_encode_profiles:
+ * @display: a #GstVaapiDisplay
+ *
+ * Gets the supported profiles for encoding. The caller owns an extra
+ * reference to the resulting array of #GstVaapiProfile elements, so
+ * it shall be released with g_array_unref() after usage.
+ *
+ * Return value: a newly allocated #GArray, or %NULL if error or if
+ *   encoding is not supported at all
+ */
+GArray *
+gst_vaapi_display_get_encode_profiles (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, NULL);
+
+  if (!ensure_profiles (display))
+    return NULL;
+  return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders, 0);
+}
+
+/**
+ * gst_vaapi_display_get_encode_profiles_by_codec:
+ * @display: a #GstVaapiDisplay
+ * @codec: a #GstVaapiCodec
+ *
+ * Gets the supported profiles which belongs to @codec for encoding.
+ * The caller owns an extra reference to the resulting array of
+ * #GstVaapiProfile elements, so it shall be released with g_array_unref()
+ * after usage.
+ *
+ * Return value: a newly allocated #GArray, or %NULL if error or if
+ *   no encoding profile is found specified by the @codec.
+ */
+GArray *
+gst_vaapi_display_get_encode_profiles_by_codec (GstVaapiDisplay * display,
+    GstVaapiCodec codec)
+{
+  g_return_val_if_fail (display != NULL, NULL);
+
+  if (!ensure_profiles (display))
+    return NULL;
+  return get_profiles (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders,
+      codec);
+}
+
+/**
+ * gst_vaapi_display_has_encoder:
+ * @display: a #GstVaapiDisplay
+ * @profile: a #VAProfile
+ * @entrypoint: a #GstVaapiEntrypoint
+ *
+ * Returns whether VA @display supports @profile for encoding at the
+ * specified @entrypoint.
+ *
+ * Return value: %TRUE if VA @display supports @profile for encoding.
+ */
+gboolean
+gst_vaapi_display_has_encoder (GstVaapiDisplay * display,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
+{
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  if (!ensure_profiles (display))
+    return FALSE;
+  return find_config (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->encoders,
+      profile, entrypoint);
+}
+
+/**
+ * gst_vaapi_display_get_image_formats:
+ * @display: a #GstVaapiDisplay
+ *
+ * Gets the supported image formats for gst_vaapi_surface_get_image()
+ * or gst_vaapi_surface_put_image().
+ *
+ * Note that this method does not necessarily map image formats
+ * returned by vaQueryImageFormats(). The set of capabilities can be
+ * stripped down, if gstreamer-vaapi does not support the format, or
+ * expanded to cover compatible formats not exposed by the underlying
+ * driver. e.g. I420 can be supported even if the driver only exposes
+ * YV12.
+ *
+ * Note: the caller owns an extra reference to the resulting array of
+ * #GstVideoFormat elements, so it shall be released with
+ * g_array_unref() after usage.
+ *
+ * Return value: a newly allocated #GArray, or %NULL on error or if
+ *   the set is empty
+ */
+GArray *
+gst_vaapi_display_get_image_formats (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, NULL);
+
+  if (!ensure_image_formats (display))
+    return NULL;
+  return get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->image_formats);
+}
+
+/**
+ * gst_vaapi_display_has_image_format:
+ * @display: a #GstVaapiDisplay
+ * @format: a #GstVideoFormat
+ *
+ * Returns whether VA @display supports @format image format.
+ *
+ * Return value: %TRUE if VA @display supports @format image format
+ */
+gboolean
+gst_vaapi_display_has_image_format (GstVaapiDisplay * display,
+    GstVideoFormat format)
+{
+  GstVaapiDisplayPrivate *priv;
+
+  g_return_val_if_fail (display != NULL, FALSE);
+  g_return_val_if_fail (format, FALSE);
+
+  priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+
+  if (!ensure_image_formats (display))
+    return FALSE;
+  if (find_format (priv->image_formats, format))
+    return TRUE;
+
+  /* XXX: try subpicture formats since some drivers could report a
+   * set of VA image formats that is not a superset of the set of VA
+   * subpicture formats
+   */
+  if (!ensure_subpicture_formats (display))
+    return FALSE;
+  return find_format (priv->subpicture_formats, format);
+}
+
+/**
+ * gst_vaapi_display_get_subpicture_formats:
+ * @display: a #GstVaapiDisplay
+ *
+ * Gets the supported subpicture formats.
+ *
+ * Note that this method does not necessarily map subpicture formats
+ * returned by vaQuerySubpictureFormats(). The set of capabilities can
+ * be stripped down if gstreamer-vaapi does not support the
+ * format. e.g. this is the case for paletted formats like IA44.
+ *
+ * Note: the caller owns an extra reference to the resulting array of
+ * #GstVideoFormat elements, so it shall be released with
+ * g_array_unref() after usage.
+ *
+ * Return value: a newly allocated #GArray, or %NULL on error of if
+ *   the set is empty
+ */
+GArray *
+gst_vaapi_display_get_subpicture_formats (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, NULL);
+
+  if (!ensure_subpicture_formats (display))
+    return NULL;
+  return
+      get_formats (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->subpicture_formats);
+}
+
+/**
+ * gst_vaapi_display_has_subpicture_format:
+ * @display: a #GstVaapiDisplay
+ * @format: a #GstVideoFormat
+ * @flags_ptr: pointer to #GstVaapiSubpictureFlags, or zero
+ *
+ * Returns whether VA @display supports @format subpicture format with
+ * the supplied @flags.
+ *
+ * Return value: %TRUE if VA @display supports @format subpicture format
+ */
+gboolean
+gst_vaapi_display_has_subpicture_format (GstVaapiDisplay * display,
+    GstVideoFormat format, guint * flags_ptr)
+{
+  GstVaapiDisplayPrivate *priv;
+  const GstVaapiFormatInfo *fip;
+
+  g_return_val_if_fail (display != NULL, FALSE);
+  g_return_val_if_fail (format, FALSE);
+
+  priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+
+  if (!ensure_subpicture_formats (display))
+    return FALSE;
+
+  fip = find_format_info (priv->subpicture_formats, format);
+  if (!fip)
+    return FALSE;
+
+  if (flags_ptr)
+    *flags_ptr = fip->flags;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_display_has_property:
+ * @display: a #GstVaapiDisplay
+ * @name: the property name to check
+ *
+ * Returns whether VA @display supports the requested property. The
+ * check is performed against the property @name. So, the client
+ * application may perform this check only once and cache this
+ * information.
+ *
+ * Return value: %TRUE if VA @display supports property @name
+ */
+gboolean
+gst_vaapi_display_has_property (GstVaapiDisplay * display, const gchar * name)
+{
+  g_return_val_if_fail (display != NULL, FALSE);
+  g_return_val_if_fail (name, FALSE);
+
+  if (!ensure_properties (display))
+    return FALSE;
+  return find_property (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->properties,
+      name) != NULL;
+}
+
+static gboolean
+get_attribute (GstVaapiDisplay * display, VADisplayAttribType type,
+    gint * value)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  VADisplayAttribute attr = { 0, };
+  VAStatus status;
+
+  attr.type = type;
+  attr.flags = VA_DISPLAY_ATTRIB_GETTABLE;
+  status = vaGetDisplayAttributes (priv->display, &attr, 1);
+  if (!vaapi_check_status (status, "vaGetDisplayAttributes()"))
+    return FALSE;
+  *value = attr.value;
+  return TRUE;
+}
+
+static gboolean
+set_attribute (GstVaapiDisplay * display, VADisplayAttribType type, gint value)
+{
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+  VADisplayAttribute attr = { 0, };
+  VAStatus status;
+
+  attr.type = type;
+  attr.value = value;
+  attr.flags = VA_DISPLAY_ATTRIB_SETTABLE;
+  status = vaSetDisplayAttributes (priv->display, &attr, 1);
+  if (!vaapi_check_status (status, "vaSetDisplayAttributes()"))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+get_render_mode_VADisplayAttribRenderMode (GstVaapiDisplay * display,
+    GstVaapiRenderMode * pmode)
+{
+  gint modes, devices;
+
+  if (!get_attribute (display, VADisplayAttribRenderDevice, &devices))
+    return FALSE;
+  if (!devices)
+    return FALSE;
+  if (!get_attribute (display, VADisplayAttribRenderMode, &modes))
+    return FALSE;
+
+  /* Favor "overlay" mode since it is the most restrictive one */
+  if (modes & (VA_RENDER_MODE_LOCAL_OVERLAY | VA_RENDER_MODE_EXTERNAL_OVERLAY))
+    *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
+  else
+    *pmode = GST_VAAPI_RENDER_MODE_TEXTURE;
+  return TRUE;
+}
+
+static gboolean
+get_render_mode_default (GstVaapiDisplay * display, GstVaapiRenderMode * pmode)
+{
+  switch (GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display)) {
+#if GST_VAAPI_USE_WAYLAND
+    case GST_VAAPI_DISPLAY_TYPE_WAYLAND:
+      /* wl_buffer mapped from VA surface through vaGetSurfaceBufferWl() */
+      *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
+      break;
+#endif
+#if GST_VAAPI_USE_DRM
+    case GST_VAAPI_DISPLAY_TYPE_DRM:
+      /* vaGetSurfaceBufferDRM() returns the underlying DRM buffer handle */
+      *pmode = GST_VAAPI_RENDER_MODE_OVERLAY;
+      break;
+#endif
+    default:
+      /* This includes VA/X11 and VA/GLX modes */
+      *pmode = DEFAULT_RENDER_MODE;
+      break;
+  }
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_display_get_render_mode:
+ * @display: a #GstVaapiDisplay
+ * @pmode: return location for the VA @display rendering mode
+ *
+ * Returns the current VA @display rendering mode.
+ *
+ * Return value: %TRUE if VA @display rendering mode could be determined
+ */
+gboolean
+gst_vaapi_display_get_render_mode (GstVaapiDisplay * display,
+    GstVaapiRenderMode * pmode)
+{
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  /* Try with render-mode attribute */
+  if (get_render_mode_VADisplayAttribRenderMode (display, pmode))
+    return TRUE;
+
+  /* Default: determine from the display type */
+  return get_render_mode_default (display, pmode);
+}
+
+/**
+ * gst_vaapi_display_set_render_mode:
+ * @display: a #GstVaapiDisplay
+ * @mode: the #GstVaapiRenderMode to set
+ *
+ * Sets the VA @display rendering mode to the supplied @mode. This
+ * function returns %FALSE if the rendering mode could not be set,
+ * e.g. run-time switching rendering mode is not supported.
+ *
+ * Return value: %TRUE if VA @display rendering @mode could be changed
+ *   to the requested value
+ */
+gboolean
+gst_vaapi_display_set_render_mode (GstVaapiDisplay * display,
+    GstVaapiRenderMode mode)
+{
+  gint modes, devices;
+
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  if (!get_attribute (display, VADisplayAttribRenderDevice, &devices))
+    return FALSE;
+
+  modes = 0;
+  switch (mode) {
+    case GST_VAAPI_RENDER_MODE_OVERLAY:
+      if (devices & VA_RENDER_DEVICE_LOCAL)
+        modes |= VA_RENDER_MODE_LOCAL_OVERLAY;
+      if (devices & VA_RENDER_DEVICE_EXTERNAL)
+        modes |= VA_RENDER_MODE_EXTERNAL_OVERLAY;
+      break;
+    case GST_VAAPI_RENDER_MODE_TEXTURE:
+      if (devices & VA_RENDER_DEVICE_LOCAL)
+        modes |= VA_RENDER_MODE_LOCAL_GPU;
+      if (devices & VA_RENDER_DEVICE_EXTERNAL)
+        modes |= VA_RENDER_MODE_EXTERNAL_GPU;
+      break;
+  }
+  if (!modes)
+    return FALSE;
+  if (!set_attribute (display, VADisplayAttribRenderMode, modes))
+    return FALSE;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_display_get_rotation:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the current VA @display rotation angle. If the VA driver
+ * does not support "rotation" display attribute, then the display is
+ * assumed to be un-rotated.
+ *
+ * Return value: the current #GstVaapiRotation value
+ */
+GstVaapiRotation
+gst_vaapi_display_get_rotation (GstVaapiDisplay * display)
+{
+  gint value;
+
+  g_return_val_if_fail (display != NULL, DEFAULT_ROTATION);
+
+  if (!get_attribute (display, VADisplayAttribRotation, &value))
+    value = VA_ROTATION_NONE;
+  return to_GstVaapiRotation (value);
+}
+
+/**
+ * gst_vaapi_display_set_rotation:
+ * @display: a #GstVaapiDisplay
+ * @rotation: the #GstVaapiRotation value to set
+ *
+ * Sets the VA @display rotation angle to the supplied @rotation
+ * value. This function returns %FALSE if the rotation angle could not
+ * be set, e.g. the VA driver does not allow to change the display
+ * rotation angle.
+ *
+ * Return value: %TRUE if VA @display rotation angle could be changed
+ *   to the requested value
+ */
+gboolean
+gst_vaapi_display_set_rotation (GstVaapiDisplay * display,
+    GstVaapiRotation rotation)
+{
+  guint value;
+
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  value = from_GstVaapiRotation (rotation);
+  if (!set_attribute (display, VADisplayAttribRotation, value))
+    return FALSE;
+  return TRUE;
+}
+
+/* Get color balance attributes */
+static gboolean
+get_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat * v)
+{
+  GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]);
+  const GstVaapiProperty *prop;
+  const VADisplayAttribute *attr;
+  gfloat out_value;
+  gint value;
+
+  if (!ensure_properties (display))
+    return FALSE;
+
+  if (!pspec)
+    return FALSE;
+
+  prop = find_property_by_pspec (display, &pspec->parent_instance);
+  if (!prop)
+    return FALSE;
+  attr = &prop->attribute;
+
+  if (!get_attribute (display, attr->type, &value))
+    return FALSE;
+
+  /* Scale wrt. the medium ("default") value */
+  out_value = pspec->default_value;
+  if (value > attr->value)
+    out_value += ((gfloat) (value - attr->value) /
+        (attr->max_value - attr->value) *
+        (pspec->maximum - pspec->default_value));
+  else if (value < attr->value)
+    out_value -= ((gfloat) (attr->value - value) /
+        (attr->value - attr->min_value) *
+        (pspec->default_value - pspec->minimum));
+  *v = out_value;
+  return TRUE;
+}
+
+/* Set color balance attribute */
+static gboolean
+set_color_balance (GstVaapiDisplay * display, guint prop_id, gfloat v)
+{
+  GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (g_properties[prop_id]);
+  const GstVaapiProperty *prop;
+  const VADisplayAttribute *attr;
+  gint value;
+
+  if (!ensure_properties (display))
+    return FALSE;
+
+  if (!pspec)
+    return FALSE;
+
+  prop = find_property_by_pspec (display, &pspec->parent_instance);
+  if (!prop)
+    return FALSE;
+  attr = &prop->attribute;
+
+  /* Scale wrt. the medium ("default") value */
+  value = attr->value;
+  if (v > pspec->default_value)
+    value += ((v - pspec->default_value) /
+        (pspec->maximum - pspec->default_value) *
+        (attr->max_value - attr->value));
+  else if (v < pspec->default_value)
+    value -= ((pspec->default_value - v) /
+        (pspec->default_value - pspec->minimum) *
+        (attr->value - attr->min_value));
+  if (!set_attribute (display, attr->type, value))
+    return FALSE;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_display_get_vendor_string:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the VA driver vendor string attached to the supplied VA @display.
+ * The @display owns the vendor string, do *not* de-allocate it.
+ *
+ * This function is thread safe.
+ *
+ * Return value: the current #GstVaapiRotation value
+ */
+const gchar *
+gst_vaapi_display_get_vendor_string (GstVaapiDisplay * display)
+{
+  g_return_val_if_fail (display != NULL, NULL);
+
+  if (!ensure_vendor_string (display))
+    return NULL;
+  return GST_VAAPI_DISPLAY_GET_PRIVATE (display)->vendor_string;
+}
+
+/**
+ * gst_vaapi_display_has_opengl:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns wether the @display that was created does support OpenGL
+ * context to be attached.
+ *
+ * This function is thread safe.
+ *
+ * Return value: %TRUE if the @display supports OpenGL context, %FALSE
+ *   otherwise
+ */
+gboolean
+gst_vaapi_display_has_opengl (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayClass *klass;
+
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  return (klass->display_type == GST_VAAPI_DISPLAY_TYPE_GLX ||
+      klass->display_type == GST_VAAPI_DISPLAY_TYPE_EGL);
+}
+
+/**
+ * gst_vaapi_display_reset_texture_map:
+ * @display: a #GstVaapiDisplay
+ *
+ * Reset the internal #GstVaapiTextureMap if available.
+ *
+ * This function is thread safe.
+ */
+void
+gst_vaapi_display_reset_texture_map (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayClass *klass;
+  GstVaapiTextureMap *map;
+
+  g_return_if_fail (display != NULL);
+
+  if (!gst_vaapi_display_has_opengl (display))
+    return;
+  klass = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  if (!klass->get_texture_map)
+    return;
+  if ((map = klass->get_texture_map (display)))
+    gst_vaapi_texture_map_reset (map);
+}
+
+/**
+ * gst_vaapi_display_get_driver_quirks:
+ * @display: a #GstVaapiDisplay
+ * @quirks: the #GstVaapiDriverQuirks bitwise to check
+ *
+ * Returns: %TRUE if @quirks are set in @display's driver
+ **/
+gboolean
+gst_vaapi_display_has_driver_quirks (GstVaapiDisplay * display, guint quirks)
+{
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  return (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->driver_quirks & quirks);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay.h
new file mode 100644 (file)
index 0000000..2ca9bd3
--- /dev/null
@@ -0,0 +1,293 @@
+/*
+ *  gstvaapidisplay.h - VA display abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_H
+#define GST_VAAPI_DISPLAY_H
+
+#include <va/va.h>
+#include <gst/gst.h>
+#include <gst/vaapi/gstvaapitypes.h>
+#include <gst/vaapi/gstvaapiprofile.h>
+#include <gst/vaapi/video-format.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DISPLAY                  (gst_vaapi_display_get_type ())
+#define GST_VAAPI_DISPLAY(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY, GstVaapiDisplay))
+#define GST_VAAPI_IS_DISPLAY(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DISPLAY))
+
+/**
+ * GST_VAAPI_DISPLAY_GET_CLASS_TYPE:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the #display class type
+ */
+#define GST_VAAPI_DISPLAY_GET_CLASS_TYPE(display) \
+    gst_vaapi_display_get_class_type (GST_VAAPI_DISPLAY (display))
+
+/**
+ * GST_VAAPI_DISPLAY_VADISPLAY_TYPE:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the underlying VADisplay @display type.
+ */
+#define GST_VAAPI_DISPLAY_VADISPLAY_TYPE(display) \
+  gst_vaapi_display_get_display_type (GST_VAAPI_DISPLAY (display))
+
+/**
+ * GST_VAAPI_DISPLAY_VADISPLAY:
+ * @display_: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to the #VADisplay of @display.
+ */
+#define GST_VAAPI_DISPLAY_VADISPLAY(display) \
+  gst_vaapi_display_get_display (GST_VAAPI_DISPLAY (display))
+
+/**
+ * GST_VAAPI_DISPLAY_LOCK:
+ * @display: a #GstVaapiDisplay
+ *
+ * Locks @display
+ */
+#define GST_VAAPI_DISPLAY_LOCK(display) \
+  gst_vaapi_display_lock (GST_VAAPI_DISPLAY (display))
+
+/**
+ * GST_VAAPI_DISPLAY_UNLOCK:
+ * @display: a #GstVaapiDisplay
+ *
+ * Unlocks @display
+ */
+#define GST_VAAPI_DISPLAY_UNLOCK(display) \
+  gst_vaapi_display_unlock (GST_VAAPI_DISPLAY (display))
+
+typedef struct _GstVaapiDisplayInfo             GstVaapiDisplayInfo;
+typedef struct _GstVaapiDisplay                 GstVaapiDisplay;
+
+/**
+ * GstVaapiDriverQuirks:
+ * @GST_VAAPI_DRIVER_QUIRK_NO_CHECK_SURFACE_PUT_IMAGE: if driver
+ *   crashes when try to put an image in a reused surface.
+ *   https://gitlab.freedesktop.org/mesa/mesa/merge_requests/2016
+ * @GST_VAAPI_DRIVER_QUIRK_NO_CHECK_VPP_COLOR_STD: if driver does not
+ *   properly report supported vpp color standards.
+ * @GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT: i965 driver doesn't
+ *   report to support ARGB format, but if it's forced to create a RGBA
+ *   surface, it works. Driver issue:
+ *   https://github.com/intel/intel-vaapi-driver/issues/500
+ * @GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50: if the driver shifts
+ *   the value by 50 when calculating quantization from quality level
+ * @GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE: The requirement
+ *   that one slice should not span tiles when tile is enabled.
+ * @GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS: i965 driver does not
+ *   report all the handled formats for JPEG decoding.
+ */
+typedef enum
+{
+  GST_VAAPI_DRIVER_QUIRK_NO_CHECK_SURFACE_PUT_IMAGE = (1U << 0),
+  GST_VAAPI_DRIVER_QUIRK_NO_CHECK_VPP_COLOR_STD = (1U << 1),
+  GST_VAAPI_DRIVER_QUIRK_MISSING_RGBA_IMAGE_FORMAT = (1U << 3),
+  GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50 = (1U << 4),
+  GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE = (1U << 5),
+  GST_VAAPI_DRIVER_QUIRK_JPEG_DEC_BROKEN_FORMATS = (1U << 6),
+} GstVaapiDriverQuirks;
+
+/**
+ * GstVaapiDisplayType:
+ * @GST_VAAPI_DISPLAY_TYPE_ANY: Automatic detection of the display type.
+ * @GST_VAAPI_DISPLAY_TYPE_X11: VA/X11 display.
+ * @GST_VAAPI_DISPLAY_TYPE_GLX: VA/GLX display.
+ * @GST_VAAPI_DISPLAY_TYPE_WAYLAND: VA/Wayland display.
+ * @GST_VAAPI_DISPLAY_TYPE_DRM: VA/DRM display.
+ * @GST_VAAPI_DISPLAY_TYPE_EGL: VA/EGL display.
+ */
+typedef enum
+{
+  GST_VAAPI_DISPLAY_TYPE_ANY = 0,
+  GST_VAAPI_DISPLAY_TYPE_X11,
+  GST_VAAPI_DISPLAY_TYPE_GLX,
+  GST_VAAPI_DISPLAY_TYPE_WAYLAND,
+  GST_VAAPI_DISPLAY_TYPE_DRM,
+  GST_VAAPI_DISPLAY_TYPE_EGL,
+} GstVaapiDisplayType;
+
+#define GST_VAAPI_TYPE_DISPLAY_TYPE \
+    (gst_vaapi_display_type_get_type())
+
+GType
+gst_vaapi_display_type_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapi_display_get_type (void) G_GNUC_CONST;
+
+gboolean
+gst_vaapi_display_type_is_compatible (GstVaapiDisplayType type1,
+    GstVaapiDisplayType type2);
+
+/**
+ * GstVaapiDisplayInfo:
+ *
+ * Generic class to retrieve VA display info
+ */
+struct _GstVaapiDisplayInfo
+{
+  GstVaapiDisplay *display;
+  gchar *display_name;
+  VADisplay va_display;
+  gpointer native_display;
+};
+
+/**
+ * GstVaapiDisplayProperties:
+ * @GST_VAAPI_DISPLAY_PROP_RENDER_MODE: rendering mode (#GstVaapiRenderMode).
+ * @GST_VAAPI_DISPLAY_PROP_ROTATION: rotation angle (#GstVaapiRotation).
+ * @GST_VAAPI_DISPLAY_PROP_HUE: hue (float: [-180 ; 180], default: 0).
+ * @GST_VAAPI_DISPLAY_PROP_SATURATION: saturation (float: [0 ; 2], default: 1).
+ * @GST_VAAPI_DISPLAY_PROP_BRIGHTNESS: brightness (float: [-1 ; 1], default: 0).
+ * @GST_VAAPI_DISPLAY_PROP_CONTRAST: contrast (float: [0 ; 2], default: 1).
+ */
+#define GST_VAAPI_DISPLAY_PROP_RENDER_MODE      "render-mode"
+#define GST_VAAPI_DISPLAY_PROP_ROTATION         "rotation"
+#define GST_VAAPI_DISPLAY_PROP_HUE              "hue"
+#define GST_VAAPI_DISPLAY_PROP_SATURATION       "saturation"
+#define GST_VAAPI_DISPLAY_PROP_BRIGHTNESS       "brightness"
+#define GST_VAAPI_DISPLAY_PROP_CONTRAST         "contrast"
+
+GstVaapiDisplay *
+gst_vaapi_display_new_with_display (VADisplay va_display);
+
+void
+gst_vaapi_display_replace (GstVaapiDisplay ** old_display_ptr,
+    GstVaapiDisplay * new_display);
+
+void
+gst_vaapi_display_lock (GstVaapiDisplay * display);
+
+void
+gst_vaapi_display_unlock (GstVaapiDisplay * display);
+
+void
+gst_vaapi_display_sync (GstVaapiDisplay * display);
+
+void
+gst_vaapi_display_flush (GstVaapiDisplay * display);
+
+GstVaapiDisplayType
+gst_vaapi_display_get_class_type (GstVaapiDisplay * display);
+
+GstVaapiDisplayType
+gst_vaapi_display_get_display_type (GstVaapiDisplay * display);
+
+const gchar *
+gst_vaapi_display_get_display_name (GstVaapiDisplay * display);
+
+VADisplay
+gst_vaapi_display_get_display (GstVaapiDisplay * display);
+
+guint
+gst_vaapi_display_get_width (GstVaapiDisplay * display);
+
+guint
+gst_vaapi_display_get_height (GstVaapiDisplay * display);
+
+void
+gst_vaapi_display_get_size (GstVaapiDisplay * display, guint * pwidth,
+    guint * pheight);
+
+void
+gst_vaapi_display_get_pixel_aspect_ratio (GstVaapiDisplay * display,
+    guint * par_n, guint * par_d);
+
+gboolean
+gst_vaapi_display_has_video_processing (GstVaapiDisplay * display);
+
+GArray *
+gst_vaapi_display_get_decode_profiles (GstVaapiDisplay * display);
+
+gboolean
+gst_vaapi_display_has_decoder (GstVaapiDisplay * display,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint);
+
+GArray *
+gst_vaapi_display_get_encode_profiles (GstVaapiDisplay * display);
+
+GArray *
+gst_vaapi_display_get_encode_profiles_by_codec (GstVaapiDisplay * display,
+    GstVaapiCodec codec);
+
+gboolean
+gst_vaapi_display_has_encoder (GstVaapiDisplay * display,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint);
+
+GArray *
+gst_vaapi_display_get_image_formats (GstVaapiDisplay * display);
+
+gboolean
+gst_vaapi_display_has_image_format (GstVaapiDisplay * display,
+    GstVideoFormat format);
+
+GArray *
+gst_vaapi_display_get_subpicture_formats (GstVaapiDisplay * display);
+
+gboolean
+gst_vaapi_display_has_subpicture_format (GstVaapiDisplay * display,
+    GstVideoFormat format, guint * flags_ptr);
+
+gboolean
+gst_vaapi_display_has_property (GstVaapiDisplay * display, const gchar * name);
+
+gboolean
+gst_vaapi_display_get_render_mode (GstVaapiDisplay * display,
+    GstVaapiRenderMode * pmode);
+
+gboolean
+gst_vaapi_display_set_render_mode (GstVaapiDisplay * display,
+    GstVaapiRenderMode mode);
+
+GstVaapiRotation
+gst_vaapi_display_get_rotation (GstVaapiDisplay * display);
+
+gboolean
+gst_vaapi_display_set_rotation (GstVaapiDisplay * display,
+    GstVaapiRotation rotation);
+
+const gchar *
+gst_vaapi_display_get_vendor_string (GstVaapiDisplay * display);
+
+gboolean
+gst_vaapi_display_has_opengl (GstVaapiDisplay * display);
+
+void
+gst_vaapi_display_reset_texture_map (GstVaapiDisplay * display);
+
+gboolean
+gst_vaapi_display_has_driver_quirks (GstVaapiDisplay * display, guint quirks);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplay, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_drm.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_drm.c
new file mode 100644 (file)
index 0000000..1fc376a
--- /dev/null
@@ -0,0 +1,470 @@
+/*
+ *  gstvaapidisplay_drm.c - VA/DRM display abstraction
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidisplay_drm
+ * @short_description: VA/DRM display abstraction
+ */
+
+#define _GNU_SOURCE
+#include "sysdeps.h"
+#include <unistd.h>
+#include <fcntl.h>
+#include <libudev.h>
+#include <xf86drm.h>
+#include <va/va_drm.h>
+#include "gstvaapiutils.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapidisplay_drm.h"
+#include "gstvaapidisplay_drm_priv.h"
+#include "gstvaapiwindow_drm.h"
+
+#define DEBUG_VAAPI_DISPLAY 1
+#include "gstvaapidebug.h"
+
+#ifndef MAXPATHLEN
+#if defined(PATH_MAX)
+#define MAXPATHLEN PATH_MAX
+#elif defined(_PC_PATH_MAX)
+#define MAXPATHLEN sysconf(_PC_PATH_MAX)
+#else
+#define MAXPATHLEN 2048
+#endif
+#endif
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiDisplayDRM, gst_vaapi_display_drm,
+    GST_TYPE_VAAPI_DISPLAY);
+
+typedef enum
+{
+  DRM_DEVICE_LEGACY = 1,
+  DRM_DEVICE_RENDERNODES,
+} DRMDeviceType;
+
+static DRMDeviceType g_drm_device_type;
+static GMutex g_drm_device_type_lock;
+static const gchar *allowed_subsystems[] = { "pci", "platform", NULL };
+
+static gboolean
+supports_vaapi (int fd)
+{
+  gboolean ret;
+  VADisplay va_dpy;
+
+  va_dpy = vaGetDisplayDRM (fd);
+  if (!va_dpy)
+    return FALSE;
+
+  ret = vaapi_initialize (va_dpy);
+  vaTerminate (va_dpy);
+  return ret;
+}
+
+/* Get default device path. Actually, the first match in the DRM subsystem */
+static const gchar *
+get_default_device_path (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayDRMPrivate *const priv =
+      GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
+  const gchar *syspath, *devpath;
+  struct udev *udev = NULL;
+  struct udev_device *device, *parent;
+  struct udev_enumerate *e = NULL;
+  struct udev_list_entry *l;
+  gint i;
+  int fd;
+
+  if (!priv->device_path_default) {
+    udev = udev_new ();
+    if (!udev)
+      goto end;
+
+    e = udev_enumerate_new (udev);
+    if (!e)
+      goto end;
+
+    udev_enumerate_add_match_subsystem (e, "drm");
+    switch (g_drm_device_type) {
+      case DRM_DEVICE_LEGACY:
+        udev_enumerate_add_match_sysname (e, "card[0-9]*");
+        break;
+      case DRM_DEVICE_RENDERNODES:
+        udev_enumerate_add_match_sysname (e, "renderD[0-9]*");
+        break;
+      default:
+        GST_ERROR ("unknown drm device type (%d)", g_drm_device_type);
+        goto end;
+    }
+    udev_enumerate_scan_devices (e);
+    udev_list_entry_foreach (l, udev_enumerate_get_list_entry (e)) {
+      syspath = udev_list_entry_get_name (l);
+      device = udev_device_new_from_syspath (udev, syspath);
+      parent = udev_device_get_parent (device);
+
+      for (i = 0; allowed_subsystems[i] != NULL; i++)
+        if (g_strcmp0 (udev_device_get_subsystem (parent),
+                allowed_subsystems[i]) == 0)
+          break;
+
+      if (allowed_subsystems[i] == NULL) {
+        udev_device_unref (device);
+        continue;
+      }
+
+      devpath = udev_device_get_devnode (device);
+      fd = open (devpath, O_RDWR | O_CLOEXEC);
+      if (fd < 0) {
+        udev_device_unref (device);
+        continue;
+      }
+
+      if (supports_vaapi (fd))
+        priv->device_path_default = g_strdup (devpath);
+      close (fd);
+      udev_device_unref (device);
+      if (priv->device_path_default)
+        break;
+    }
+
+  end:
+    if (e)
+      udev_enumerate_unref (e);
+    if (udev)
+      udev_unref (udev);
+  }
+  return priv->device_path_default;
+}
+
+/* Reconstruct a device path without our prefix */
+static const gchar *
+get_device_path (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayDRMPrivate *const priv =
+      GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
+  const gchar *device_path = priv->device_path;
+
+  if (!device_path || *device_path == '\0')
+    return NULL;
+  return device_path;
+}
+
+/* Mangle device path with our prefix */
+static gboolean
+set_device_path (GstVaapiDisplay * display, const gchar * device_path)
+{
+  GstVaapiDisplayDRMPrivate *const priv =
+      GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
+
+  g_free (priv->device_path);
+  priv->device_path = NULL;
+
+  if (!device_path) {
+    device_path = get_default_device_path (display);
+    if (!device_path)
+      return FALSE;
+  }
+  priv->device_path = g_strdup (device_path);
+  return priv->device_path != NULL;
+}
+
+/* Set device path from file descriptor */
+static gboolean
+set_device_path_from_fd (GstVaapiDisplay * display, gint drm_device)
+{
+  GstVaapiDisplayDRMPrivate *const priv =
+      GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
+  gboolean success = FALSE;
+  gchar fd_name[MAXPATHLEN];
+  GError *error = NULL;
+
+  g_free (priv->device_path);
+  priv->device_path = NULL;
+
+  if (drm_device < 0)
+    goto end;
+
+  sprintf (fd_name, "/proc/%d/fd/%d", getpid (), drm_device);
+  priv->device_path = g_file_read_link (fd_name, &error);
+
+  if (error) {
+    g_error_free (error);
+    goto end;
+  }
+
+  if (g_str_has_prefix (priv->device_path, "/dev/dri/card") ||
+      g_str_has_prefix (priv->device_path, "/dev/dri/renderD"))
+    success = TRUE;
+  else {
+    g_free (priv->device_path);
+    priv->device_path = NULL;
+  }
+
+end:
+  return success;
+}
+
+static gboolean
+gst_vaapi_display_drm_bind_display (GstVaapiDisplay * display,
+    gpointer native_display)
+{
+  GstVaapiDisplayDRMPrivate *const priv =
+      GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
+
+  priv->drm_device = GPOINTER_TO_INT (native_display);
+  priv->use_foreign_display = TRUE;
+
+  if (!set_device_path_from_fd (display, priv->drm_device))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_display_drm_open_display (GstVaapiDisplay * display,
+    const gchar * name)
+{
+  GstVaapiDisplayDRMPrivate *const priv =
+      GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
+
+  if (!set_device_path (display, name))
+    return FALSE;
+
+  priv->drm_device = open (get_device_path (display), O_RDWR | O_CLOEXEC);
+  if (priv->drm_device < 0)
+    return FALSE;
+  priv->use_foreign_display = FALSE;
+
+  return TRUE;
+}
+
+static void
+gst_vaapi_display_drm_close_display (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayDRMPrivate *const priv =
+      GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
+
+  if (priv->drm_device >= 0) {
+    if (!priv->use_foreign_display)
+      close (priv->drm_device);
+    priv->drm_device = -1;
+  }
+
+  g_clear_pointer (&priv->device_path, g_free);
+  g_clear_pointer (&priv->device_path_default, g_free);
+}
+
+static gboolean
+gst_vaapi_display_drm_get_display_info (GstVaapiDisplay * display,
+    GstVaapiDisplayInfo * info)
+{
+  GstVaapiDisplayDRMPrivate *const priv =
+      GST_VAAPI_DISPLAY_DRM_PRIVATE (display);
+
+  info->native_display = GINT_TO_POINTER (priv->drm_device);
+  info->display_name = priv->device_path;
+  if (!info->va_display) {
+    info->va_display = vaGetDisplayDRM (priv->drm_device);
+    if (!info->va_display)
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static GstVaapiWindow *
+gst_vaapi_display_drm_create_window (GstVaapiDisplay * display, GstVaapiID id,
+    guint width, guint height)
+{
+  return id != GST_VAAPI_ID_INVALID ?
+      NULL : gst_vaapi_window_drm_new (display, width, height);
+}
+
+static void
+gst_vaapi_display_drm_init (GstVaapiDisplayDRM * display)
+{
+  GstVaapiDisplayDRMPrivate *const priv =
+      gst_vaapi_display_drm_get_instance_private (display);
+
+  display->priv = priv;
+  priv->drm_device = -1;
+}
+
+static void
+gst_vaapi_display_drm_class_init (GstVaapiDisplayDRMClass * klass)
+{
+  GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass);
+
+  dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_DRM;
+  dpy_class->bind_display = gst_vaapi_display_drm_bind_display;
+  dpy_class->open_display = gst_vaapi_display_drm_open_display;
+  dpy_class->close_display = gst_vaapi_display_drm_close_display;
+  dpy_class->get_display = gst_vaapi_display_drm_get_display_info;
+  dpy_class->create_window = gst_vaapi_display_drm_create_window;
+}
+
+/**
+ * gst_vaapi_display_drm_new:
+ * @device_path: the DRM device path
+ *
+ * Opens an DRM file descriptor using @device_path and returns a newly
+ * allocated #GstVaapiDisplay object. The DRM display will be cloed
+ * when the reference count of the object reaches zero.
+ *
+ * If @device_path is NULL, the DRM device path will be automatically
+ * determined as the first positive match in the list of available DRM
+ * devices.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_drm_new (const gchar * device_path)
+{
+  GstVaapiDisplay *display;
+  guint types[3], i, num_types = 0;
+  gpointer device_paths[3];
+
+  g_mutex_lock (&g_drm_device_type_lock);
+  if (device_path) {
+    device_paths[num_types] = (gpointer) device_path;
+    types[num_types++] = 0;
+  } else if (g_drm_device_type) {
+    device_paths[num_types] = (gpointer) device_path;
+    types[num_types++] = g_drm_device_type;
+  } else {
+    const gchar *user_choice = g_getenv ("GST_VAAPI_DRM_DEVICE");
+
+    if (user_choice) {
+      device_paths[num_types] = (gpointer) user_choice;
+      types[num_types++] = 0;
+    } else {
+      device_paths[num_types] = (gpointer) device_path;
+      types[num_types++] = DRM_DEVICE_RENDERNODES;
+      device_paths[num_types] = (gpointer) device_path;
+      types[num_types++] = DRM_DEVICE_LEGACY;
+    }
+  }
+
+  for (i = 0; i < num_types; i++) {
+    g_drm_device_type = types[i];
+    display = g_object_new (GST_TYPE_VAAPI_DISPLAY_DRM, NULL);
+    display = gst_vaapi_display_config (display,
+        GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, device_paths[i]);
+    if (display || device_path)
+      break;
+  }
+  g_mutex_unlock (&g_drm_device_type_lock);
+  return display;
+}
+
+/**
+ * gst_vaapi_display_drm_new_with_device:
+ * @device: an open DRM device (file descriptor)
+ *
+ * Creates a #GstVaapiDisplay based on the open DRM @device. The
+ * caller still owns the device file descriptor and must call close()
+ * when all #GstVaapiDisplay references are released. Doing so too
+ * early can yield undefined behaviour.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_drm_new_with_device (gint device)
+{
+  GstVaapiDisplay *display;
+
+  g_return_val_if_fail (device >= 0, NULL);
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_DRM, NULL);
+  return gst_vaapi_display_config (display,
+      GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, GINT_TO_POINTER (device));
+}
+
+/**
+ * gst_vaapi_display_drm_new_with_va_display:
+ * @va_display: a VADisplay #va_display
+ * @fd: an open DRM device (file descriptor) #fd
+ *
+ * Creates a #GstVaapiDisplay based on the VADisplay @va_display and
+ * the open DRM device @fd.
+ * The caller still owns the device file descriptor and must call close()
+ * when all #GstVaapiDisplay references are released.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+
+GstVaapiDisplay *
+gst_vaapi_display_drm_new_with_va_display (VADisplay va_display, gint fd)
+{
+  GstVaapiDisplay *display;
+  GstVaapiDisplayInfo info = {
+    .va_display = va_display,
+    .native_display = GINT_TO_POINTER (fd),
+  };
+
+  g_return_val_if_fail (fd >= 0, NULL);
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_DRM, NULL);
+  if (!gst_vaapi_display_config (display,
+          GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info)) {
+    gst_object_unref (display);
+    return NULL;
+  }
+
+  return display;
+}
+
+/**
+ * gst_vaapi_display_drm_get_device:
+ * @display: a #GstVaapiDisplayDRM
+ *
+ * Returns the underlying DRM device file descriptor that was created
+ * by gst_vaapi_display_drm_new() or that was bound from
+ * gst_vaapi_display_drm_new_with_device().
+ *
+ * Return value: the DRM file descriptor attached to @display
+ */
+gint
+gst_vaapi_display_drm_get_device (GstVaapiDisplayDRM * display)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_DRM (display), -1);
+
+  return GST_VAAPI_DISPLAY_DRM_DEVICE (display);
+}
+
+/**
+ * gst_vaapi_display_drm_get_device_path:
+ * @display: a #GstVaapiDisplayDRM
+ *
+ * Returns the underlying DRM device path name was created by
+ * gst_vaapi_display_drm_new() or that was bound from
+ * gst_vaapi_display_drm_new_with_device().
+ *
+ * Note: the #GstVaapiDisplayDRM object owns the resulting string, so
+ * it shall not be deallocated.
+ *
+ * Return value: the DRM device path name attached to @display
+ */
+const gchar *
+gst_vaapi_display_drm_get_device_path (GstVaapiDisplayDRM * display)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_DRM (display), NULL);
+
+  return get_device_path (GST_VAAPI_DISPLAY_CAST (display));
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_drm.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_drm.h
new file mode 100644 (file)
index 0000000..199c6ea
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  gstvaapidisplay_drm.h - VA/DRM display abstraction
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_DRM_H
+#define GST_VAAPI_DISPLAY_DRM_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DISPLAY_DRM              (gst_vaapi_display_drm_get_type ())
+#define GST_VAAPI_DISPLAY_DRM(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_DRM, GstVaapiDisplayDRM))
+
+typedef struct _GstVaapiDisplayDRM              GstVaapiDisplayDRM;
+
+GstVaapiDisplay *
+gst_vaapi_display_drm_new (const gchar * device_path);
+
+GstVaapiDisplay *
+gst_vaapi_display_drm_new_with_device (gint device);
+
+GstVaapiDisplay *
+gst_vaapi_display_drm_new_with_va_display (VADisplay va_display, gint fd);
+
+gint
+gst_vaapi_display_drm_get_device (GstVaapiDisplayDRM * display);
+
+const gchar *
+gst_vaapi_display_drm_get_device_path (GstVaapiDisplayDRM *
+    display);
+
+GType
+gst_vaapi_display_drm_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayDRM, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_DRM_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_drm_priv.h
new file mode 100644 (file)
index 0000000..ef3d255
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *  gstvaapidisplay_drm_priv.h - Internal VA/DRM interface
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_DRM_PRIV_H
+#define GST_VAAPI_DISPLAY_DRM_PRIV_H
+
+#include <gst/vaapi/gstvaapidisplay_drm.h>
+#include "gstvaapidisplay_priv.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_IS_DISPLAY_DRM(display) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_DRM))
+
+#define GST_VAAPI_DISPLAY_DRM_CAST(display) \
+    ((GstVaapiDisplayDRM *)(display))
+
+#define GST_VAAPI_DISPLAY_DRM_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_DRM, GstVaapiDisplayDRMClass))
+
+#define GST_VAAPI_DISPLAY_DRM_PRIVATE(display) \
+    (GST_VAAPI_DISPLAY_DRM_CAST(display)->priv)
+
+typedef struct _GstVaapiDisplayDRMPrivate       GstVaapiDisplayDRMPrivate;
+typedef struct _GstVaapiDisplayDRMClass         GstVaapiDisplayDRMClass;
+
+/**
+ * GST_VAAPI_DISPLAY_DRM_DEVICE:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to the underlying DRM file descriptor of @display
+ */
+#undef  GST_VAAPI_DISPLAY_DRM_DEVICE
+#define GST_VAAPI_DISPLAY_DRM_DEVICE(display) \
+    GST_VAAPI_DISPLAY_DRM_PRIVATE(display)->drm_device
+
+struct _GstVaapiDisplayDRMPrivate
+{
+  gchar *device_path_default;
+  gchar *device_path;
+  gint drm_device;
+  guint use_foreign_display:1;  // Foreign native_display?
+};
+
+/**
+ * GstVaapiDisplayDRM:
+ *
+ * VA/DRM display wrapper.
+ */
+struct _GstVaapiDisplayDRM
+{
+  /*< private >*/
+  GstVaapiDisplay parent_instance;
+
+  GstVaapiDisplayDRMPrivate *priv;
+};
+
+/**
+ * GstVaapiDisplayDRMClass:
+ *
+ * VA/DRM display wrapper clas.
+ */
+struct _GstVaapiDisplayDRMClass
+{
+  /*< private >*/
+  GstVaapiDisplayClass parent_class;
+};
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_DRM_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_egl.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_egl.c
new file mode 100644 (file)
index 0000000..8213908
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ *  gstvaapidisplay_egl.c - VA/EGL display abstraction
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapidisplay_egl.h"
+#include "gstvaapidisplay_egl_priv.h"
+#include "gstvaapiwindow.h"
+#include "gstvaapiwindow_egl.h"
+#include "gstvaapiwindow_priv.h"
+#include "gstvaapitexture_egl.h"
+
+#if GST_VAAPI_USE_X11
+#include "gstvaapidisplay_x11.h"
+#endif
+#if GST_VAAPI_USE_WAYLAND
+#include "gstvaapidisplay_wayland.h"
+#endif
+
+#define DEBUG_VAAPI_DISPLAY 1
+#include "gstvaapidebug.h"
+
+G_DEFINE_TYPE (GstVaapiDisplayEGL, gst_vaapi_display_egl,
+    GST_TYPE_VAAPI_DISPLAY);
+
+/* ------------------------------------------------------------------------- */
+/* --- EGL backend implementation                                        --- */
+/* ------------------------------------------------------------------------- */
+
+typedef struct
+{
+  gpointer display;
+  guint display_type;
+  guint gles_version;
+  gpointer gl_display;
+} InitParams;
+
+static gboolean
+reset_context (GstVaapiDisplayEGL * display, EGLContext gl_context)
+{
+  EglConfig *config;
+  EglContext *ctx;
+
+  egl_object_replace (&display->egl_context, NULL);
+
+  if (gl_context != EGL_NO_CONTEXT)
+    ctx = egl_context_new_wrapped (display->egl_display, gl_context);
+  else {
+    config = egl_config_new (display->egl_display, display->gles_version,
+        GST_VIDEO_FORMAT_RGB);
+    if (!config)
+      return FALSE;
+
+    ctx = egl_context_new (display->egl_display, config, NULL);
+    egl_object_unref (config);
+  }
+  if (!ctx)
+    return FALSE;
+
+  egl_object_replace (&display->egl_context, ctx);
+  egl_object_unref (ctx);
+  return TRUE;
+}
+
+static inline gboolean
+ensure_context (GstVaapiDisplayEGL * display)
+{
+  return display->egl_context || reset_context (display, EGL_NO_CONTEXT);
+}
+
+static inline gboolean
+ensure_context_is_wrapped (GstVaapiDisplayEGL * display, EGLContext gl_context)
+{
+  return (display->egl_context &&
+      display->egl_context->base.handle.p == gl_context) ||
+      reset_context (display, gl_context);
+}
+
+static gboolean
+gst_vaapi_display_egl_bind_display (GstVaapiDisplay * base_display,
+    gpointer native_params)
+{
+  GstVaapiDisplay *native_vaapi_display;
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  EglDisplay *egl_display;
+  EGLDisplay *native_egl_display;
+  guint gl_platform = EGL_PLATFORM_UNKNOWN;
+  const InitParams *params = (InitParams *) native_params;
+  GstVaapiDisplayPrivate *const priv = GST_VAAPI_DISPLAY_GET_PRIVATE (display);
+
+  native_vaapi_display = params->display;
+  native_egl_display = params->gl_display;
+
+  if (!native_vaapi_display) {
+#if GST_VAAPI_USE_X11
+    if (params->display_type == GST_VAAPI_DISPLAY_TYPE_ANY
+        || params->display_type == GST_VAAPI_DISPLAY_TYPE_X11
+        || params->display_type == GST_VAAPI_DISPLAY_TYPE_EGL)
+      native_vaapi_display = gst_vaapi_display_x11_new (NULL);
+#endif
+#if GST_VAAPI_USE_WAYLAND
+    if (!native_vaapi_display)
+      native_vaapi_display = gst_vaapi_display_wayland_new (NULL);
+#endif
+  } else {
+    /* thus it could be assigned to parent */
+    gst_object_ref (native_vaapi_display);
+  }
+  if (!native_vaapi_display)
+    return FALSE;
+
+  gst_vaapi_display_replace (&display->display, native_vaapi_display);
+  priv->parent = native_vaapi_display;
+
+  switch (GST_VAAPI_DISPLAY_GET_CLASS_TYPE (display->display)) {
+    case GST_VAAPI_DISPLAY_TYPE_X11:
+      gl_platform = EGL_PLATFORM_X11;
+      break;
+    case GST_VAAPI_DISPLAY_TYPE_WAYLAND:
+      gl_platform = EGL_PLATFORM_WAYLAND;
+      break;
+    default:
+      break;
+  }
+
+  if (native_egl_display) {
+    egl_display = egl_display_new_wrapped (native_egl_display);
+  } else {
+    egl_display = egl_display_new (GST_VAAPI_DISPLAY_NATIVE (display->display),
+        gl_platform);
+  }
+  if (!egl_display)
+    return FALSE;
+
+  egl_object_replace (&display->egl_display, egl_display);
+  egl_object_unref (egl_display);
+  display->gles_version = params->gles_version;
+  return TRUE;
+}
+
+static void
+gst_vaapi_display_egl_close_display (GstVaapiDisplay * base_display)
+{
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  gst_vaapi_display_replace (&display->display, NULL);
+}
+
+static void
+gst_vaapi_display_egl_lock (GstVaapiDisplay * base_display)
+{
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  GstVaapiDisplayClass *const klass =
+      GST_VAAPI_DISPLAY_GET_CLASS (display->display);
+
+  if (klass->lock)
+    klass->lock (display->display);
+}
+
+static void
+gst_vaapi_display_egl_unlock (GstVaapiDisplay * base_display)
+{
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  GstVaapiDisplayClass *const klass =
+      GST_VAAPI_DISPLAY_GET_CLASS (display->display);
+
+  if (klass->unlock)
+    klass->unlock (display->display);
+}
+
+static void
+gst_vaapi_display_egl_sync (GstVaapiDisplay * base_display)
+{
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  GstVaapiDisplayClass *const klass =
+      GST_VAAPI_DISPLAY_GET_CLASS (display->display);
+
+  if (klass->sync)
+    klass->sync (display->display);
+  else if (klass->flush)
+    klass->flush (display->display);
+}
+
+static void
+gst_vaapi_display_egl_flush (GstVaapiDisplay * base_display)
+{
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  GstVaapiDisplayClass *const klass =
+      GST_VAAPI_DISPLAY_GET_CLASS (display->display);
+
+  if (klass->flush)
+    klass->flush (display->display);
+}
+
+static gboolean
+gst_vaapi_display_egl_get_display_info (GstVaapiDisplay * base_display,
+    GstVaapiDisplayInfo * info)
+{
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  GstVaapiDisplayClass *const klass =
+      GST_VAAPI_DISPLAY_GET_CLASS (display->display);
+
+  info->va_display = GST_VAAPI_DISPLAY_VADISPLAY (display->display);
+
+  if (klass->get_display && !klass->get_display (display->display, info))
+    return FALSE;
+  return TRUE;
+}
+
+static void
+gst_vaapi_display_egl_get_size (GstVaapiDisplay * base_display,
+    guint * width_ptr, guint * height_ptr)
+{
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  GstVaapiDisplayClass *const klass =
+      GST_VAAPI_DISPLAY_GET_CLASS (display->display);
+
+  if (klass->get_size)
+    klass->get_size (display->display, width_ptr, height_ptr);
+}
+
+static void
+gst_vaapi_display_egl_get_size_mm (GstVaapiDisplay * base_display,
+    guint * width_ptr, guint * height_ptr)
+{
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  GstVaapiDisplayClass *const klass =
+      GST_VAAPI_DISPLAY_GET_CLASS (display->display);
+
+  if (klass->get_size_mm)
+    klass->get_size_mm (display->display, width_ptr, height_ptr);
+}
+
+static guintptr
+gst_vaapi_display_egl_get_visual_id (GstVaapiDisplay * base_display,
+    GstVaapiWindow * window)
+{
+  GstVaapiDisplayEGL *display = GST_VAAPI_DISPLAY_EGL (base_display);
+  if (!ensure_context (display))
+    return 0;
+  return display->egl_context->config->visual_id;
+}
+
+static GstVaapiWindow *
+gst_vaapi_display_egl_create_window (GstVaapiDisplay * display, GstVaapiID id,
+    guint width, guint height)
+{
+  if (id != GST_VAAPI_ID_INVALID)
+    return NULL;
+  return gst_vaapi_window_egl_new (display, width, height);
+}
+
+static void
+ensure_texture_map (GstVaapiDisplayEGL * display)
+{
+  if (!display->texture_map)
+    display->texture_map = gst_vaapi_texture_map_new ();
+}
+
+static GstVaapiTexture *
+gst_vaapi_display_egl_create_texture (GstVaapiDisplay * display, GstVaapiID id,
+    guint target, guint format, guint width, guint height)
+{
+  GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (display);
+  GstVaapiTexture *texture;
+
+  if (id == GST_VAAPI_ID_INVALID)
+    return gst_vaapi_texture_egl_new (display, target, format, width, height);
+
+  ensure_texture_map (dpy);
+  if (!(texture = gst_vaapi_texture_map_lookup (dpy->texture_map, id))) {
+    if ((texture =
+            gst_vaapi_texture_egl_new_wrapped (display, id, target, format,
+                width, height))) {
+      gst_vaapi_texture_map_add (dpy->texture_map, texture, id);
+    }
+  }
+
+  return texture;
+}
+
+static GstVaapiTextureMap *
+gst_vaapi_display_egl_get_texture_map (GstVaapiDisplay * display)
+{
+  return GST_VAAPI_DISPLAY_EGL (display)->texture_map;
+}
+
+static void
+gst_vaapi_display_egl_finalize (GObject * object)
+{
+  GstVaapiDisplayEGL *dpy = GST_VAAPI_DISPLAY_EGL (object);
+
+  if (dpy->texture_map)
+    gst_object_unref (dpy->texture_map);
+
+  /* HACK to avoid to call twice vaTerminate() since this and the
+   * proxied display share the same vaDisplay */
+  GST_VAAPI_DISPLAY_VADISPLAY (object) = NULL;
+
+  egl_object_replace (&dpy->egl_display, NULL);
+  egl_object_replace (&dpy->egl_context, NULL);
+
+  gst_vaapi_display_replace (&dpy->display, NULL);
+
+  G_OBJECT_CLASS (gst_vaapi_display_egl_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_display_egl_init (GstVaapiDisplayEGL * display)
+{
+}
+
+static void
+gst_vaapi_display_egl_class_init (GstVaapiDisplayEGLClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_display_egl_finalize;
+  dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_EGL;
+  dpy_class->bind_display = gst_vaapi_display_egl_bind_display;
+  dpy_class->close_display = gst_vaapi_display_egl_close_display;
+  dpy_class->lock = gst_vaapi_display_egl_lock;
+  dpy_class->unlock = gst_vaapi_display_egl_unlock;
+  dpy_class->sync = gst_vaapi_display_egl_sync;
+  dpy_class->flush = gst_vaapi_display_egl_flush;
+  dpy_class->get_display = gst_vaapi_display_egl_get_display_info;
+  dpy_class->get_size = gst_vaapi_display_egl_get_size;
+  dpy_class->get_size_mm = gst_vaapi_display_egl_get_size_mm;
+  dpy_class->get_visual_id = gst_vaapi_display_egl_get_visual_id;
+  dpy_class->create_window = gst_vaapi_display_egl_create_window;
+  dpy_class->create_texture = gst_vaapi_display_egl_create_texture;
+  dpy_class->get_texture_map = gst_vaapi_display_egl_get_texture_map;
+}
+
+/**
+ * gst_vaapi_display_egl_new:
+ * @display: a #GstVaapiDisplay, or %NULL to pick any one
+ * @gles_version: the OpenGL ES version API to use
+ *
+ * Creates a new #GstVaapiDisplay object suitable in EGL context. If
+ * the native @display is %NULL, then any type of display is picked,
+ * i.e. one that can be successfully opened. The @gles_version will
+ * further ensure the OpenGL ES API to use, or zero to indicate
+ * "desktop" OpenGL.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_egl_new (GstVaapiDisplay * display, guint gles_version)
+{
+  GstVaapiDisplay *wrapper_display;
+  InitParams params = {
+    .gles_version = gles_version,
+  };
+
+  if (display) {
+    params.display = display;
+    params.display_type = GST_VAAPI_DISPLAY_VADISPLAY_TYPE (display);
+  }
+
+  wrapper_display = g_object_new (GST_TYPE_VAAPI_DISPLAY_EGL, NULL);
+  return gst_vaapi_display_config (wrapper_display,
+      GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, &params);
+}
+
+/**
+ * gst_vaapi_display_egl_new_with_native_display:
+ * @native_display: an EGLDisplay object
+ * @display_type: the display type of @native_display
+ * @gles_version: the OpenGL ES version API to use
+ *
+ * Creates a #GstVaapiDisplay based on the native display supplied in
+ * as @native_display. The caller still owns the display and must call
+ * native display close function when all #GstVaapiDisplay references
+ * are released. Doing so too early can yield undefined behaviour.
+ *
+ * The @gles_version will further ensure the OpenGL ES API to use, or
+ * zero to indicate "desktop" OpenGL.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_egl_new_with_native_display (gpointer native_display,
+    GstVaapiDisplayType display_type, guint gles_version)
+{
+  GstVaapiDisplay *display;
+  InitParams params = {
+    .display_type = display_type,
+    .gl_display = native_display,
+    .gles_version = gles_version,
+  };
+
+  g_return_val_if_fail (native_display != NULL, NULL);
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_EGL, NULL);
+  return gst_vaapi_display_config (display,
+      GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, &params);
+}
+
+EglContext *
+gst_vaapi_display_egl_get_context (GstVaapiDisplayEGL * display)
+{
+  return ensure_context (display) ? display->egl_context : NULL;
+}
+
+EGLDisplay
+gst_vaapi_display_egl_get_gl_display (GstVaapiDisplayEGL * display)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), EGL_NO_DISPLAY);
+
+  return display->egl_display->base.handle.p;
+}
+
+EGLContext
+gst_vaapi_display_egl_get_gl_context (GstVaapiDisplayEGL * display)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), EGL_NO_CONTEXT);
+
+  return ensure_context (display) ? display->egl_context->base.handle.p :
+      EGL_NO_CONTEXT;
+}
+
+gboolean
+gst_vaapi_display_egl_set_gl_context (GstVaapiDisplayEGL * display,
+    EGLContext gl_context)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), FALSE);
+
+  return ensure_context_is_wrapped (display, gl_context);
+}
+
+gboolean
+gst_vaapi_display_egl_set_current_display (GstVaapiDisplayEGL * display)
+{
+  EglDisplay *egl_display;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), FALSE);
+
+  if (G_UNLIKELY (eglGetCurrentDisplay () == EGL_NO_DISPLAY))
+    return TRUE;
+  if (G_LIKELY (display->egl_display->base.handle.p == eglGetCurrentDisplay ()))
+    return TRUE;
+
+  egl_display = egl_display_new_wrapped (eglGetCurrentDisplay ());
+  if (!egl_display)
+    return FALSE;
+  egl_object_replace (&display->egl_display, egl_display);
+  egl_object_unref (egl_display);
+  if (!gst_vaapi_display_egl_set_gl_context (display, eglGetCurrentContext ()))
+    return FALSE;
+
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_egl.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_egl.h
new file mode 100644 (file)
index 0000000..07fbf83
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ *  gstvaapidisplay_egl.h - VA/EGL display abstraction
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) egl later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT EGL WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_EGL_H
+#define GST_VAAPI_DISPLAY_EGL_H
+
+#include <EGL/egl.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiDisplayEGL GstVaapiDisplayEGL;
+
+#define GST_TYPE_VAAPI_DISPLAY_EGL              (gst_vaapi_display_egl_get_type ())
+#define GST_VAAPI_DISPLAY_EGL(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_EGL, GstVaapiDisplayEGL))
+
+GstVaapiDisplay *
+gst_vaapi_display_egl_new (GstVaapiDisplay * display, guint gles_version);
+
+GstVaapiDisplay *
+gst_vaapi_display_egl_new_with_native_display (gpointer native_display,
+    GstVaapiDisplayType display_type, guint gles_version);
+
+EGLDisplay
+gst_vaapi_display_egl_get_gl_display (GstVaapiDisplayEGL * display);
+
+EGLContext
+gst_vaapi_display_egl_get_gl_context (GstVaapiDisplayEGL * display);
+
+gboolean
+gst_vaapi_display_egl_set_gl_context (GstVaapiDisplayEGL * display,
+    EGLContext gl_context);
+
+gboolean
+gst_vaapi_display_egl_set_current_display (GstVaapiDisplayEGL * display);
+
+GType
+gst_vaapi_display_egl_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayEGL, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_EGL_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_egl_priv.h
new file mode 100644 (file)
index 0000000..e99c54b
--- /dev/null
@@ -0,0 +1,105 @@
+/*
+ *  gstvaapidisplay_egl_priv.h - Internal VA/EGL interface
+ *
+ *  Copyright (C) 2014 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_EGL_PRIV_H
+#define GST_VAAPI_DISPLAY_EGL_PRIV_H
+
+#include <gst/vaapi/gstvaapiwindow.h>
+#include <gst/vaapi/gstvaapitexturemap.h>
+#include "gstvaapidisplay_egl.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapiutils_egl.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_IS_DISPLAY_EGL(display) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_EGL))
+
+#define GST_VAAPI_DISPLAY_EGL_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DISPLAY_EGL, GstVaapiDisplayEGLClass))
+
+#define GST_VAAPI_DISPLAY_EGL_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_EGL, GstVaapiDisplayEGLClass))
+
+#define GST_VAAPI_DISPLAY_EGL_CAST(obj) \
+    ((GstVaapiDisplayEGL *)(obj))
+
+/**
+ * GST_VAAPI_DISPLAY_EGL_DISPLAY:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to #EglDisplay wrapper for @display.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DISPLAY_EGL_DISPLAY
+#define GST_VAAPI_DISPLAY_EGL_DISPLAY(display) \
+  (GST_VAAPI_DISPLAY_EGL_CAST (display)->egl_display)
+
+/**
+ * GST_VAAPI_DISPLAY_EGL_CONTEXT:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to #EglContext wrapper for @display.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DISPLAY_EGL_CONTEXT
+#define GST_VAAPI_DISPLAY_EGL_CONTEXT(display) \
+  gst_vaapi_display_egl_get_context (GST_VAAPI_DISPLAY_EGL (display))
+
+typedef struct _GstVaapiDisplayEGLClass GstVaapiDisplayEGLClass;
+
+/**
+ * GstVaapiDisplayEGL:
+ *
+ * VA/EGL display wrapper.
+ */
+struct _GstVaapiDisplayEGL
+{
+  /*< private >*/
+  GstVaapiDisplay parent_instance;
+
+  gpointer loader;
+  GstVaapiDisplay *display;
+  EglDisplay *egl_display;
+  EglContext *egl_context;
+  guint gles_version;
+  GstVaapiTextureMap *texture_map;
+};
+
+/**
+ * GstVaapiDisplayEGLClass:
+ *
+ * VA/EGL display wrapper clas.
+ */
+struct _GstVaapiDisplayEGLClass
+{
+  /*< private >*/
+  GstVaapiDisplayClass parent_class;
+};
+
+G_GNUC_INTERNAL
+EglContext *
+gst_vaapi_display_egl_get_context (GstVaapiDisplayEGL * display);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_EGL_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_glx.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_glx.c
new file mode 100644 (file)
index 0000000..f75ab90
--- /dev/null
@@ -0,0 +1,159 @@
+/*
+ *  gstvaapidisplay_glx.c - VA/GLX display abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidisplay_glx
+ * @short_description: VA/GLX display abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiutils_glx.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapidisplay_x11_priv.h"
+#include "gstvaapidisplay_glx.h"
+#include "gstvaapidisplay_glx_priv.h"
+#include "gstvaapiwindow_glx.h"
+#include "gstvaapitexture_glx.h"
+
+#define DEBUG_VAAPI_DISPLAY 1
+#include "gstvaapidebug.h"
+
+G_DEFINE_TYPE (GstVaapiDisplayGLX, gst_vaapi_display_glx,
+    GST_TYPE_VAAPI_DISPLAY_X11);
+
+static GstVaapiWindow *
+gst_vaapi_display_glx_create_window (GstVaapiDisplay * display, GstVaapiID id,
+    guint width, guint height)
+{
+  return id != GST_VAAPI_ID_INVALID ?
+      gst_vaapi_window_glx_new_with_xid (display, id) :
+      gst_vaapi_window_glx_new (display, width, height);
+}
+
+static void
+ensure_texture_map (GstVaapiDisplayGLX * display)
+{
+  if (!display->texture_map)
+    display->texture_map = gst_vaapi_texture_map_new ();
+}
+
+static GstVaapiTexture *
+gst_vaapi_display_glx_create_texture (GstVaapiDisplay * display, GstVaapiID id,
+    guint target, guint format, guint width, guint height)
+{
+  GstVaapiTexture *texture;
+  GstVaapiDisplayGLX *dpy = GST_VAAPI_DISPLAY_GLX (display);
+
+  if (id == GST_VAAPI_ID_INVALID)
+    return gst_vaapi_texture_glx_new (display, target, format, width, height);
+
+  ensure_texture_map (dpy);
+  if (!(texture = gst_vaapi_texture_map_lookup (dpy->texture_map, id))) {
+    if ((texture =
+            gst_vaapi_texture_glx_new_wrapped (display, id, target, format))) {
+      gst_vaapi_texture_map_add (dpy->texture_map, texture, id);
+    }
+  }
+
+  return texture;
+}
+
+static GstVaapiTextureMap *
+gst_vaapi_display_glx_get_texture_map (GstVaapiDisplay * display)
+{
+  return GST_VAAPI_DISPLAY_GLX (display)->texture_map;
+}
+
+static void
+gst_vaapi_display_glx_finalize (GObject * object)
+{
+  GstVaapiDisplayGLX *dpy = GST_VAAPI_DISPLAY_GLX (object);
+
+  if (dpy->texture_map)
+    gst_object_unref (dpy->texture_map);
+  G_OBJECT_CLASS (gst_vaapi_display_glx_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_display_glx_init (GstVaapiDisplayGLX * display)
+{
+}
+
+static void
+gst_vaapi_display_glx_class_init (GstVaapiDisplayGLXClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_display_glx_finalize;
+  dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_GLX;
+  dpy_class->create_window = gst_vaapi_display_glx_create_window;
+  dpy_class->create_texture = gst_vaapi_display_glx_create_texture;
+  dpy_class->get_texture_map = gst_vaapi_display_glx_get_texture_map;
+}
+
+/**
+ * gst_vaapi_display_glx_new:
+ * @display_name: the X11 display name
+ *
+ * Opens an X11 #Display using @display_name and returns a newly
+ * allocated #GstVaapiDisplay object. The X11 display will be cloed
+ * when the reference count of the object reaches zero.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_glx_new (const gchar * display_name)
+{
+  GstVaapiDisplay *display;
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_GLX, NULL);
+  return gst_vaapi_display_config (display,
+      GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer) display_name);
+}
+
+/**
+ * gst_vaapi_display_glx_new_with_display:
+ * @x11_display: an X11 #Display
+ *
+ * Creates a #GstVaapiDisplay based on the X11 @x11_display
+ * display. The caller still owns the display and must call
+ * XCloseDisplay() when all #GstVaapiDisplay references are
+ * released. Doing so too early can yield undefined behaviour.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_glx_new_with_display (Display * x11_display)
+{
+  GstVaapiDisplay *display;
+
+  g_return_val_if_fail (x11_display != NULL, NULL);
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_GLX, NULL);
+  return gst_vaapi_display_config (display,
+      GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, x11_display);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_glx.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_glx.h
new file mode 100644 (file)
index 0000000..c4bdcc9
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  gstvaapidisplay_glx.h - VA/GLX display abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_GLX_H
+#define GST_VAAPI_DISPLAY_GLX_H
+
+#include <gst/vaapi/gstvaapidisplay_x11.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DISPLAY_GLX              (gst_vaapi_display_glx_get_type ())
+#define GST_VAAPI_DISPLAY_GLX(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_GLX, GstVaapiDisplayGLX))
+
+typedef struct _GstVaapiDisplayGLX              GstVaapiDisplayGLX;
+
+GstVaapiDisplay *
+gst_vaapi_display_glx_new (const gchar * display_name);
+
+GstVaapiDisplay *
+gst_vaapi_display_glx_new_with_display (Display * x11_display);
+
+GType
+gst_vaapi_display_glx_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayGLX, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_GLX_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_glx_priv.h
new file mode 100644 (file)
index 0000000..a715175
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  gstvaapidisplay_glx_priv.h - Internal VA/GLX interface
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_GLX_PRIV_H
+#define GST_VAAPI_DISPLAY_GLX_PRIV_H
+
+#include <gst/vaapi/gstvaapiutils_glx.h>
+#include <gst/vaapi/gstvaapidisplay_glx.h>
+#include <gst/vaapi/gstvaapitexturemap.h>
+#include "gstvaapidisplay_x11_priv.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_IS_DISPLAY_GLX(display) \
+   (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_GLX))
+
+#define GST_VAAPI_DISPLAY_GLX_CAST(display) \
+    ((GstVaapiDisplayGLX *)(display))
+
+#define GST_VAAPI_DISPLAY_GLX_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DISPLAY_GLX, GstVaapiDisplayGLXClass))
+
+#define GST_VAAPI_DISPLAY_GLX_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_GLX, GstVaapiDisplayGLXClass))
+
+typedef struct _GstVaapiDisplayGLXClass         GstVaapiDisplayGLXClass;
+
+/**
+ * GstVaapiDisplayGLX:
+ *
+ * VA/GLX display wrapper.
+ */
+struct _GstVaapiDisplayGLX
+{
+  /*< private >*/
+  GstVaapiDisplayX11 parent_instance;
+  GstVaapiTextureMap *texture_map;
+};
+
+/**
+ * GstVaapiDisplayGLXClass:
+ *
+ * VA/GLX display wrapper clas.
+ */
+struct _GstVaapiDisplayGLXClass
+{
+  /*< private >*/
+  GstVaapiDisplayX11Class parent_class;
+};
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_GLX_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_priv.h
new file mode 100644 (file)
index 0000000..b8cb2bd
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ *  gstvaapidisplay_priv.h - Base VA display (private definitions)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_PRIV_H
+#define GST_VAAPI_DISPLAY_PRIV_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+#include <gst/vaapi/gstvaapitexture.h>
+#include <gst/vaapi/gstvaapitexturemap.h>
+#include "gstvaapiminiobject.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_DISPLAY_CAST(display) \
+    ((GstVaapiDisplay *)(display))
+
+#define GST_VAAPI_DISPLAY_GET_PRIVATE(display) \
+    (GST_VAAPI_DISPLAY_CAST (display)->priv)
+
+#define GST_VAAPI_DISPLAY_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DISPLAY, GstVaapiDisplayClass))
+
+#define GST_VAAPI_IS_DISPLAY_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_DISPLAY))
+
+#define GST_VAAPI_DISPLAY_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY, GstVaapiDisplayClass))
+
+typedef struct _GstVaapiDisplayPrivate          GstVaapiDisplayPrivate;
+typedef struct _GstVaapiDisplayClass            GstVaapiDisplayClass;
+typedef enum _GstVaapiDisplayInitType           GstVaapiDisplayInitType;
+
+/**
+ * GST_VAAPI_DISPLAY_GET_CLASS_TYPE:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the #display class type
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DISPLAY_GET_CLASS_TYPE
+#define GST_VAAPI_DISPLAY_GET_CLASS_TYPE(display) \
+  (GST_VAAPI_DISPLAY_GET_CLASS (display)->display_type)
+
+/**
+ * GST_VAAPI_DISPLAY_NATIVE:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to the native display of @display.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DISPLAY_NATIVE
+#define GST_VAAPI_DISPLAY_NATIVE(display) \
+  (GST_VAAPI_DISPLAY_GET_PRIVATE (display)->native_display)
+
+/**
+ * GST_VAAPI_DISPLAY_VADISPLAY:
+ * @display_: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to the #VADisplay of @display_.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DISPLAY_VADISPLAY
+#define GST_VAAPI_DISPLAY_VADISPLAY(display_) \
+  (GST_VAAPI_DISPLAY_GET_PRIVATE (display_)->display)
+
+/**
+ * GST_VAAPI_DISPLAY_VADISPLAY_TYPE:
+ * @display: a #GstVaapiDisplay
+ *
+ * Returns the underlying VADisplay @display type
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DISPLAY_VADISPLAY_TYPE
+#define GST_VAAPI_DISPLAY_VADISPLAY_TYPE(display) \
+  (GST_VAAPI_DISPLAY_GET_CLASS (display)->display_type)
+
+/**
+ * GST_VAAPI_DISPLAY_HAS_VPP:
+ * @display: a @GstVaapiDisplay
+ *
+ * Returns whether the @display supports video processing (VA/VPP)
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_DISPLAY_HAS_VPP
+#define GST_VAAPI_DISPLAY_HAS_VPP(display) \
+  gst_vaapi_display_has_video_processing (GST_VAAPI_DISPLAY_CAST (display))
+
+struct _GstVaapiDisplayPrivate
+{
+  GstVaapiDisplay *parent;
+  GRecMutex mutex;
+  gchar *display_name;
+  VADisplay display;
+  gpointer native_display;
+  guint width;
+  guint height;
+  guint width_mm;
+  guint height_mm;
+  guint par_n;
+  guint par_d;
+  GPtrArray *decoders; /* ref element in codecs */
+  GPtrArray *encoders; /* ref element in codecs */
+  GArray *codecs;
+  GArray *image_formats;
+  GArray *subpicture_formats;
+  GArray *properties;
+  gchar *vendor_string;
+  guint use_foreign_display:1;
+  guint has_vpp:1;
+  guint has_profiles:1;
+  guint got_scrres:1;
+  guint driver_quirks;
+};
+
+/**
+ * GstVaapiDisplay:
+ *
+ * Base class for VA displays.
+ */
+struct _GstVaapiDisplay
+{
+  /*< private >*/
+  GstObject parent_instance;
+
+  GstVaapiDisplayPrivate *priv;
+};
+
+/**
+ * GstVaapiDisplayClass:
+ * @open_display: virtual function to open a display
+ * @close_display: virtual function to close a display
+ * @lock: (optional) virtual function to lock a display
+ * @unlock: (optional) virtual function to unlock a display
+ * @sync: (optional) virtual function to sync a display
+ * @flush: (optional) virtual function to flush pending requests of a display
+ * @get_display: virtual function to retrieve the #GstVaapiDisplayInfo
+ * @get_size: virtual function to retrieve the display dimensions, in pixels
+ * @get_size_mm: virtual function to retrieve the display dimensions, in millimeters
+ * @get_visual_id: (optional) virtual function to retrieve the window visual id
+ * @get_colormap: (optional) virtual function to retrieve the window colormap
+ * @create_window: (optional) virtual function to create a window
+ * @create_texture: (optional) virtual function to create a texture
+ * @get_texture_map: (optional) virtual function to get texture map
+ *
+ * Base class for VA displays.
+ */
+struct _GstVaapiDisplayClass
+{
+  /*< private >*/
+  GstObjectClass parent_class;
+
+  /*< protected >*/
+  guint display_type;
+
+  /*< public >*/
+  void                (*init)            (GstVaapiDisplay * display);
+  gboolean            (*bind_display)    (GstVaapiDisplay * display, gpointer native_dpy);
+  gboolean            (*open_display)    (GstVaapiDisplay * display, const gchar * name);
+  void                (*close_display)   (GstVaapiDisplay * display);
+  void                (*lock)            (GstVaapiDisplay * display);
+  void                (*unlock)          (GstVaapiDisplay * display);
+  void                (*sync)            (GstVaapiDisplay * display);
+  void                (*flush)           (GstVaapiDisplay * display);
+  gboolean            (*get_display)     (GstVaapiDisplay * display, GstVaapiDisplayInfo * info);
+  void                (*get_size)        (GstVaapiDisplay * display, guint * pwidth, guint * pheight);
+  void                (*get_size_mm)     (GstVaapiDisplay * display, guint * pwidth, guint * pheight);
+  guintptr            (*get_visual_id)   (GstVaapiDisplay * display, GstVaapiWindow * window);
+  guintptr            (*get_colormap)    (GstVaapiDisplay * display, GstVaapiWindow * window);
+  GstVaapiWindow     *(*create_window)   (GstVaapiDisplay * display, GstVaapiID id, guint width, guint height);
+  GstVaapiTexture    *(*create_texture)  (GstVaapiDisplay * display, GstVaapiID id, guint target, guint format,
+    guint width, guint height);
+  GstVaapiTextureMap *(*get_texture_map) (GstVaapiDisplay * display);
+};
+
+/* Initialization types */
+enum _GstVaapiDisplayInitType
+{
+  GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME = 1,
+  GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY,
+  GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY
+};
+
+GstVaapiDisplay *
+gst_vaapi_display_config (GstVaapiDisplay * display,
+    GstVaapiDisplayInitType init_type, gpointer init_value);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_wayland.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_wayland.c
new file mode 100644 (file)
index 0000000..e6e3f39
--- /dev/null
@@ -0,0 +1,457 @@
+/*
+ *  gstvaapidisplay_wayland.c - VA/Wayland display abstraction
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidisplay_wayland
+ * @short_description: VA/Wayland display abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapidisplay_wayland.h"
+#include "gstvaapidisplay_wayland_priv.h"
+#include "gstvaapiwindow_wayland.h"
+
+#define DEBUG_VAAPI_DISPLAY 1
+#include "gstvaapidebug.h"
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiDisplayWayland, gst_vaapi_display_wayland,
+    GST_TYPE_VAAPI_DISPLAY);
+
+static inline const gchar *
+get_default_display_name (void)
+{
+  static const gchar *g_display_name;
+
+  if (!g_display_name)
+    g_display_name = getenv ("WAYLAND_DISPLAY");
+  return g_display_name;
+}
+
+/* Mangle display name with our prefix */
+static gboolean
+set_display_name (GstVaapiDisplay * display, const gchar * display_name)
+{
+  GstVaapiDisplayWaylandPrivate *const priv =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+
+  g_free (priv->display_name);
+
+  if (!display_name) {
+    display_name = get_default_display_name ();
+    if (!display_name)
+      display_name = "";
+  }
+  priv->display_name = g_strdup (display_name);
+  return priv->display_name != NULL;
+}
+
+static void
+output_handle_geometry (void *data, struct wl_output *output,
+    int x, int y, int physical_width, int physical_height,
+    int subpixel, const char *make, const char *model, int transform)
+{
+  GstVaapiDisplayWaylandPrivate *const priv = data;
+
+  priv->phys_width = physical_width;
+  priv->phys_height = physical_height;
+}
+
+static void
+output_handle_mode (void *data, struct wl_output *wl_output,
+    uint32_t flags, int width, int height, int refresh)
+{
+  GstVaapiDisplayWaylandPrivate *const priv = data;
+
+  if (flags & WL_OUTPUT_MODE_CURRENT) {
+    priv->width = width;
+    priv->height = height;
+  }
+}
+
+static const struct wl_output_listener output_listener = {
+  output_handle_geometry,
+  output_handle_mode,
+};
+
+static void
+handle_xdg_wm_base_ping (void *user_data, struct xdg_wm_base *xdg_wm_base,
+    uint32_t serial)
+{
+  xdg_wm_base_pong (xdg_wm_base, serial);
+}
+
+static const struct xdg_wm_base_listener xdg_wm_base_listener = {
+  handle_xdg_wm_base_ping
+};
+
+static void
+dmabuf_format (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
+    uint32_t format)
+{
+}
+
+static void
+dmabuf_modifier (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
+    uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
+{
+  GstVaapiDisplayWaylandPrivate *const priv = data;
+  GstDRMFormat drm_format = {
+    .format = format,
+    .modifier = (guint64) modifier_hi << 32 | modifier_lo
+  };
+
+  if (gst_vaapi_video_format_from_drm_format (format) ==
+      GST_VIDEO_FORMAT_UNKNOWN) {
+    GST_LOG ("ignoring unknown format 0x%x with modifier 0x%" G_GINT64_MODIFIER
+        "x", format, drm_format.modifier);
+    return;
+  }
+
+  GST_LOG ("got format 0x%x (%s) with modifier 0x%" G_GINT64_MODIFIER "x",
+      format, gst_video_format_to_string (gst_vaapi_video_format_from_drm_format
+          (format)), drm_format.modifier);
+
+  g_array_append_val (priv->dmabuf_formats, drm_format);
+}
+
+static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
+  dmabuf_format,
+  dmabuf_modifier,
+};
+
+
+static void
+registry_handle_global (void *data,
+    struct wl_registry *registry,
+    uint32_t id, const char *interface, uint32_t version)
+{
+  GstVaapiDisplayWaylandPrivate *const priv = data;
+
+  if (strcmp (interface, "wl_compositor") == 0)
+    priv->compositor =
+        wl_registry_bind (registry, id, &wl_compositor_interface, 1);
+  else if (strcmp (interface, "wl_subcompositor") == 0)
+    priv->subcompositor =
+        wl_registry_bind (registry, id, &wl_subcompositor_interface, 1);
+  else if (strcmp (interface, "wl_shell") == 0)
+    priv->wl_shell = wl_registry_bind (registry, id, &wl_shell_interface, 1);
+  else if (strcmp (interface, "xdg_wm_base") == 0) {
+    priv->xdg_wm_base =
+        wl_registry_bind (registry, id, &xdg_wm_base_interface, 1);
+    xdg_wm_base_add_listener (priv->xdg_wm_base, &xdg_wm_base_listener, priv);
+  } else if (strcmp (interface, "wl_output") == 0) {
+    if (!priv->output) {
+      priv->output = wl_registry_bind (registry, id, &wl_output_interface, 1);
+      wl_output_add_listener (priv->output, &output_listener, priv);
+    }
+  } else if (strcmp (interface, "zwp_linux_dmabuf_v1") == 0) {
+    priv->dmabuf =
+        wl_registry_bind (registry, id, &zwp_linux_dmabuf_v1_interface, 3);
+    zwp_linux_dmabuf_v1_add_listener (priv->dmabuf, &dmabuf_listener, priv);
+  }
+}
+
+static const struct wl_registry_listener registry_listener = {
+  registry_handle_global,
+  NULL,
+};
+
+static gboolean
+gst_vaapi_display_wayland_setup (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayWaylandPrivate *const priv =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+
+  wl_display_set_user_data (priv->wl_display, priv);
+  priv->registry = wl_display_get_registry (priv->wl_display);
+  wl_registry_add_listener (priv->registry, &registry_listener, priv);
+  priv->event_fd = wl_display_get_fd (priv->wl_display);
+  wl_display_roundtrip (priv->wl_display);
+
+  if (!priv->width || !priv->height) {
+    wl_display_roundtrip (priv->wl_display);
+    if (!priv->width || !priv->height) {
+      GST_ERROR ("failed to determine the display size");
+      return FALSE;
+    }
+  }
+
+  if (!priv->compositor) {
+    GST_ERROR ("failed to bind compositor interface");
+    return FALSE;
+  }
+
+  if (priv->xdg_wm_base)
+    return TRUE;
+
+  if (!priv->wl_shell) {
+    GST_ERROR ("failed to bind wl_shell interface");
+    return FALSE;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_display_wayland_bind_display (GstVaapiDisplay * display,
+    gpointer native_display)
+{
+  GstVaapiDisplayWaylandPrivate *const priv =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+
+  priv->wl_display = native_display;
+  priv->use_foreign_display = TRUE;
+
+  /* XXX: how to get socket/display name? */
+  GST_WARNING ("wayland: get display name");
+  set_display_name (display, NULL);
+
+  return gst_vaapi_display_wayland_setup (display);
+}
+
+static gboolean
+gst_vaapi_display_wayland_open_display (GstVaapiDisplay * display,
+    const gchar * name)
+{
+  GstVaapiDisplayWaylandPrivate *const priv =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+
+  if (!set_display_name (display, name))
+    return FALSE;
+
+  priv->wl_display = wl_display_connect (name);
+  if (!priv->wl_display)
+    return FALSE;
+  priv->use_foreign_display = FALSE;
+
+  return gst_vaapi_display_wayland_setup (display);
+}
+
+static void
+gst_vaapi_display_wayland_close_display (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayWaylandPrivate *const priv =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+
+  g_clear_pointer (&priv->output, wl_output_destroy);
+  g_clear_pointer (&priv->wl_shell, wl_shell_destroy);
+  g_clear_pointer (&priv->xdg_wm_base, xdg_wm_base_destroy);
+  g_clear_pointer (&priv->subcompositor, wl_subcompositor_destroy);
+  g_clear_pointer (&priv->compositor, wl_compositor_destroy);
+  g_clear_pointer (&priv->registry, wl_registry_destroy);
+
+  g_array_unref (priv->dmabuf_formats);
+
+  if (priv->wl_display) {
+    if (!priv->use_foreign_display)
+      wl_display_disconnect (priv->wl_display);
+    priv->wl_display = NULL;
+  }
+
+  g_clear_pointer (&priv->display_name, g_free);
+}
+
+static gboolean
+gst_vaapi_display_wayland_get_display_info (GstVaapiDisplay * display,
+    GstVaapiDisplayInfo * info)
+{
+  GstVaapiDisplayWaylandPrivate *const priv =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+
+  info->native_display = priv->wl_display;
+  info->display_name = priv->display_name;
+  if (!info->va_display) {
+    info->va_display = vaGetDisplayWl (priv->wl_display);
+    if (!info->va_display)
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static void
+gst_vaapi_display_wayland_get_size (GstVaapiDisplay * display,
+    guint * pwidth, guint * pheight)
+{
+  GstVaapiDisplayWaylandPrivate *const priv =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+
+  if (!priv->output)
+    return;
+
+  if (pwidth)
+    *pwidth = priv->width;
+
+  if (pheight)
+    *pheight = priv->height;
+}
+
+static void
+gst_vaapi_display_wayland_get_size_mm (GstVaapiDisplay * display,
+    guint * pwidth, guint * pheight)
+{
+  GstVaapiDisplayWaylandPrivate *const priv =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+
+  if (!priv->output)
+    return;
+
+  if (pwidth)
+    *pwidth = priv->phys_width;
+
+  if (pheight)
+    *pheight = priv->phys_height;
+}
+
+static GstVaapiWindow *
+gst_vaapi_display_wayland_create_window (GstVaapiDisplay * display,
+    GstVaapiID id, guint width, guint height)
+{
+  if (id != GST_VAAPI_ID_INVALID)
+    return NULL;
+  return gst_vaapi_window_wayland_new (display, width, height);
+}
+
+static void
+gst_vaapi_display_wayland_init (GstVaapiDisplayWayland * display)
+{
+  GstVaapiDisplayWaylandPrivate *const priv =
+      gst_vaapi_display_wayland_get_instance_private (display);
+
+  display->priv = priv;
+  priv->event_fd = -1;
+  priv->dmabuf_formats = g_array_new (FALSE, FALSE, sizeof (GstDRMFormat));
+}
+
+static void
+gst_vaapi_display_wayland_class_init (GstVaapiDisplayWaylandClass * klass)
+{
+  GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass);
+
+  dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_WAYLAND;
+
+  dpy_class->bind_display = gst_vaapi_display_wayland_bind_display;
+  dpy_class->open_display = gst_vaapi_display_wayland_open_display;
+  dpy_class->close_display = gst_vaapi_display_wayland_close_display;
+  dpy_class->get_display = gst_vaapi_display_wayland_get_display_info;
+  dpy_class->get_size = gst_vaapi_display_wayland_get_size;
+  dpy_class->get_size_mm = gst_vaapi_display_wayland_get_size_mm;
+  dpy_class->create_window = gst_vaapi_display_wayland_create_window;
+}
+
+/**
+ * gst_vaapi_display_wayland_new:
+ * @display_name: the Wayland display name
+ *
+ * Opens an Wayland #wl_display using @display_name and returns a
+ * newly allocated #GstVaapiDisplay object. The Wayland display will
+ * be cloed when the reference count of the object reaches zero.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_wayland_new (const gchar * display_name)
+{
+  GstVaapiDisplay *display;
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_WAYLAND, NULL);
+  return gst_vaapi_display_config (display,
+      GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer) display_name);
+}
+
+/**
+ * gst_vaapi_display_wayland_new_with_display:
+ * @wl_display: an Wayland #wl_display
+ *
+ * Creates a #GstVaapiDisplay based on the Wayland @wl_display
+ * display. The caller still owns the display and must call
+ * wl_display_disconnect() when all #GstVaapiDisplay references are
+ * released. Doing so too early can yield undefined behaviour.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_wayland_new_with_display (struct wl_display * wl_display)
+{
+  GstVaapiDisplay *display;
+
+  g_return_val_if_fail (wl_display, NULL);
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_WAYLAND, NULL);
+  return gst_vaapi_display_config (display,
+      GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, wl_display);
+}
+
+/**
+ * gst_vaapi_display_wayland_new_with_va_display:
+ * @va_display: a VADisplay #va_display
+ * @wl_display: an Wayland #wl_display
+ *
+ * Creates a #GstVaapiDisplay based on the VADisplay @va_display and
+ * the Wayland @wl_display display.
+ * The caller still owns the display and must call
+ * wl_display_disconnect() when all #GstVaapiDisplay references are
+ * released.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+
+GstVaapiDisplay *
+gst_vaapi_display_wayland_new_with_va_display (VADisplay va_display,
+    struct wl_display * wl_display)
+{
+  GstVaapiDisplay *display;
+  GstVaapiDisplayInfo info = {
+    .va_display = va_display,
+    .native_display = wl_display,
+  };
+
+  g_return_val_if_fail (wl_display, NULL);
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_WAYLAND, NULL);
+  if (!gst_vaapi_display_config (display,
+          GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info)) {
+    gst_object_unref (display);
+    return NULL;
+  }
+
+  return display;
+}
+
+/**
+ * gst_vaapi_display_wayland_get_display:
+ * @display: a #GstVaapiDisplayWayland
+ *
+ * Returns the underlying Wayland #wl_display that was created by
+ * gst_vaapi_display_wayland_new() or that was bound from
+ * gst_vaapi_display_wayland_new_with_display().
+ *
+ * Return value: the Wayland #wl_display attached to @display
+ */
+struct wl_display *
+gst_vaapi_display_wayland_get_display (GstVaapiDisplayWayland * display)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_WAYLAND (display), NULL);
+
+  return GST_VAAPI_DISPLAY_WL_DISPLAY (display);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_wayland.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_wayland.h
new file mode 100644 (file)
index 0000000..1f9ec30
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *  gstvaapidisplay_wayland.h - VA/Wayland display abstraction
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_WAYLAND_H
+#define GST_VAAPI_DISPLAY_WAYLAND_H
+
+#include <va/va_wayland.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DISPLAY_WAYLAND          (gst_vaapi_display_wayland_get_type ())
+#define GST_VAAPI_DISPLAY_WAYLAND(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_WAYLAND, GstVaapiDisplayWayland))
+
+typedef struct _GstVaapiDisplayWayland          GstVaapiDisplayWayland;
+
+GstVaapiDisplay *
+gst_vaapi_display_wayland_new (const gchar * display_name);
+
+GstVaapiDisplay *
+gst_vaapi_display_wayland_new_with_display (struct wl_display * wl_display);
+
+GstVaapiDisplay *
+gst_vaapi_display_wayland_new_with_va_display (VADisplay va_display,
+    struct wl_display * wl_display);
+
+struct wl_display *
+gst_vaapi_display_wayland_get_display (GstVaapiDisplayWayland * display);
+
+GType
+gst_vaapi_display_wayland_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayWayland, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_WAYLAND_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_wayland_priv.h
new file mode 100644 (file)
index 0000000..a4e9992
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *  gstvaapidisplay_wayland_priv.h - Internal VA/Wayland interface
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_WAYLAND_PRIV_H
+#define GST_VAAPI_DISPLAY_WAYLAND_PRIV_H
+
+#include "xdg-shell-client-protocol.h"
+#include "linux-dmabuf-unstable-v1-client-protocol.h"
+
+#include <gst/vaapi/gstvaapidisplay_wayland.h>
+#include "gstvaapidisplay_priv.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_IS_DISPLAY_WAYLAND(display) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_WAYLAND))
+
+#define GST_VAAPI_DISPLAY_WAYLAND_CAST(display) \
+    ((GstVaapiDisplayWayland *)(display))
+
+#define GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE(display) \
+    (GST_VAAPI_DISPLAY_WAYLAND_CAST(display)->priv)
+
+#define GST_VAAPI_DISPLAY_WAYLAND_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_WAYLAND, GstVaapiDisplayWaylandClass))
+
+typedef struct _GstVaapiDisplayWaylandPrivate   GstVaapiDisplayWaylandPrivate;
+typedef struct _GstVaapiDisplayWaylandClass     GstVaapiDisplayWaylandClass;
+
+/**
+ * GST_VAAPI_DISPLAY_WL_DISPLAY:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to the underlying Wayland #wl_display object
+ * of @display
+ */
+#undef  GST_VAAPI_DISPLAY_WL_DISPLAY
+#define GST_VAAPI_DISPLAY_WL_DISPLAY(display) \
+    GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE(display)->wl_display
+
+typedef struct _GstDRMFormat GstDRMFormat;
+
+struct _GstDRMFormat {
+  guint format;
+  guint64 modifier;
+};
+
+struct _GstVaapiDisplayWaylandPrivate
+{
+  gchar *display_name;
+  struct wl_display *wl_display;
+  struct wl_compositor *compositor;
+  struct wl_shell *wl_shell;
+  struct xdg_wm_base *xdg_wm_base;
+  struct wl_subcompositor *subcompositor;
+  struct wl_output *output;
+  struct zwp_linux_dmabuf_v1 *dmabuf;
+  struct wl_registry *registry;
+  GArray *dmabuf_formats;
+  guint width;
+  guint height;
+  guint phys_width;
+  guint phys_height;
+  gint event_fd;
+  guint use_foreign_display:1;
+};
+
+/**
+ * GstVaapiDisplayWayland:
+ *
+ * VA/Wayland display wrapper.
+ */
+struct _GstVaapiDisplayWayland
+{
+  /*< private >*/
+  GstVaapiDisplay parent_instance;
+
+  GstVaapiDisplayWaylandPrivate *priv;
+};
+
+/**
+ * GstVaapiDisplayWaylandClass:
+ *
+ * VA/Wayland display wrapper clas.
+ */
+struct _GstVaapiDisplayWaylandClass
+{
+  /*< private >*/
+  GstVaapiDisplayClass parent_class;
+};
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_WAYLAND_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_x11.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_x11.c
new file mode 100644 (file)
index 0000000..1f2e1cc
--- /dev/null
@@ -0,0 +1,545 @@
+/*
+ *  gstvaapidisplay_x11.c - VA/X11 display abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapidisplay_x11
+ * @short_description: VA/X11 display abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiutils.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapidisplay_x11.h"
+#include "gstvaapidisplay_x11_priv.h"
+#include "gstvaapiwindow_x11.h"
+
+#if HAVE_XRANDR
+# include <X11/extensions/Xrandr.h>
+#endif
+
+#define DEBUG_VAAPI_DISPLAY 1
+#include "gstvaapidebug.h"
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiDisplayX11, gst_vaapi_display_x11,
+    GST_TYPE_VAAPI_DISPLAY);
+
+static inline const gchar *
+get_default_display_name (void)
+{
+  static const gchar *g_display_name;
+
+  if (!g_display_name)
+    g_display_name = getenv ("DISPLAY");
+  return g_display_name;
+}
+
+/* Reconstruct a display name without our prefix */
+static const gchar *
+get_display_name (GstVaapiDisplayX11 * display)
+{
+  GstVaapiDisplayX11Private *const priv = display->priv;
+  const gchar *display_name = priv->display_name;
+
+  if (!display_name || *display_name == '\0')
+    return NULL;
+  return display_name;
+}
+
+/* Mangle display name with our prefix */
+static gboolean
+set_display_name (GstVaapiDisplayX11 * display, const gchar * display_name)
+{
+  GstVaapiDisplayX11Private *const priv = display->priv;
+
+  g_free (priv->display_name);
+
+  if (!display_name) {
+    display_name = get_default_display_name ();
+    if (!display_name)
+      display_name = "";
+  }
+  priv->display_name = g_strdup (display_name);
+  return priv->display_name != NULL;
+}
+
+/* Set synchronous behavious on the underlying X11 display */
+static void
+set_synchronous (GstVaapiDisplayX11 * display, gboolean synchronous)
+{
+  GstVaapiDisplayX11Private *const priv = display->priv;
+
+  if (priv->synchronous != synchronous) {
+    priv->synchronous = synchronous;
+    if (priv->x11_display) {
+      GST_VAAPI_DISPLAY_LOCK (display);
+      XSynchronize (priv->x11_display, synchronous);
+      GST_VAAPI_DISPLAY_UNLOCK (display);
+    }
+  }
+}
+
+/* Check for display server extensions */
+static void
+check_extensions (GstVaapiDisplayX11 * display)
+{
+  GstVaapiDisplayX11Private *const priv = display->priv;
+  int evt_base, err_base;
+
+#if HAVE_XRANDR
+  priv->use_xrandr = XRRQueryExtension (priv->x11_display,
+      &evt_base, &err_base);
+#endif
+}
+
+static gboolean
+gst_vaapi_display_x11_bind_display (GstVaapiDisplay * base_display,
+    gpointer native_display)
+{
+  GstVaapiDisplayX11 *const display = GST_VAAPI_DISPLAY_X11_CAST (base_display);
+  GstVaapiDisplayX11Private *const priv = display->priv;
+
+  priv->x11_display = native_display;
+  priv->x11_screen = DefaultScreen (native_display);
+  priv->use_foreign_display = TRUE;
+
+  check_extensions (display);
+  if (!set_display_name (display, XDisplayString (priv->x11_display)))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_display_x11_open_display (GstVaapiDisplay * base_display,
+    const gchar * name)
+{
+  GstVaapiDisplayX11 *const display = GST_VAAPI_DISPLAY_X11_CAST (base_display);
+  GstVaapiDisplayX11Private *const priv = display->priv;
+
+  if (!set_display_name (display, name))
+    return FALSE;
+
+  priv->x11_display = XOpenDisplay (get_display_name (display));
+  if (!priv->x11_display)
+    return FALSE;
+  priv->use_foreign_display = FALSE;
+
+  priv->x11_screen = DefaultScreen (priv->x11_display);
+
+  check_extensions (display);
+  return TRUE;
+}
+
+static void
+gst_vaapi_display_x11_close_display (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayX11Private *const priv =
+      GST_VAAPI_DISPLAY_X11_PRIVATE (display);
+
+  g_clear_pointer (&priv->pixmap_formats, g_array_unref);
+
+  if (priv->x11_display) {
+    if (!priv->use_foreign_display)
+      XCloseDisplay (priv->x11_display);
+    priv->x11_display = NULL;
+  }
+
+  g_clear_pointer (&priv->display_name, g_free);
+}
+
+static void
+gst_vaapi_display_x11_sync (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayX11Private *const priv =
+      GST_VAAPI_DISPLAY_X11_PRIVATE (display);
+
+  if (priv->x11_display) {
+    GST_VAAPI_DISPLAY_LOCK (display);
+    XSync (priv->x11_display, False);
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+  }
+}
+
+static void
+gst_vaapi_display_x11_flush (GstVaapiDisplay * display)
+{
+  GstVaapiDisplayX11Private *const priv =
+      GST_VAAPI_DISPLAY_X11_PRIVATE (display);
+
+  if (priv->x11_display) {
+    GST_VAAPI_DISPLAY_LOCK (display);
+    XFlush (priv->x11_display);
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+  }
+}
+
+static gboolean
+gst_vaapi_display_x11_get_display_info (GstVaapiDisplay * display,
+    GstVaapiDisplayInfo * info)
+{
+  GstVaapiDisplayX11Private *const priv =
+      GST_VAAPI_DISPLAY_X11_PRIVATE (display);
+
+  info->native_display = priv->x11_display;
+  info->display_name = priv->display_name;
+  if (!info->va_display) {
+    info->va_display = vaGetDisplay (priv->x11_display);
+    if (!info->va_display)
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static void
+gst_vaapi_display_x11_get_size (GstVaapiDisplay * display,
+    guint * pwidth, guint * pheight)
+{
+  GstVaapiDisplayX11Private *const priv =
+      GST_VAAPI_DISPLAY_X11_PRIVATE (display);
+
+  if (!priv->x11_display)
+    return;
+
+  if (pwidth)
+    *pwidth = DisplayWidth (priv->x11_display, priv->x11_screen);
+
+  if (pheight)
+    *pheight = DisplayHeight (priv->x11_display, priv->x11_screen);
+}
+
+static void
+gst_vaapi_display_x11_get_size_mm (GstVaapiDisplay * display,
+    guint * pwidth, guint * pheight)
+{
+  GstVaapiDisplayX11Private *const priv =
+      GST_VAAPI_DISPLAY_X11_PRIVATE (display);
+  guint width_mm, height_mm;
+
+  if (!priv->x11_display)
+    return;
+
+  width_mm = DisplayWidthMM (priv->x11_display, priv->x11_screen);
+  height_mm = DisplayHeightMM (priv->x11_display, priv->x11_screen);
+
+#if HAVE_XRANDR
+  /* XXX: fix up physical size if the display is rotated */
+  if (priv->use_xrandr) {
+    XRRScreenConfiguration *xrr_config = NULL;
+    XRRScreenSize *xrr_sizes;
+    Window win;
+    int num_xrr_sizes, size_id, screen;
+    Rotation rotation;
+
+    do {
+      win = DefaultRootWindow (priv->x11_display);
+      screen = XRRRootToScreen (priv->x11_display, win);
+
+      xrr_config = XRRGetScreenInfo (priv->x11_display, win);
+      if (!xrr_config)
+        break;
+
+      size_id = XRRConfigCurrentConfiguration (xrr_config, &rotation);
+      if (rotation == RR_Rotate_0 || rotation == RR_Rotate_180)
+        break;
+
+      xrr_sizes = XRRSizes (priv->x11_display, screen, &num_xrr_sizes);
+      if (!xrr_sizes || size_id >= num_xrr_sizes)
+        break;
+
+      width_mm = xrr_sizes[size_id].mheight;
+      height_mm = xrr_sizes[size_id].mwidth;
+    } while (0);
+    if (xrr_config)
+      XRRFreeScreenConfigInfo (xrr_config);
+  }
+#endif
+
+  if (pwidth)
+    *pwidth = width_mm;
+
+  if (pheight)
+    *pheight = height_mm;
+}
+
+static GstVaapiWindow *
+gst_vaapi_display_x11_create_window (GstVaapiDisplay * display, GstVaapiID id,
+    guint width, guint height)
+{
+  return id != GST_VAAPI_ID_INVALID ?
+      gst_vaapi_window_x11_new_with_xid (display, id) :
+      gst_vaapi_window_x11_new (display, width, height);
+}
+
+void
+gst_vaapi_display_x11_class_init (GstVaapiDisplayX11Class * klass)
+{
+  GstVaapiDisplayClass *const dpy_class = GST_VAAPI_DISPLAY_CLASS (klass);
+
+  dpy_class->display_type = GST_VAAPI_DISPLAY_TYPE_X11;
+  dpy_class->bind_display = gst_vaapi_display_x11_bind_display;
+  dpy_class->open_display = gst_vaapi_display_x11_open_display;
+  dpy_class->close_display = gst_vaapi_display_x11_close_display;
+  dpy_class->sync = gst_vaapi_display_x11_sync;
+  dpy_class->flush = gst_vaapi_display_x11_flush;
+  dpy_class->get_display = gst_vaapi_display_x11_get_display_info;
+  dpy_class->get_size = gst_vaapi_display_x11_get_size;
+  dpy_class->get_size_mm = gst_vaapi_display_x11_get_size_mm;
+  dpy_class->create_window = gst_vaapi_display_x11_create_window;
+}
+
+static void
+gst_vaapi_display_x11_init (GstVaapiDisplayX11 * display)
+{
+  GstVaapiDisplayX11Private *const priv =
+      gst_vaapi_display_x11_get_instance_private (display);
+
+  display->priv = priv;
+}
+
+/**
+ * gst_vaapi_display_x11_new:
+ * @display_name: the X11 display name
+ *
+ * Opens an X11 #Display using @display_name and returns a newly
+ * allocated #GstVaapiDisplay object. The X11 display will be cloed
+ * when the reference count of the object reaches zero.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_x11_new (const gchar * display_name)
+{
+  GstVaapiDisplay *display;
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_X11, NULL);
+  return gst_vaapi_display_config (display,
+      GST_VAAPI_DISPLAY_INIT_FROM_DISPLAY_NAME, (gpointer) display_name);
+}
+
+/**
+ * gst_vaapi_display_x11_new_with_display:
+ * @x11_display: an X11 #Display
+ *
+ * Creates a #GstVaapiDisplay based on the X11 @x11_display
+ * display. The caller still owns the display and must call
+ * XCloseDisplay() when all #GstVaapiDisplay references are
+ * released. Doing so too early can yield undefined behaviour.
+ *
+ * Return value: a newly allocated #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_display_x11_new_with_display (Display * x11_display)
+{
+  GstVaapiDisplay *display;
+
+  g_return_val_if_fail (x11_display, NULL);
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_X11, NULL);
+  return gst_vaapi_display_config (display,
+      GST_VAAPI_DISPLAY_INIT_FROM_NATIVE_DISPLAY, x11_display);
+}
+
+GstVaapiDisplay *
+gst_vaapi_display_x11_new_with_va_display (VADisplay va_display,
+    Display * x11_display)
+{
+  GstVaapiDisplay *display;
+  GstVaapiDisplayInfo info = {
+    .va_display = va_display,
+    .native_display = x11_display,
+  };
+
+  g_return_val_if_fail (x11_display, NULL);
+
+  display = g_object_new (GST_TYPE_VAAPI_DISPLAY_X11, NULL);
+  return gst_vaapi_display_config (display,
+      GST_VAAPI_DISPLAY_INIT_FROM_VA_DISPLAY, &info);
+}
+
+/**
+ * gst_vaapi_display_x11_get_display:
+ * @display: a #GstVaapiDisplayX11
+ *
+ * Returns the underlying X11 #Display that was created by
+ * gst_vaapi_display_x11_new() or that was bound from
+ * gst_vaapi_display_x11_new_with_display().
+ *
+ * Return value: the X11 #Display attached to @display
+ */
+Display *
+gst_vaapi_display_x11_get_display (GstVaapiDisplayX11 * display)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), NULL);
+
+  return GST_VAAPI_DISPLAY_XDISPLAY (display);
+}
+
+/**
+ * gst_vaapi_display_x11_get_screen:
+ * @display: a #GstVaapiDisplayX11
+ *
+ * Returns the default X11 screen that was created by
+ * gst_vaapi_display_x11_new() or that was bound from
+ * gst_vaapi_display_x11_new_with_display().
+ *
+ * Return value: the X11 #Display attached to @display
+ */
+int
+gst_vaapi_display_x11_get_screen (GstVaapiDisplayX11 * display)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), -1);
+
+  return GST_VAAPI_DISPLAY_XSCREEN (display);
+}
+
+/**
+ * gst_vaapi_display_x11_set_synchronous:
+ * @display: a #GstVaapiDisplayX11
+ * @synchronous: boolean value that indicates whether to enable or
+ *   disable synchronization
+ *
+ * If @synchronous is %TRUE, gst_vaapi_display_x11_set_synchronous()
+ * turns on synchronous behaviour on the underlying X11
+ * display. Otherwise, synchronous behaviour is disabled if
+ * @synchronous is %FALSE.
+ */
+void
+gst_vaapi_display_x11_set_synchronous (GstVaapiDisplayX11 * display,
+    gboolean synchronous)
+{
+  g_return_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display));
+
+  set_synchronous (display, synchronous);
+}
+
+typedef struct _GstVaapiPixmapFormatX11 GstVaapiPixmapFormatX11;
+struct _GstVaapiPixmapFormatX11
+{
+  GstVideoFormat format;
+  gint depth;
+  gint bpp;
+};
+
+static GstVideoFormat
+pix_fmt_to_video_format (gint depth, gint bpp)
+{
+  GstVideoFormat format = GST_VIDEO_FORMAT_UNKNOWN;
+
+  switch (bpp) {
+    case 16:
+      if (depth == 15)
+        format = GST_VIDEO_FORMAT_RGB15;
+      else if (depth == 16)
+        format = GST_VIDEO_FORMAT_RGB16;
+      break;
+    case 24:
+      if (depth == 24)
+        format = GST_VIDEO_FORMAT_RGB;
+      break;
+    case 32:
+      if (depth == 24 || depth == 32)
+        format = GST_VIDEO_FORMAT_xRGB;
+      break;
+  }
+  return format;
+}
+
+static gboolean
+ensure_pix_fmts (GstVaapiDisplayX11 * display)
+{
+  GstVaapiDisplayX11Private *const priv =
+      GST_VAAPI_DISPLAY_X11_PRIVATE (display);
+  XPixmapFormatValues *pix_fmts;
+  int i, n, num_pix_fmts;
+
+  if (priv->pixmap_formats)
+    return TRUE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  pix_fmts = XListPixmapFormats (GST_VAAPI_DISPLAY_XDISPLAY (display),
+      &num_pix_fmts);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!pix_fmts)
+    return FALSE;
+
+  priv->pixmap_formats = g_array_sized_new (FALSE, FALSE,
+      sizeof (GstVaapiPixmapFormatX11), num_pix_fmts);
+  if (!priv->pixmap_formats) {
+    XFree (pix_fmts);
+    return FALSE;
+  }
+
+  for (i = 0, n = 0; i < num_pix_fmts; i++) {
+    GstVaapiPixmapFormatX11 *const pix_fmt =
+        &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, n);
+
+    pix_fmt->depth = pix_fmts[i].depth;
+    pix_fmt->bpp = pix_fmts[i].bits_per_pixel;
+    pix_fmt->format = pix_fmt_to_video_format (pix_fmt->depth, pix_fmt->bpp);
+    if (pix_fmt->format != GST_VIDEO_FORMAT_UNKNOWN)
+      n++;
+  }
+  priv->pixmap_formats->len = n;
+  XFree (pix_fmts);
+  return TRUE;
+}
+
+/* Determine the GstVideoFormat based on a supported Pixmap depth */
+GstVideoFormat
+gst_vaapi_display_x11_get_pixmap_format (GstVaapiDisplayX11 * display,
+    guint depth)
+{
+  if (ensure_pix_fmts (display)) {
+    GstVaapiDisplayX11Private *const priv =
+        GST_VAAPI_DISPLAY_X11_PRIVATE (display);
+    guint i;
+
+    for (i = 0; i < priv->pixmap_formats->len; i++) {
+      GstVaapiPixmapFormatX11 *const pix_fmt =
+          &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, i);
+      if (pix_fmt->depth == depth)
+        return pix_fmt->format;
+    }
+  }
+  return GST_VIDEO_FORMAT_UNKNOWN;
+}
+
+/* Determine the Pixmap depth based on a GstVideoFormat */
+guint
+gst_vaapi_display_x11_get_pixmap_depth (GstVaapiDisplayX11 * display,
+    GstVideoFormat format)
+{
+  if (ensure_pix_fmts (display)) {
+    GstVaapiDisplayX11Private *const priv =
+        GST_VAAPI_DISPLAY_X11_PRIVATE (display);
+    guint i;
+
+    for (i = 0; i < priv->pixmap_formats->len; i++) {
+      GstVaapiPixmapFormatX11 *const pix_fmt =
+          &g_array_index (priv->pixmap_formats, GstVaapiPixmapFormatX11, i);
+      if (pix_fmt->format == format)
+        return pix_fmt->depth;
+    }
+  }
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_x11.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_x11.h
new file mode 100644 (file)
index 0000000..78b6103
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  gstvaapidisplay_x11.h - VA/X11 display abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_X11_H
+#define GST_VAAPI_DISPLAY_X11_H
+
+#include <va/va_x11.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DISPLAY_X11              (gst_vaapi_display_x11_get_type ())
+#define GST_VAAPI_DISPLAY_X11(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DISPLAY_X11, GstVaapiDisplayX11))
+
+typedef struct _GstVaapiDisplayX11              GstVaapiDisplayX11;
+
+GstVaapiDisplay *
+gst_vaapi_display_x11_new (const gchar * display_name);
+
+GstVaapiDisplay *
+gst_vaapi_display_x11_new_with_display (Display * x11_display);
+
+GstVaapiDisplay *
+gst_vaapi_display_x11_new_with_va_display (VADisplay va_display, Display * x11_display);
+
+Display *
+gst_vaapi_display_x11_get_display (GstVaapiDisplayX11 * display);
+
+int
+gst_vaapi_display_x11_get_screen (GstVaapiDisplayX11 * display);
+
+void
+gst_vaapi_display_x11_set_synchronous (GstVaapiDisplayX11 * display,
+    gboolean synchronous);
+
+GType
+gst_vaapi_display_x11_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiDisplayX11, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_X11_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapidisplay_x11_priv.h
new file mode 100644 (file)
index 0000000..2f2cc7a
--- /dev/null
@@ -0,0 +1,116 @@
+/*
+ *  gstvaapidisplay_x11_priv.h - Internal VA/X11 interface
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DISPLAY_X11_PRIV_H
+#define GST_VAAPI_DISPLAY_X11_PRIV_H
+
+#include <gst/vaapi/gstvaapiutils_x11.h>
+#include <gst/vaapi/gstvaapidisplay_x11.h>
+#include "gstvaapidisplay_priv.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_IS_DISPLAY_X11(display) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((display), GST_TYPE_VAAPI_DISPLAY_X11))
+
+#define GST_VAAPI_DISPLAY_X11_CAST(display) \
+    ((GstVaapiDisplayX11 *)(display))
+
+#define GST_VAAPI_DISPLAY_X11_PRIVATE(display) \
+    (GST_VAAPI_DISPLAY_X11_CAST (display)->priv)
+
+#define GST_VAAPI_DISPLAY_X11_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DISPLAY_X11, GstVaapiDisplayX11Class))
+
+typedef struct _GstVaapiDisplayX11Private       GstVaapiDisplayX11Private;
+typedef struct _GstVaapiDisplayX11Class         GstVaapiDisplayX11Class;
+
+/**
+ * GST_VAAPI_DISPLAY_XDISPLAY:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to the underlying X11 #Display of @display
+ */
+#undef  GST_VAAPI_DISPLAY_XDISPLAY
+#define GST_VAAPI_DISPLAY_XDISPLAY(display) \
+    GST_VAAPI_DISPLAY_X11_PRIVATE(display)->x11_display
+
+/**
+ * GST_VAAPI_DISPLAY_XSCREEN:
+ * @display: a #GstVaapiDisplay
+ *
+ * Macro that evaluates to the underlying X11 screen of @display
+ */
+#undef  GST_VAAPI_DISPLAY_XSCREEN
+#define GST_VAAPI_DISPLAY_XSCREEN(display) \
+    GST_VAAPI_DISPLAY_X11_PRIVATE(display)->x11_screen
+
+struct _GstVaapiDisplayX11Private
+{
+  gchar *display_name;
+  Display *x11_display;
+  int x11_screen;
+  GArray *pixmap_formats;
+  guint use_foreign_display:1;  // Foreign native_display?
+  guint use_xrandr:1;
+  guint synchronous:1;
+};
+
+/**
+ * GstVaapiDisplayX11:
+ *
+ * VA/X11 display wrapper.
+ */
+struct _GstVaapiDisplayX11
+{
+  /*< private >*/
+  GstVaapiDisplay parent_instance;
+
+  GstVaapiDisplayX11Private *priv;
+};
+
+/**
+ * GstVaapiDisplayX11Class:
+ *
+ * VA/X11 display wrapper class.
+ */
+struct _GstVaapiDisplayX11Class
+{
+  /*< private >*/
+  GstVaapiDisplayClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GstVideoFormat
+gst_vaapi_display_x11_get_pixmap_format (GstVaapiDisplayX11 * display,
+    guint depth);
+
+G_GNUC_INTERNAL
+guint
+gst_vaapi_display_x11_get_pixmap_depth (GstVaapiDisplayX11 * display,
+    GstVideoFormat format);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DISPLAY_X11_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder.c
new file mode 100644 (file)
index 0000000..8ab33ca
--- /dev/null
@@ -0,0 +1,1873 @@
+/*
+ *  gstvaapiencoder.c - VA encoder abstraction
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiencoder.h"
+#include "gstvaapiencoder_priv.h"
+#include "gstvaapicontext.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiutils_core.h"
+#include "gstvaapivalue.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+gboolean
+gst_vaapi_encoder_ensure_param_quality_level (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture * picture)
+{
+  GstVaapiEncMiscParam *misc;
+
+  /* quality level param is not supported */
+  if (GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) == 0)
+    return TRUE;
+
+  misc = GST_VAAPI_ENC_QUALITY_LEVEL_MISC_PARAM_NEW (encoder);
+  if (!misc)
+    return FALSE;
+  memcpy (misc->data, &encoder->va_quality_level,
+      sizeof (encoder->va_quality_level));
+  gst_vaapi_enc_picture_add_misc_param (picture, misc);
+  gst_vaapi_codec_object_replace (&misc, NULL);
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_encoder_ensure_param_control_rate (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture * picture)
+{
+  GstVaapiEncMiscParam *misc;
+
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
+    return TRUE;
+
+  /* HRD params */
+  misc = GST_VAAPI_ENC_MISC_PARAM_NEW (HRD, encoder);
+  if (!misc)
+    return FALSE;
+  memcpy (misc->data, &GST_VAAPI_ENCODER_VA_HRD (encoder),
+      sizeof (VAEncMiscParameterHRD));
+  gst_vaapi_enc_picture_add_misc_param (picture, misc);
+  gst_vaapi_codec_object_replace (&misc, NULL);
+
+  /* RateControl params */
+  misc = GST_VAAPI_ENC_MISC_PARAM_NEW (RateControl, encoder);
+  if (!misc)
+    return FALSE;
+  memcpy (misc->data, &GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder),
+      sizeof (VAEncMiscParameterRateControl));
+  gst_vaapi_enc_picture_add_misc_param (picture, misc);
+  gst_vaapi_codec_object_replace (&misc, NULL);
+
+  /* FrameRate params */
+  if (GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder).framerate == 0)
+    return TRUE;
+
+  misc = GST_VAAPI_ENC_MISC_PARAM_NEW (FrameRate, encoder);
+  if (!misc)
+    return FALSE;
+  memcpy (misc->data, &GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder),
+      sizeof (VAEncMiscParameterFrameRate));
+  gst_vaapi_enc_picture_add_misc_param (picture, misc);
+  gst_vaapi_codec_object_replace (&misc, NULL);
+
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_encoder_ensure_param_trellis (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture * picture)
+{
+#if VA_CHECK_VERSION(1,0,0)
+  GstVaapiEncMiscParam *misc;
+  VAEncMiscParameterQuantization *param;
+
+  if (!encoder->trellis)
+    return TRUE;
+
+  misc = GST_VAAPI_ENC_QUANTIZATION_MISC_PARAM_NEW (encoder);
+  if (!misc)
+    return FALSE;
+  if (!misc->data)
+    return FALSE;
+
+  param = (VAEncMiscParameterQuantization *) misc->data;
+  param->quantization_flags.bits.disable_trellis = 0;
+  param->quantization_flags.bits.enable_trellis_I = 1;
+  param->quantization_flags.bits.enable_trellis_B = 1;
+  param->quantization_flags.bits.enable_trellis_P = 1;
+
+  gst_vaapi_enc_picture_add_misc_param (picture, misc);
+  gst_vaapi_codec_object_replace (&misc, NULL);
+#endif
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_encoder_ensure_param_roi_regions (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture * picture)
+{
+#if VA_CHECK_VERSION(0,39,1)
+  GstVaapiContextInfo *const cip = &encoder->context_info;
+  const GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
+  VAEncMiscParameterBufferROI *roi_param;
+  GstVaapiEncMiscParam *misc;
+  VAEncROI *region_roi;
+  GstBuffer *input;
+  guint num_roi, i;
+  gpointer state = NULL;
+
+  if (!config->roi_capability)
+    return TRUE;
+
+  if (!picture->frame)
+    return FALSE;
+
+  input = picture->frame->input_buffer;
+  if (!input)
+    return FALSE;
+
+  num_roi =
+      gst_buffer_get_n_meta (input, GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
+  if (num_roi == 0)
+    return TRUE;
+  num_roi = CLAMP (num_roi, 1, config->roi_num_supported);
+
+  misc =
+      gst_vaapi_enc_misc_param_new (encoder, VAEncMiscParameterTypeROI,
+      sizeof (VAEncMiscParameterBufferROI) + num_roi * sizeof (VAEncROI));
+  if (!misc)
+    return FALSE;
+
+  region_roi =
+      (VAEncROI *) ((guint8 *) misc->param + sizeof (VAEncMiscParameterBuffer) +
+      sizeof (VAEncMiscParameterBufferROI));
+
+  roi_param = misc->data;
+  roi_param->num_roi = num_roi;
+  roi_param->roi = region_roi;
+
+  /* roi_value in VAEncROI should be used as ROI delta QP */
+  roi_param->roi_flags.bits.roi_value_is_qp_delta = 1;
+  roi_param->max_delta_qp = 10;
+  roi_param->min_delta_qp = -10;
+
+  for (i = 0; i < num_roi; i++) {
+    GstVideoRegionOfInterestMeta *roi;
+    GstStructure *s;
+
+    roi = (GstVideoRegionOfInterestMeta *)
+        gst_buffer_iterate_meta_filtered (input, &state,
+        GST_VIDEO_REGION_OF_INTEREST_META_API_TYPE);
+    if (!roi)
+      continue;
+
+    /* ignore roi if overflow */
+    if ((roi->x > G_MAXINT16) || (roi->y > G_MAXINT16)
+        || (roi->w > G_MAXUINT16) || (roi->h > G_MAXUINT16))
+      continue;
+
+    GST_LOG ("Input buffer ROI: type=%s id=%d (%d, %d) %dx%d",
+        g_quark_to_string (roi->roi_type), roi->id, roi->x, roi->y, roi->w,
+        roi->h);
+
+    picture->has_roi = TRUE;
+
+    region_roi[i].roi_rectangle.x = roi->x;
+    region_roi[i].roi_rectangle.y = roi->y;
+    region_roi[i].roi_rectangle.width = roi->w;
+    region_roi[i].roi_rectangle.height = roi->h;
+
+    s = gst_video_region_of_interest_meta_get_param (roi, "roi/vaapi");
+    if (s) {
+      int value = 0;
+
+      if (!gst_structure_get_int (s, "delta-qp", &value))
+        continue;
+      value = CLAMP (value, roi_param->min_delta_qp, roi_param->max_delta_qp);
+      region_roi[i].roi_value = value;
+    } else {
+      region_roi[i].roi_value = encoder->default_roi_value;
+
+      GST_LOG ("No ROI value specified upstream, use default (%d)",
+          encoder->default_roi_value);
+    }
+  }
+
+  if (picture->has_roi)
+    gst_vaapi_enc_picture_add_misc_param (picture, misc);
+
+  gst_vaapi_codec_object_replace (&misc, NULL);
+#endif
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_encoder_replace:
+ * @old_encoder_ptr: a pointer to a #GstVaapiEncoder
+ * @new_encoder: a #GstVaapiEncoder
+ *
+ * Atomically replaces the encoder encoder held in @old_encoder_ptr
+ * with @new_encoder. This means that @old_encoder_ptr shall reference
+ * a valid encoder. However, @new_encoder can be NULL.
+ */
+void
+gst_vaapi_encoder_replace (GstVaapiEncoder ** old_encoder_ptr,
+    GstVaapiEncoder * new_encoder)
+{
+  gst_object_replace ((GstObject **) old_encoder_ptr,
+      (GstObject *) new_encoder);
+}
+
+/* Notifies gst_vaapi_encoder_create_coded_buffer() that a new buffer is free */
+static void
+_coded_buffer_proxy_released_notify (GstVaapiEncoder * encoder)
+{
+  g_mutex_lock (&encoder->mutex);
+  g_cond_signal (&encoder->codedbuf_free);
+  g_mutex_unlock (&encoder->mutex);
+}
+
+/* Creates a new VA coded buffer object proxy, backed from a pool */
+static GstVaapiCodedBufferProxy *
+gst_vaapi_encoder_create_coded_buffer (GstVaapiEncoder * encoder)
+{
+  GstVaapiCodedBufferPool *const pool =
+      GST_VAAPI_CODED_BUFFER_POOL (encoder->codedbuf_pool);
+  GstVaapiCodedBufferProxy *codedbuf_proxy;
+
+  g_mutex_lock (&encoder->mutex);
+  do {
+    codedbuf_proxy = gst_vaapi_coded_buffer_proxy_new_from_pool (pool);
+    if (codedbuf_proxy)
+      break;
+
+    /* Wait for a free coded buffer to become available */
+    g_cond_wait (&encoder->codedbuf_free, &encoder->mutex);
+    codedbuf_proxy = gst_vaapi_coded_buffer_proxy_new_from_pool (pool);
+  } while (0);
+  g_mutex_unlock (&encoder->mutex);
+  if (!codedbuf_proxy)
+    return NULL;
+
+  gst_vaapi_coded_buffer_proxy_set_destroy_notify (codedbuf_proxy,
+      (GDestroyNotify) _coded_buffer_proxy_released_notify, encoder);
+  return codedbuf_proxy;
+}
+
+/* Notifies gst_vaapi_encoder_create_surface() that a new surface is free */
+static void
+_surface_proxy_released_notify (GstVaapiEncoder * encoder)
+{
+  g_mutex_lock (&encoder->mutex);
+  g_cond_signal (&encoder->surface_free);
+  g_mutex_unlock (&encoder->mutex);
+}
+
+/* Creates a new VA surface object proxy, backed from a pool and
+   useful to allocate reconstructed surfaces */
+GstVaapiSurfaceProxy *
+gst_vaapi_encoder_create_surface (GstVaapiEncoder * encoder)
+{
+  GstVaapiSurfaceProxy *proxy;
+
+  g_return_val_if_fail (encoder->context != NULL, NULL);
+
+  g_mutex_lock (&encoder->mutex);
+  for (;;) {
+    proxy = gst_vaapi_context_get_surface_proxy (encoder->context);
+    if (proxy)
+      break;
+
+    /* Wait for a free surface proxy to become available */
+    g_cond_wait (&encoder->surface_free, &encoder->mutex);
+  }
+  g_mutex_unlock (&encoder->mutex);
+
+  gst_vaapi_surface_proxy_set_destroy_notify (proxy,
+      (GDestroyNotify) _surface_proxy_released_notify, encoder);
+  return proxy;
+}
+
+/* Create a coded buffer proxy where the picture is going to be
+ * decoded, the subclass encode vmethod is called and, if it doesn't
+ * fail, the coded buffer is pushed into the async queue */
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_encode_and_queue (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture * picture)
+{
+  GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
+  GstVaapiCodedBufferProxy *codedbuf_proxy;
+  GstVaapiEncoderStatus status;
+
+  codedbuf_proxy = gst_vaapi_encoder_create_coded_buffer (encoder);
+  if (!codedbuf_proxy)
+    goto error_create_coded_buffer;
+
+  status = klass->encode (encoder, picture, codedbuf_proxy);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    goto error_encode;
+
+  gst_vaapi_coded_buffer_proxy_set_user_data (codedbuf_proxy,
+      picture, (GDestroyNotify) gst_vaapi_mini_object_unref);
+  g_async_queue_push (encoder->codedbuf_queue, codedbuf_proxy);
+  encoder->num_codedbuf_queued++;
+
+  return status;
+
+  /* ERRORS */
+error_create_coded_buffer:
+  {
+    GST_ERROR ("failed to allocate coded buffer");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+error_encode:
+  {
+    GST_ERROR ("failed to encode frame (status = %d)", status);
+    gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy);
+    return status;
+  }
+}
+
+/**
+ * gst_vaapi_encoder_put_frame:
+ * @encoder: a #GstVaapiEncoder
+ * @frame: a #GstVideoCodecFrame
+ *
+ * Queues a #GstVideoCodedFrame to the HW encoder. The encoder holds
+ * an extra reference to the @frame.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder,
+    GstVideoCodecFrame * frame)
+{
+  GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
+  GstVaapiEncoderStatus status;
+  GstVaapiEncPicture *picture;
+
+  for (;;) {
+    picture = NULL;
+    status = klass->reordering (encoder, frame, &picture);
+    if (status == GST_VAAPI_ENCODER_STATUS_NO_SURFACE)
+      break;
+    if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+      goto error_reorder_frame;
+
+    status = gst_vaapi_encoder_encode_and_queue (encoder, picture);
+    if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+      goto error_encode;
+
+    /* Try again with any pending reordered frame now available for encoding */
+    frame = NULL;
+  }
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error_reorder_frame:
+  {
+    GST_ERROR ("failed to process reordered frames");
+    return status;
+  }
+error_encode:
+  {
+    gst_vaapi_enc_picture_unref (picture);
+    return status;
+  }
+}
+
+/**
+ * gst_vaapi_encoder_get_buffer_with_timeout:
+ * @encoder: a #GstVaapiEncoder
+ * @out_codedbuf_proxy_ptr: the next coded buffer as a #GstVaapiCodedBufferProxy
+ * @timeout: the number of microseconds to wait for the coded buffer, at most
+ *
+ * Upon successful return, *@out_codedbuf_proxy_ptr contains the next
+ * coded buffer as a #GstVaapiCodedBufferProxy. The caller owns this
+ * object, so gst_vaapi_coded_buffer_proxy_unref() shall be called
+ * after usage. Otherwise, @GST_VAAPI_DECODER_STATUS_ERROR_NO_BUFFER
+ * is returned if no coded buffer is available so far (timeout).
+ *
+ * The parent frame is available as a #GstVideoCodecFrame attached to
+ * the user-data anchor of the output coded buffer. Ownership of the
+ * frame is transferred to the coded buffer.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_get_buffer_with_timeout (GstVaapiEncoder * encoder,
+    GstVaapiCodedBufferProxy ** out_codedbuf_proxy_ptr, guint64 timeout)
+{
+  GstVaapiEncPicture *picture;
+  GstVaapiCodedBufferProxy *codedbuf_proxy;
+
+  codedbuf_proxy = g_async_queue_timeout_pop (encoder->codedbuf_queue, timeout);
+  if (!codedbuf_proxy)
+    return GST_VAAPI_ENCODER_STATUS_NO_BUFFER;
+
+  /* Wait for completion of all operations and report any error that occurred */
+  picture = gst_vaapi_coded_buffer_proxy_get_user_data (codedbuf_proxy);
+  if (!gst_vaapi_surface_sync (picture->surface))
+    goto error_invalid_buffer;
+
+  gst_vaapi_coded_buffer_proxy_set_user_data (codedbuf_proxy,
+      gst_video_codec_frame_ref (picture->frame),
+      (GDestroyNotify) gst_video_codec_frame_unref);
+
+  if (out_codedbuf_proxy_ptr)
+    *out_codedbuf_proxy_ptr = gst_vaapi_coded_buffer_proxy_ref (codedbuf_proxy);
+  gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy);
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error_invalid_buffer:
+  {
+    GST_ERROR ("failed to encode the frame");
+    gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_SURFACE;
+  }
+}
+
+static inline gboolean
+_get_pending_reordered (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture ** picture, gpointer * state)
+{
+  GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
+
+  if (!klass->get_pending_reordered)
+    return FALSE;
+  return klass->get_pending_reordered (encoder, picture, state);
+}
+
+/**
+ * gst_vaapi_encoder_flush:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Submits any pending (reordered) frame for encoding.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_flush (GstVaapiEncoder * encoder)
+{
+  GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
+  GstVaapiEncPicture *picture;
+  GstVaapiEncoderStatus status;
+  gpointer iter = NULL;
+
+  picture = NULL;
+  while (_get_pending_reordered (encoder, &picture, &iter)) {
+    if (!picture)
+      continue;
+    status = gst_vaapi_encoder_encode_and_queue (encoder, picture);
+    if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+      goto error_encode;
+  }
+  g_free (iter);
+
+  return klass->flush (encoder);
+
+  /* ERRORS */
+error_encode:
+  {
+    gst_vaapi_enc_picture_unref (picture);
+    return status;
+  }
+}
+
+/**
+ * gst_vaapi_encoder_get_codec_data:
+ * @encoder: a #GstVaapiEncoder
+ * @out_codec_data_ptr: the pointer to the resulting codec-data (#GstBuffer)
+ *
+ * Returns a codec-data buffer that best represents the encoded
+ * bitstream. Upon successful return, and if the @out_codec_data_ptr
+ * contents is not NULL, then the caller function shall deallocates
+ * that buffer with gst_buffer_unref().
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder,
+    GstBuffer ** out_codec_data_ptr)
+{
+  GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_SUCCESS;
+  GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
+
+  *out_codec_data_ptr = NULL;
+  if (!klass->get_codec_data)
+    return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  ret = klass->get_codec_data (encoder, out_codec_data_ptr);
+  return ret;
+}
+
+/* Checks video info */
+static GstVaapiEncoderStatus
+check_video_info (GstVaapiEncoder * encoder, const GstVideoInfo * vip)
+{
+  if (!vip->width || !vip->height)
+    goto error_invalid_resolution;
+  if (vip->fps_n < 0 || vip->fps_d <= 0)
+    goto error_invalid_framerate;
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error_invalid_resolution:
+  {
+    GST_ERROR ("invalid resolution (%dx%d)", vip->width, vip->height);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
+  }
+error_invalid_framerate:
+  {
+    GST_ERROR ("invalid framerate (%d/%d)", vip->fps_n, vip->fps_d);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER;
+  }
+}
+
+/* Gets a compatible profile for the active codec */
+static GstVaapiProfile
+get_compatible_profile (GstVaapiEncoder * encoder)
+{
+  const GstVaapiEncoderClassData *const cdata =
+      GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data;
+  GstVaapiProfile profile;
+  GArray *profiles;
+  guint i;
+
+  profiles = gst_vaapi_display_get_encode_profiles (encoder->display);
+  if (!profiles)
+    return GST_VAAPI_PROFILE_UNKNOWN;
+
+  // Pick a profile matching the class codec
+  for (i = 0; i < profiles->len; i++) {
+    profile = g_array_index (profiles, GstVaapiProfile, i);
+    if (gst_vaapi_profile_get_codec (profile) == cdata->codec)
+      break;
+  }
+  if (i == profiles->len)
+    profile = GST_VAAPI_PROFILE_UNKNOWN;
+
+  g_array_unref (profiles);
+  return profile;
+}
+
+/* Gets a supported profile for the active codec */
+static GstVaapiProfile
+get_profile (GstVaapiEncoder * encoder)
+{
+  if (!encoder->profile)
+    encoder->profile = get_compatible_profile (encoder);
+  return encoder->profile;
+}
+
+/* Gets config attribute for the supplied profile */
+static gboolean
+get_config_attribute (GstVaapiEncoder * encoder, VAConfigAttribType type,
+    guint * out_value_ptr)
+{
+  GstVaapiProfile profile;
+  VAProfile va_profile;
+  VAEntrypoint va_entrypoint;
+
+  profile = get_profile (encoder);
+  if (!profile)
+    return FALSE;
+  va_profile = gst_vaapi_profile_get_va_profile (profile);
+
+  va_entrypoint =
+      gst_vaapi_entrypoint_get_va_entrypoint (encoder->context_info.entrypoint);
+
+  return gst_vaapi_get_config_attribute (encoder->display, va_profile,
+      va_entrypoint, type, out_value_ptr);
+}
+
+/* Determines the set of supported packed headers */
+static guint
+get_packed_headers (GstVaapiEncoder * encoder)
+{
+  const GstVaapiEncoderClassData *const cdata =
+      GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data;
+  guint value;
+
+  if (encoder->got_packed_headers)
+    return encoder->packed_headers;
+
+  if (!get_config_attribute (encoder, VAConfigAttribEncPackedHeaders, &value))
+    value = 0;
+  GST_INFO ("supported packed headers: 0x%08x", value);
+
+  encoder->got_packed_headers = TRUE;
+  encoder->packed_headers = cdata->packed_headers & value;
+
+  return encoder->packed_headers;
+}
+
+static gboolean
+get_roi_capability (GstVaapiEncoder * encoder, guint * num_roi_supported)
+{
+#if VA_CHECK_VERSION(0,39,1)
+  VAConfigAttribValEncROI *roi_config;
+  guint value;
+
+  if (!get_config_attribute (encoder, VAConfigAttribEncROI, &value))
+    return FALSE;
+
+  roi_config = (VAConfigAttribValEncROI *) & value;
+
+  if (roi_config->bits.num_roi_regions == 0)
+    return FALSE;
+
+  /* Only support QP delta, and it only makes sense when rate control
+   * is not CQP */
+  if ((GST_VAAPI_ENCODER_RATE_CONTROL (encoder) != GST_VAAPI_RATECONTROL_CQP)
+      && (VA_ROI_RC_QP_DELTA_SUPPORT (roi_config) == 0))
+    return FALSE;
+
+  GST_INFO ("Support for ROI - number of regions supported: %d",
+      roi_config->bits.num_roi_regions);
+
+  *num_roi_supported = roi_config->bits.num_roi_regions;
+  return TRUE;
+#else
+  return FALSE;
+#endif
+}
+
+static inline gboolean
+is_chroma_type_supported (GstVaapiEncoder * encoder)
+{
+  GstVaapiContextInfo *const cip = &encoder->context_info;
+  const GstVideoFormat fmt =
+      GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder));
+  guint format = 0;
+
+  if (fmt == GST_VIDEO_FORMAT_ENCODED)
+    return TRUE;
+
+  if (cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420 &&
+      cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV422 &&
+      cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420_10BPP &&
+      cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV444 &&
+      cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV444_10BPP &&
+      cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV422_10BPP &&
+      cip->chroma_type != GST_VAAPI_CHROMA_TYPE_YUV420_12BPP)
+    goto unsupported;
+
+  if (!get_config_attribute (encoder, VAConfigAttribRTFormat, &format))
+    return FALSE;
+
+  if (!(format & from_GstVaapiChromaType (cip->chroma_type)))
+    goto unsupported;
+
+  return TRUE;
+
+  /* ERRORS */
+unsupported:
+  {
+    GST_ERROR ("The encoding format %s is not supported, "
+        "Please try to use vaapipostproc to convert the input format.",
+        gst_video_format_to_string (fmt));
+    return FALSE;
+  }
+}
+
+static guint
+get_default_chroma_type (GstVaapiEncoder * encoder,
+    const GstVaapiContextInfo * cip)
+{
+  guint value;
+
+  if (!gst_vaapi_get_config_attribute (encoder->display,
+          gst_vaapi_profile_get_va_profile (cip->profile),
+          gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint),
+          VAConfigAttribRTFormat, &value))
+    return 0;
+
+  return to_GstVaapiChromaType (value);
+}
+
+static void
+init_context_info (GstVaapiEncoder * encoder, GstVaapiContextInfo * cip)
+{
+  cip->usage = GST_VAAPI_CONTEXT_USAGE_ENCODE;
+  cip->chroma_type = get_default_chroma_type (encoder, cip);
+  cip->width = 0;
+  cip->height = 0;
+  cip->ref_frames = encoder->num_ref_frames;
+}
+
+/* Updates video context */
+static gboolean
+set_context_info (GstVaapiEncoder * encoder)
+{
+  GstVaapiContextInfo *const cip = &encoder->context_info;
+  GstVaapiConfigInfoEncoder *const config = &cip->config.encoder;
+  const GstVideoFormat format =
+      GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder));
+
+  g_assert (cip->profile != GST_VAAPI_PROFILE_UNKNOWN);
+  g_assert (cip->entrypoint != GST_VAAPI_ENTRYPOINT_INVALID);
+
+  init_context_info (encoder, cip);
+  cip->chroma_type = gst_vaapi_video_format_get_chroma_type (format);
+  cip->width = GST_VAAPI_ENCODER_WIDTH (encoder);
+  cip->height = GST_VAAPI_ENCODER_HEIGHT (encoder);
+
+  if (!is_chroma_type_supported (encoder))
+    goto error_unsupported_format;
+
+  memset (config, 0, sizeof (*config));
+  config->rc_mode = GST_VAAPI_ENCODER_RATE_CONTROL (encoder);
+  config->packed_headers = get_packed_headers (encoder);
+  config->roi_capability =
+      get_roi_capability (encoder, &config->roi_num_supported);
+
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_format:
+  {
+    GST_ERROR ("failed to determine chroma type for format %s",
+        gst_vaapi_video_format_to_string (format));
+    return FALSE;
+  }
+}
+
+/* Ensures the underlying VA context for encoding is created */
+static gboolean
+gst_vaapi_encoder_ensure_context (GstVaapiEncoder * encoder)
+{
+  GstVaapiContextInfo *const cip = &encoder->context_info;
+
+  if (!set_context_info (encoder))
+    return FALSE;
+
+  if (encoder->context) {
+    if (!gst_vaapi_context_reset (encoder->context, cip))
+      return FALSE;
+  } else {
+    encoder->context = gst_vaapi_context_new (encoder->display, cip);
+    if (!encoder->context)
+      return FALSE;
+  }
+  encoder->va_context = gst_vaapi_context_get_id (encoder->context);
+  return TRUE;
+}
+
+/* Reconfigures the encoder with the new properties */
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_reconfigure_internal (GstVaapiEncoder * encoder)
+{
+  GstVaapiEncoderClass *const klass = GST_VAAPI_ENCODER_GET_CLASS (encoder);
+  GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+  GstVaapiEncoderStatus status;
+  GstVaapiVideoPool *pool;
+  guint codedbuf_size, target_percentage;
+  guint fps_d, fps_n;
+  guint quality_level_max = 0;
+
+  fps_d = GST_VIDEO_INFO_FPS_D (vip);
+  fps_n = GST_VIDEO_INFO_FPS_N (vip);
+
+  /* Generate a keyframe every second */
+  if (!encoder->keyframe_period)
+    encoder->keyframe_period = (fps_n + fps_d - 1) / fps_d;
+
+  /* Default frame rate parameter */
+  if (fps_d > 0 && fps_n > 0)
+    GST_VAAPI_ENCODER_VA_FRAME_RATE (encoder).framerate = fps_d << 16 | fps_n;
+
+  target_percentage =
+      (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR) ?
+      100 : encoder->target_percentage;
+
+  /* *INDENT-OFF* */
+  /* Default values for rate control parameter */
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder) = (VAEncMiscParameterRateControl) {
+    .bits_per_second = encoder->bitrate * 1000,
+    .target_percentage = target_percentage,
+    .window_size = 500,
+  };
+  /* *INDENT-ON* */
+
+  status = klass->reconfigure (encoder);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return status;
+
+  if (!gst_vaapi_encoder_ensure_context (encoder))
+    goto error_reset_context;
+
+  if (get_config_attribute (encoder, VAConfigAttribEncQualityRange,
+          &quality_level_max) && quality_level_max > 0) {
+    GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) =
+        CLAMP (GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder), 1, quality_level_max);
+  } else {
+    GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) = 0;
+  }
+  GST_INFO ("Quality level is fixed to %d",
+      GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder));
+
+  if (encoder->trellis) {
+#if VA_CHECK_VERSION(1,0,0)
+    guint quantization_method = 0;
+    if (get_config_attribute (encoder, VAConfigAttribEncQuantization,
+            &quantization_method) == FALSE
+        || !(quantization_method & VA_ENC_QUANTIZATION_TRELLIS_SUPPORTED)) {
+
+      GST_INFO ("Trellis Quantization is not supported,"
+          " trellis will be disabled");
+      encoder->trellis = FALSE;
+    }
+#else
+    GST_INFO ("The encode trellis quantization option is not supported"
+        " in this VAAPI version.");
+    encoder->trellis = FALSE;
+#endif
+  }
+
+  codedbuf_size = encoder->codedbuf_pool ?
+      gst_vaapi_coded_buffer_pool_get_buffer_size (GST_VAAPI_CODED_BUFFER_POOL
+      (encoder)) : 0;
+  if (codedbuf_size != encoder->codedbuf_size) {
+    pool = gst_vaapi_coded_buffer_pool_new (encoder, encoder->codedbuf_size);
+    if (!pool)
+      goto error_alloc_codedbuf_pool;
+    gst_vaapi_video_pool_set_capacity (pool, 5);
+    gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, pool);
+    gst_vaapi_video_pool_unref (pool);
+  }
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error_alloc_codedbuf_pool:
+  {
+    GST_ERROR ("failed to initialize coded buffer pool");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+error_reset_context:
+  {
+    GST_ERROR ("failed to update VA context");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+}
+
+/**
+ * gst_vaapi_encoder_set_codec_state:
+ * @encoder: a #GstVaapiEncoder
+ * @state : a #GstVideoCodecState
+ *
+ * Notifies the encoder about the source surface properties. The
+ * accepted set of properties is: video resolution, colorimetry,
+ * pixel-aspect-ratio and framerate.
+ *
+ * This function is a synchronization point for codec configuration.
+ * This means that, at this point, the encoder is reconfigured to
+ * match the new properties and any other change beyond this point has
+ * zero effect.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_codec_state (GstVaapiEncoder * encoder,
+    GstVideoCodecState * state)
+{
+  GstVaapiEncoderStatus status;
+
+  g_return_val_if_fail (encoder != NULL,
+      GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (state != NULL,
+      GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER);
+
+  if (!gst_video_info_is_equal (&state->info, &encoder->video_info)) {
+    status = check_video_info (encoder, &state->info);
+    if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+      return status;
+    encoder->video_info = state->info;
+  }
+  return gst_vaapi_encoder_reconfigure_internal (encoder);
+}
+
+/* Determine the supported rate control modes */
+static guint
+get_rate_control_mask (GstVaapiEncoder * encoder)
+{
+  const GstVaapiEncoderClassData *const cdata =
+      GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data;
+  guint i, value, rate_control_mask = 0;
+
+  if (encoder->got_rate_control_mask)
+    return encoder->rate_control_mask;
+
+  if (get_config_attribute (encoder, VAConfigAttribRateControl, &value)) {
+    for (i = 0; i < 32; i++) {
+      if (!(value & (1U << i)))
+        continue;
+      rate_control_mask |= 1 << to_GstVaapiRateControl (1 << i);
+    }
+    GST_INFO ("supported rate controls: 0x%08x", rate_control_mask);
+
+    encoder->got_rate_control_mask = TRUE;
+    encoder->rate_control_mask = cdata->rate_control_mask & rate_control_mask;
+  }
+
+  return encoder->rate_control_mask;
+}
+
+/**
+ * gst_vaapi_encoder_set_rate_control:
+ * @encoder: a #GstVaapiEncoder
+ * @rate_control: the requested rate control
+ *
+ * Notifies the @encoder to use the supplied @rate_control mode.
+ *
+ * If the underlying encoder does not support that rate control mode,
+ * then @GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL is
+ * returned.
+ *
+ * The rate control mode can only be specified before the first frame
+ * is to be encoded. Afterwards, any change to this parameter is
+ * invalid and @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED is
+ * returned.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_rate_control (GstVaapiEncoder * encoder,
+    GstVaapiRateControl rate_control)
+{
+  guint32 rate_control_mask;
+
+  g_return_val_if_fail (encoder != NULL,
+      GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER);
+
+  if (encoder->rate_control != rate_control && encoder->num_codedbuf_queued > 0)
+    goto error_operation_failed;
+
+  rate_control_mask = get_rate_control_mask (encoder);
+  if (rate_control_mask && !(rate_control_mask & (1U << rate_control)))
+    goto error_unsupported_rate_control;
+
+  encoder->rate_control = rate_control;
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error_operation_failed:
+  {
+    GST_ERROR ("could not change rate control mode after encoding started");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+error_unsupported_rate_control:
+  {
+    GST_ERROR ("unsupported rate control mode (%d)", rate_control);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL;
+  }
+}
+
+/**
+ * gst_vaapi_encoder_set_bitrate:
+ * @encoder: a #GstVaapiEncoder
+ * @bitrate: the requested bitrate (in kbps)
+ *
+ * Notifies the @encoder to use the supplied @bitrate value.
+ *
+ * Note: currently, the bitrate can only be specified before the first
+ * frame is encoded. Afterwards, any change to this parameter is
+ * invalid and @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED is
+ * returned.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_bitrate (GstVaapiEncoder * encoder, guint bitrate)
+{
+  g_return_val_if_fail (encoder != NULL, 0);
+
+  if (encoder->bitrate != bitrate && encoder->num_codedbuf_queued > 0) {
+    GST_INFO ("Bitrate is changed to %d on runtime", bitrate);
+    encoder->bitrate = bitrate;
+    return gst_vaapi_encoder_reconfigure_internal (encoder);
+  }
+
+  encoder->bitrate = bitrate;
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_target_percentage (GstVaapiEncoder * encoder,
+    guint target_percentage)
+{
+  g_return_val_if_fail (encoder != NULL, 0);
+
+  if (encoder->target_percentage != target_percentage
+      && encoder->num_codedbuf_queued > 0) {
+    if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) != GST_VAAPI_RATECONTROL_CBR) {
+      GST_INFO ("Target percentage is changed to %d on runtime",
+          target_percentage);
+      encoder->target_percentage = target_percentage;
+      return gst_vaapi_encoder_reconfigure_internal (encoder);
+    }
+    GST_WARNING ("Target percentage is ignored for CBR rate-control");
+    return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+  }
+
+  encoder->target_percentage = target_percentage;
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+/**
+ * gst_vaapi_encoder_set_keyframe_period:
+ * @encoder: a #GstVaapiEncoder
+ * @keyframe_period: the maximal distance between two keyframes
+ *
+ * Notifies the @encoder to use the supplied @keyframe_period value.
+ *
+ * Note: currently, the keyframe period can only be specified before
+ * the last call to gst_vaapi_encoder_set_codec_state(), which shall
+ * occur before the first frame is encoded. Afterwards, any change to
+ * this parameter causes gst_vaapi_encoder_set_keyframe_period() to
+ * return @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_keyframe_period (GstVaapiEncoder * encoder,
+    guint keyframe_period)
+{
+  g_return_val_if_fail (encoder != NULL, 0);
+
+  if (encoder->keyframe_period != keyframe_period
+      && encoder->num_codedbuf_queued > 0)
+    goto error_operation_failed;
+
+  encoder->keyframe_period = keyframe_period;
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error_operation_failed:
+  {
+    GST_ERROR ("could not change keyframe period after encoding started");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+}
+
+/**
+ * gst_vaapi_encoder_set_tuning:
+ * @encoder: a #GstVaapiEncoder
+ * @tuning: the #GstVaapiEncoderTune option
+ *
+ * Notifies the @encoder to use the supplied @tuning option.
+ *
+ * Note: currently, the tuning option can only be specified before the
+ * last call to gst_vaapi_encoder_set_codec_state(), which shall occur
+ * before the first frame is encoded. Afterwards, any change to this
+ * parameter causes gst_vaapi_encoder_set_tuning() to return
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_tuning (GstVaapiEncoder * encoder,
+    GstVaapiEncoderTune tuning)
+{
+  g_return_val_if_fail (encoder != NULL, 0);
+
+  if (encoder->tune != tuning && encoder->num_codedbuf_queued > 0)
+    goto error_operation_failed;
+
+  encoder->tune = tuning;
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error_operation_failed:
+  {
+    GST_ERROR ("could not change tuning options after encoding started");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+}
+
+/**
+ * gst_vaapi_encoder_set_quality_level:
+ * @encoder: a #GstVaapiEncoder
+ * @quality_level: the encoder quality level
+ *
+ * Notifies the @encoder to use the supplied @quality_level value.
+ *
+ * Note: currently, the quality_level can only be specified before
+ * the last call to gst_vaapi_encoder_set_codec_state(), which shall
+ * occur before the first frame is encoded. Afterwards, any change to
+ * this parameter causes gst_vaapi_encoder_set_quality_level() to
+ * return @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_quality_level (GstVaapiEncoder * encoder,
+    guint quality_level)
+{
+  g_return_val_if_fail (encoder != NULL, 0);
+
+  if (GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) != quality_level
+      && encoder->num_codedbuf_queued > 0)
+    goto error_operation_failed;
+
+  GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder) = quality_level;
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error_operation_failed:
+  {
+    GST_ERROR ("could not change quality level after encoding started");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+}
+
+/**
+ * gst_vaapi_encoder_set_trellis:
+ * @encoder: a #GstVaapiEncoder
+ * @trellis: whether to use trellis quantization
+ *
+ * Notifies the @encoder to use the supplied @trellis option.
+ *
+ * Note: currently, the tuning option can only be specified before the
+ * last call to gst_vaapi_encoder_set_codec_state(), which shall occur
+ * before the first frame is encoded. Afterwards, any change to this
+ * parameter causes gst_vaapi_encoder_set_tuning() to return
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED.
+ *
+ * Return value: a #GstVaapiEncoderStatus
+ */
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_trellis (GstVaapiEncoder * encoder, gboolean trellis)
+{
+  g_return_val_if_fail (encoder != NULL, 0);
+
+  if (encoder->trellis != trellis && encoder->num_codedbuf_queued > 0)
+    goto error_operation_failed;
+
+  encoder->trellis = trellis;
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error_operation_failed:
+  {
+    GST_ERROR ("could not change trellis options after encoding started");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+}
+
+G_DEFINE_ABSTRACT_TYPE (GstVaapiEncoder, gst_vaapi_encoder, GST_TYPE_OBJECT);
+
+/**
+ * GstVaapiEncoderProp:
+ * @ENCODER_PROP_DISPLAY: The display.
+ * @ENCODER_PROP_BITRATE: Bitrate expressed in kbps (uint).
+ * @ENCODER_PROP_TARGET_PERCENTAGE: Desired target percentage of
+ *  bitrate for variable rate controls.
+ * @ENCODER_PROP_KEYFRAME_PERIOD: The maximal distance
+ *   between two keyframes (uint).
+ * @ENCODER_PROP_DEFAULT_ROI_VALUE: The default delta qp to apply
+ *   to each region of interest.
+ * @ENCODER_PROP_TRELLIS: Use trellis quantization method (gboolean).
+ *
+ * The set of configurable properties for the encoder.
+ */
+enum
+{
+  ENCODER_PROP_DISPLAY = 1,
+  ENCODER_PROP_BITRATE,
+  ENCODER_PROP_TARGET_PERCENTAGE,
+  ENCODER_PROP_KEYFRAME_PERIOD,
+  ENCODER_PROP_QUALITY_LEVEL,
+  ENCODER_PROP_DEFAULT_ROI_VALUE,
+  ENCODER_PROP_TRELLIS,
+  ENCODER_N_PROPERTIES
+};
+
+static GParamSpec *properties[ENCODER_N_PROPERTIES];
+
+static void
+gst_vaapi_encoder_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoder *encoder = GST_VAAPI_ENCODER (object);
+  GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  switch (prop_id) {
+    case ENCODER_PROP_DISPLAY:
+      g_assert (encoder->display == NULL);
+      encoder->display = g_value_dup_object (value);
+      g_assert (encoder->display != NULL);
+      encoder->va_display = GST_VAAPI_DISPLAY_VADISPLAY (encoder->display);
+      break;
+    case ENCODER_PROP_BITRATE:
+      status = gst_vaapi_encoder_set_bitrate (encoder,
+          g_value_get_uint (value));
+      break;
+    case ENCODER_PROP_TARGET_PERCENTAGE:
+      status =
+          gst_vaapi_encoder_set_target_percentage (encoder,
+          g_value_get_uint (value));
+      break;
+    case ENCODER_PROP_KEYFRAME_PERIOD:
+      status =
+          gst_vaapi_encoder_set_keyframe_period (encoder,
+          g_value_get_uint (value));
+      break;
+    case ENCODER_PROP_QUALITY_LEVEL:
+      status =
+          gst_vaapi_encoder_set_quality_level (encoder,
+          g_value_get_uint (value));
+      break;
+    case ENCODER_PROP_DEFAULT_ROI_VALUE:
+      encoder->default_roi_value = g_value_get_int (value);
+      status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
+      break;
+    case ENCODER_PROP_TRELLIS:
+      status =
+          gst_vaapi_encoder_set_trellis (encoder, g_value_get_boolean (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+
+  if (status)
+    GST_WARNING_OBJECT (encoder, "Failed to set the property:%s, error is %d",
+        g_param_spec_get_name (pspec), status);
+}
+
+static void
+gst_vaapi_encoder_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoder *encoder = GST_VAAPI_ENCODER (object);
+
+  switch (prop_id) {
+    case ENCODER_PROP_DISPLAY:
+      g_value_set_object (value, encoder->display);
+      break;
+    case ENCODER_PROP_BITRATE:
+      g_value_set_uint (value, encoder->bitrate);
+      break;
+    case ENCODER_PROP_TARGET_PERCENTAGE:
+      g_value_set_uint (value, encoder->target_percentage);
+      break;
+    case ENCODER_PROP_KEYFRAME_PERIOD:
+      g_value_set_uint (value, encoder->keyframe_period);
+      break;
+    case ENCODER_PROP_QUALITY_LEVEL:
+      g_value_set_uint (value, GST_VAAPI_ENCODER_QUALITY_LEVEL (encoder));
+      break;
+    case ENCODER_PROP_DEFAULT_ROI_VALUE:
+      g_value_set_int (value, encoder->default_roi_value);
+      break;
+    case ENCODER_PROP_TRELLIS:
+      g_value_set_boolean (value, encoder->trellis);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_encoder_init (GstVaapiEncoder * encoder)
+{
+  encoder->va_context = VA_INVALID_ID;
+
+  gst_video_info_init (&encoder->video_info);
+
+  g_mutex_init (&encoder->mutex);
+  g_cond_init (&encoder->surface_free);
+  g_cond_init (&encoder->codedbuf_free);
+
+  encoder->codedbuf_queue = g_async_queue_new_full ((GDestroyNotify)
+      gst_vaapi_coded_buffer_proxy_unref);
+}
+
+/* Base encoder cleanup (internal) */
+static void
+gst_vaapi_encoder_finalize (GObject * object)
+{
+  GstVaapiEncoder *encoder = GST_VAAPI_ENCODER (object);
+
+  if (encoder->context)
+    gst_vaapi_context_unref (encoder->context);
+  encoder->context = NULL;
+  gst_vaapi_display_replace (&encoder->display, NULL);
+  encoder->va_display = NULL;
+
+  if (encoder->properties) {
+    g_ptr_array_unref (encoder->properties);
+    encoder->properties = NULL;
+  }
+
+  gst_vaapi_video_pool_replace (&encoder->codedbuf_pool, NULL);
+  if (encoder->codedbuf_queue) {
+    g_async_queue_unref (encoder->codedbuf_queue);
+    encoder->codedbuf_queue = NULL;
+  }
+  g_cond_clear (&encoder->surface_free);
+  g_cond_clear (&encoder->codedbuf_free);
+  g_mutex_clear (&encoder->mutex);
+
+  G_OBJECT_CLASS (gst_vaapi_encoder_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_encoder_class_init (GstVaapiEncoderClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = gst_vaapi_encoder_set_property;
+  object_class->get_property = gst_vaapi_encoder_get_property;
+  object_class->finalize = gst_vaapi_encoder_finalize;
+
+  /**
+   * GstVaapiDecoder:display:
+   *
+   * #GstVaapiDisplay to be used.
+   */
+  properties[ENCODER_PROP_DISPLAY] =
+      g_param_spec_object ("display", "Gst VA-API Display",
+      "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY,
+      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME);
+
+  /**
+   * GstVaapiEncoder:bitrate:
+   *
+   * The desired bitrate, expressed in kbps.
+   * This is available when rate-control is CBR or VBR.
+   *
+   * CBR: This applies equally to minimum, maximum and target bitrate in the driver.
+   * VBR: This applies to maximum bitrate in the driver.
+   *      Minimum bitrate will be calculated like the following in the driver.
+   *      if (target percentage < 50) minimum bitrate = 0
+   *      else minimum bitrate = maximum bitrate * (2 * target percentage -100) / 100
+   *      Target bitrate will be calculated like the following in the driver.
+   *      target bitrate = maximum bitrate * target percentage / 100
+   */
+  properties[ENCODER_PROP_BITRATE] =
+      g_param_spec_uint ("bitrate",
+      "Bitrate (kbps)",
+      "The desired bitrate expressed in kbps (0: auto-calculate)",
+      0, 2000 * 1024, 0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoder:target-percentage:
+   *
+   * The desired target percentage of bitrate for variable rate controls.
+   */
+  properties[ENCODER_PROP_TARGET_PERCENTAGE] =
+      g_param_spec_uint ("target-percentage",
+      "Target Percentage",
+      "The desired target percentage of bitrate for variable rate "
+      "controls.", 1, 100, 70,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoder:keyframe-period:
+   *
+   * The maximal distance between two keyframes.
+   */
+  properties[ENCODER_PROP_KEYFRAME_PERIOD] =
+      g_param_spec_uint ("keyframe-period",
+      "Keyframe Period",
+      "Maximal distance between two keyframes (0: auto-calculate)", 0,
+      G_MAXUINT32, 30,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoder:quality-level:
+   *
+   * The Encoding quality level.
+   */
+  properties[ENCODER_PROP_QUALITY_LEVEL] =
+      g_param_spec_uint ("quality-level",
+      "Quality Level", "Encoding Quality Level "
+      "(lower value means higher-quality/slow-encode, "
+      " higher value means lower-quality/fast-encode)",
+      1, 7, 4, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVapiEncoder:roi-default-delta-qp
+   *
+   * Default delta-qp to apply to each Region of Interest
+   */
+  properties[ENCODER_PROP_DEFAULT_ROI_VALUE] =
+      g_param_spec_int ("default-roi-delta-qp", "Default ROI delta QP",
+      "The default delta-qp to apply to each Region of Interest"
+      "(lower value means higher-quality, "
+      "higher value means lower-quality)",
+      -10, 10, -10,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoder: trellis:
+   *
+   * The trellis quantization method the encoder can use.
+   * Trellis is an improved quantization algorithm.
+   *
+   */
+  properties[ENCODER_PROP_TRELLIS] =
+      g_param_spec_boolean ("trellis",
+      "Trellis Quantization",
+      "The Trellis Quantization Method of Encoder",
+      FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  g_object_class_install_properties (object_class, ENCODER_N_PROPERTIES,
+      properties);
+}
+
+static GstVaapiContext *
+create_test_context_config (GstVaapiEncoder * encoder, GstVaapiProfile profile)
+{
+  GstVaapiContextInfo cip = { 0, };
+  GstVaapiContext *ctxt;
+
+  g_assert (profile != GST_VAAPI_PROFILE_UNKNOWN);
+
+  cip.profile = profile;
+  cip.entrypoint = gst_vaapi_encoder_get_entrypoint (encoder, profile);
+  if (cip.entrypoint == GST_VAAPI_ENTRYPOINT_INVALID) {
+    GST_INFO ("can not find %s entrypoint for profile %s to create"
+        " text context. Ignore this profile",
+        GST_VAAPI_ENCODER_TUNE (encoder) == GST_VAAPI_ENCODER_TUNE_LOW_POWER ?
+        "the low-power" : "an available",
+        gst_vaapi_profile_get_va_name (profile));
+    return NULL;
+  }
+
+  init_context_info (encoder, &cip);
+  ctxt = gst_vaapi_context_new (encoder->display, &cip);
+  return ctxt;
+}
+
+static gboolean
+get_profile_surface_attributes (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile, GstVaapiConfigSurfaceAttributes * attribs)
+{
+  GstVaapiContext *ctxt = NULL;
+  gboolean ret;
+
+  g_return_val_if_fail (attribs != NULL, FALSE);
+  g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN, FALSE);
+
+  ctxt = create_test_context_config (encoder, profile);
+  if (!ctxt)
+    return FALSE;
+
+  ret = gst_vaapi_context_get_surface_attributes (ctxt, attribs);
+  if (ret) {
+    attribs->formats = gst_vaapi_context_get_surface_formats (ctxt);
+
+    if (!attribs->formats)
+      ret = FALSE;
+  }
+
+  gst_vaapi_context_unref (ctxt);
+  return ret;
+}
+
+static gboolean
+merge_profile_surface_attributes (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile, GstVaapiConfigSurfaceAttributes * attribs)
+{
+  GstVaapiConfigSurfaceAttributes attr = { 0, };
+  guint i, j;
+  GstVideoFormat fmt, sfmt;
+
+  if (profile == GST_VAAPI_PROFILE_UNKNOWN)
+    return FALSE;
+
+  if (!get_profile_surface_attributes (encoder, profile, &attr))
+    return FALSE;
+
+  for (i = 0; i < attr.formats->len; i++) {
+    sfmt = g_array_index (attr.formats, GstVideoFormat, i);
+    for (j = 0; j < attribs->formats->len; j++) {
+      fmt = g_array_index (attribs->formats, GstVideoFormat, j);
+      if (fmt == sfmt)
+        break;
+    }
+    if (j >= attribs->formats->len)
+      g_array_append_val (attribs->formats, sfmt);
+  }
+
+  g_array_unref (attr.formats);
+
+  attribs->min_width = MIN (attribs->min_width, attr.min_width);
+  attribs->min_height = MIN (attribs->min_height, attr.min_height);
+  attribs->max_width = MAX (attribs->max_width, attr.max_width);
+  attribs->max_height = MAX (attribs->max_height, attr.max_height);
+  attribs->mem_types &= attr.mem_types;
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_encoder_get_surface_attributres:
+ * @encoder: a #GstVaapiEncoder instances
+ * @profiles: a #GArray of #GstVaapiProfile to be test
+ * @min_width (out): the minimal surface width
+ * @min_height (out): the minimal surface height
+ * @max_width (out): the maximal surface width
+ * @max_height (out): the maximal surface height
+ *
+ * Fetches the valid surface's attributes for the specified @profiles
+ *
+ * Returns: a #GArray of valid formats we get or %NULL if failed.
+ **/
+GArray *
+gst_vaapi_encoder_get_surface_attributes (GstVaapiEncoder * encoder,
+    GArray * profiles, gint * min_width, gint * min_height,
+    gint * max_width, gint * max_height, guint * mem_types)
+{
+  GstVaapiConfigSurfaceAttributes attribs = {
+    G_MAXINT, G_MAXINT, 1, 1, G_MAXUINT, NULL
+  };
+  GstVaapiProfile profile;
+  guint i;
+
+  attribs.formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
+  for (i = 0; i < profiles->len; i++) {
+    profile = g_array_index (profiles, GstVaapiProfile, i);
+    g_assert (profile != GST_VAAPI_PROFILE_UNKNOWN);
+    GST_LOG ("Detect input formats of profile %s",
+        gst_vaapi_profile_get_va_name (profile));
+
+    if (!merge_profile_surface_attributes (encoder, profile, &attribs)) {
+      GST_INFO ("Can not get surface formats for profile %s",
+          gst_vaapi_profile_get_va_name (profile));
+      continue;
+    }
+  }
+
+  if (attribs.formats->len == 0) {
+    g_array_unref (attribs.formats);
+    return NULL;
+  }
+
+  if (min_width)
+    *min_width = attribs.min_width;
+  if (min_height)
+    *min_height = attribs.min_height;
+  if (max_width)
+    *max_width = attribs.max_width;
+  if (max_height)
+    *max_height = attribs.max_height;
+  if (mem_types)
+    *mem_types = attribs.mem_types;
+  return attribs.formats;
+}
+
+/**
+ * gst_vaapi_encoder_ensure_num_slices:
+ * @encoder: a #GstVaapiEncoder
+ * @profile: a #GstVaapiProfile
+ * @entrypoint: a #GstVaapiEntrypoint
+ * @media_max_slices: the number of the slices permitted by the stream
+ * @num_slices: (out): the possible number of slices to process
+ *
+ * This function will clamp the @num_slices provided by the user,
+ * according the limit of the number of slices permitted by the stream
+ * and by the hardware.
+ *
+ * We need to pass the @profile and the @entrypoint, because at the
+ * moment the encoder base class, still doesn't have them assigned,
+ * and this function is meant to be called by the derived classes
+ * while they are configured.
+ *
+ * Returns: %TRUE if the number of slices is different than zero.
+ **/
+gboolean
+gst_vaapi_encoder_ensure_num_slices (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint,
+    guint media_max_slices, guint * num_slices)
+{
+  VAProfile va_profile;
+  VAEntrypoint va_entrypoint;
+  guint max_slices, num;
+
+  va_profile = gst_vaapi_profile_get_va_profile (profile);
+  va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint (entrypoint);
+
+  if (!gst_vaapi_get_config_attribute (encoder->display, va_profile,
+          va_entrypoint, VAConfigAttribEncMaxSlices, &max_slices)) {
+    *num_slices = 1;
+    return TRUE;
+  }
+
+  num = *num_slices;
+  if (num > max_slices)
+    num = max_slices;
+  if (num > media_max_slices)
+    num = media_max_slices;
+
+  if (num == 0)
+    return FALSE;
+  *num_slices = num;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_encoder_ensure_max_num_ref_frames:
+ * @encoder: a #GstVaapiEncoder
+ * @profile: a #GstVaapiProfile
+ * @entrypoint: a #GstVaapiEntrypoint
+ *
+ * This function will query VAConfigAttribEncMaxRefFrames to get the
+ * maximum number of reference frames in the driver,
+ * for both the reference picture list 0 (bottom 16 bits) and
+ * the reference picture list 1 (top 16 bits).
+ *
+ * We need to pass the @profile and the @entrypoint, because at the
+ * moment the encoder base class, still doesn't have them assigned,
+ * and this function is meant to be called by the derived classes
+ * while they are configured.
+ *
+ * Returns: %TRUE if the number of reference frames is different than zero.
+ **/
+gboolean
+gst_vaapi_encoder_ensure_max_num_ref_frames (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
+{
+  VAProfile va_profile;
+  VAEntrypoint va_entrypoint;
+  guint max_ref_frames;
+
+  va_profile = gst_vaapi_profile_get_va_profile (profile);
+  va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint (entrypoint);
+
+  if (!gst_vaapi_get_config_attribute (encoder->display, va_profile,
+          va_entrypoint, VAConfigAttribEncMaxRefFrames, &max_ref_frames)) {
+    /* Set the default the number of reference frames */
+    encoder->max_num_ref_frames_0 = 1;
+    encoder->max_num_ref_frames_1 = 0;
+    return TRUE;
+  }
+
+  encoder->max_num_ref_frames_0 = max_ref_frames & 0xffff;
+  encoder->max_num_ref_frames_1 = (max_ref_frames >> 16) & 0xffff;
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_encoder_ensure_tile_support:
+ * @encoder: a #GstVaapiEncoder
+ * @profile: a #GstVaapiProfile
+ * @entrypoint: a #GstVaapiEntrypoint
+ *
+ * This function will query VAConfigAttribEncTileSupport to check
+ * whether the encoder support tile.
+ *
+ * We need to pass the @profile and the @entrypoint, because at the
+ * moment the encoder base class, still doesn't have them assigned,
+ * and this function is meant to be called by the derived classes
+ * while they are configured.
+ *
+ * Returns: %TRUE if supported, %FALSE if not.
+ **/
+gboolean
+gst_vaapi_encoder_ensure_tile_support (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint)
+{
+  guint tile = 0;
+
+#if VA_CHECK_VERSION(1,0,1)
+  VAProfile va_profile;
+  VAEntrypoint va_entrypoint;
+
+  va_profile = gst_vaapi_profile_get_va_profile (profile);
+  va_entrypoint = gst_vaapi_entrypoint_get_va_entrypoint (entrypoint);
+
+  if (!gst_vaapi_get_config_attribute (encoder->display, va_profile,
+          va_entrypoint, VAConfigAttribEncTileSupport, &tile))
+    return FALSE;
+#endif
+
+  return tile > 0;
+}
+
+GstVaapiProfile
+gst_vaapi_encoder_get_profile (GstVaapiEncoder * encoder)
+{
+  g_return_val_if_fail (encoder, GST_VAAPI_PROFILE_UNKNOWN);
+
+  return encoder->profile;
+}
+
+/* Get the entrypoint based on the tune option. */
+/**
+ * gst_vaapi_encoder_get_entrypoint:
+ * @encoder: a #GstVaapiEncoder
+ * @profile: a #GstVaapiProfile
+ *
+ * This function will return the valid entrypoint of the @encoder for
+ * @profile. If the low-power mode(tune option) is set, only LP
+ * entrypoints will be considered. If not, the first available entry
+ * point will be return.
+ *
+ * Returns: The #GstVaapiEntrypoint.
+ **/
+GstVaapiEntrypoint
+gst_vaapi_encoder_get_entrypoint (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile)
+{
+  /* XXX: The profile may not be the same with encoder->profile */
+
+  g_return_val_if_fail (encoder, GST_VAAPI_ENTRYPOINT_INVALID);
+  g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN,
+      GST_VAAPI_ENTRYPOINT_INVALID);
+
+  if (profile == GST_VAAPI_PROFILE_JPEG_BASELINE)
+    return GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE;
+
+  if (GST_VAAPI_ENCODER_TUNE (encoder) == GST_VAAPI_ENCODER_TUNE_LOW_POWER) {
+    if (gst_vaapi_display_has_encoder (GST_VAAPI_ENCODER_DISPLAY (encoder),
+            profile, GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP))
+      return GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP;
+  } else {
+    /* If not set, choose the available one */
+    if (gst_vaapi_display_has_encoder (GST_VAAPI_ENCODER_DISPLAY (encoder),
+            profile, GST_VAAPI_ENTRYPOINT_SLICE_ENCODE))
+      return GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
+
+    if (gst_vaapi_display_has_encoder (GST_VAAPI_ENCODER_DISPLAY (encoder),
+            profile, GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP))
+      return GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP;
+  }
+
+  return GST_VAAPI_ENTRYPOINT_INVALID;
+}
+
+/**
+ * gst_vaapi_encoder_get_available_profiles:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Collect all supported #GstVaapiProfile of current @encoder's #GstVaapiCodec,
+ * and return them as a #GArray
+ *
+ * Returns: An #GArray of #GstVaapiProfile.
+ **/
+GArray *
+gst_vaapi_encoder_get_available_profiles (GstVaapiEncoder * encoder)
+{
+  GstVaapiCodec codec;
+  GArray *all_profiles = NULL;
+  GArray *profiles = NULL;
+  GstVaapiProfile profile;
+  guint i;
+
+  g_return_val_if_fail (encoder != NULL, 0);
+
+  codec = GST_VAAPI_ENCODER_GET_CLASS (encoder)->class_data->codec;
+
+  all_profiles = gst_vaapi_display_get_encode_profiles
+      (GST_VAAPI_ENCODER_DISPLAY (encoder));
+  if (!all_profiles)
+    goto out;
+
+  /* Add all supported profiles belong to current codec */
+  profiles = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile));
+  if (!profiles)
+    goto out;
+
+  for (i = 0; i < all_profiles->len; i++) {
+    profile = g_array_index (all_profiles, GstVaapiProfile, i);
+    if (gst_vaapi_profile_get_codec (profile) == codec)
+      g_array_append_val (profiles, profile);
+  }
+
+out:
+  if (all_profiles)
+    g_array_unref (all_profiles);
+  if (profiles && profiles->len == 0) {
+    g_array_unref (profiles);
+    profiles = NULL;
+  }
+
+  return profiles;
+}
+
+/** Returns a GType for the #GstVaapiEncoderTune set */
+GType
+gst_vaapi_encoder_tune_get_type (void)
+{
+  static gsize g_type = 0;
+
+  static const GEnumValue encoder_tune_values[] = {
+    /* *INDENT-OFF* */
+    { GST_VAAPI_ENCODER_TUNE_NONE,
+      "None", "none" },
+    { GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION,
+      "High compression", "high-compression" },
+    { GST_VAAPI_ENCODER_TUNE_LOW_LATENCY,
+      "Low latency", "low-latency" },
+    { GST_VAAPI_ENCODER_TUNE_LOW_POWER,
+      "Low power mode", "low-power" },
+    { 0, NULL, NULL },
+    /* *INDENT-ON* */
+  };
+
+  if (g_once_init_enter (&g_type)) {
+    GType type =
+        g_enum_register_static ("GstVaapiEncoderTune", encoder_tune_values);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+/** Returns a GType for the #GstVaapiEncoderMbbrc set */
+GType
+gst_vaapi_encoder_mbbrc_get_type (void)
+{
+  static gsize g_type = 0;
+
+  if (g_once_init_enter (&g_type)) {
+    static const GEnumValue encoder_mbbrc_values[] = {
+      {GST_VAAPI_ENCODER_MBBRC_AUTO, "Auto", "auto"},
+      {GST_VAAPI_ENCODER_MBBRC_ON, "On", "on"},
+      {GST_VAAPI_ENCODER_MBBRC_OFF, "Off", "off"},
+      {0, NULL, NULL},
+    };
+
+    GType type =
+        g_enum_register_static (g_intern_static_string ("GstVaapiEncoderMbbrc"),
+        encoder_mbbrc_values);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder.h
new file mode 100644 (file)
index 0000000..6bc9887
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ *  gstvaapiencoder.h - VA encoder abstraction
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_H
+#define GST_VAAPI_ENCODER_H
+
+#include <gst/video/gstvideoutils.h>
+#include <gst/vaapi/gstvaapicodedbufferproxy.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_ENCODER \
+    (gst_vaapi_encoder_get_type ())
+#define GST_VAAPI_ENCODER(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_ENCODER, GstVaapiEncoder))
+#define GST_VAAPI_IS_ENCODER(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_ENCODER))
+
+typedef struct _GstVaapiEncoder GstVaapiEncoder;
+
+GType
+gst_vaapi_encoder_get_type (void) G_GNUC_CONST;
+
+/**
+ * GST_VAAPI_PARAM_ENCODER_EXPOSURE: (value 65536)
+ *
+ * This user defined flag is added when the internal encoder class
+ * wants to expose its property gparam spec to the according encode
+ * class. */
+#define GST_VAAPI_PARAM_ENCODER_EXPOSURE GST_PARAM_USER_SHIFT
+
+/**
+ * GstVaapiEncoderStatus:
+ * @GST_VAAPI_ENCODER_STATUS_SUCCESS: Success.
+ * @GST_VAAPI_ENCODER_STATUS_NO_SURFACE: No surface left to encode.
+ * @GST_VAAPI_ENCODER_STATUS_NO_BUFFER: No coded buffer left to hold
+ *   the encoded picture.
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN: Unknown error.
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED: No memory left.
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED: The requested
+ *   operation failed to execute properly. e.g. invalid point in time to
+ *   execute the operation.
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL:
+ *   Unsupported rate control value.
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE: Unsupported profile.
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER: Invalid parameter.
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_BUFFER: Invalid buffer.
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_SURFACE: Invalid surface.
+ * @GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER: Invalid header.
+ *
+ * Set of #GstVaapiEncoder status codes.
+ */
+typedef enum
+{
+  GST_VAAPI_ENCODER_STATUS_SUCCESS = 0,
+  GST_VAAPI_ENCODER_STATUS_NO_SURFACE = 1,
+  GST_VAAPI_ENCODER_STATUS_NO_BUFFER = 2,
+
+  GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN = -1,
+  GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED = -2,
+  GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED = -3,
+  GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_RATE_CONTROL = -4,
+  GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE = -5,
+  GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_PARAMETER = -100,
+  GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_BUFFER = -101,
+  GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_SURFACE = -102,
+  GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER = -103,
+} GstVaapiEncoderStatus;
+
+/**
+ * GstVaapiEncoderTune:
+ * @GST_VAAPI_ENCODER_TUNE_NONE: No tuning option set.
+ * @GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION: Tune for higher compression
+ *   ratios, at the expense of lower compatibility at decoding time.
+ * @GST_VAAPI_ENCODER_TUNE_LOW_LATENCY: Tune for low latency decoding.
+ * @GST_VAAPI_ENCODER_TUNE_LOW_POWER: Tune encoder for low power /
+ *   resources conditions. This can affect compression ratio or visual
+ *   quality to match low power conditions.
+ *
+ * The set of tuning options for a #GstVaapiEncoder. By default,
+ * maximum compatibility for decoding is preferred, so the lowest
+ * coding tools are enabled.
+ */
+typedef enum {
+  GST_VAAPI_ENCODER_TUNE_NONE = 0,
+  GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION,
+  GST_VAAPI_ENCODER_TUNE_LOW_LATENCY,
+  GST_VAAPI_ENCODER_TUNE_LOW_POWER,
+} GstVaapiEncoderTune;
+
+/**
+ * GstVaapiEncoderMbbrc:
+ * @GST_VAAPI_ENCODER_MBBRC_AUTO: bitrate control auto
+ * @GST_VAAPI_ENCODER_MBBRC_ON: bitrate control on
+ * @GST_VAAPI_ENCODER_MBBRC_OFF: bitrate control off
+ *
+ * Values for the macroblock level bitrate control.
+ *
+ * This property values are only available for H264 and H265 (HEVC)
+ * encoders, when rate control is not Constant QP.
+ **/
+typedef enum {
+  GST_VAAPI_ENCODER_MBBRC_AUTO = 0,
+  GST_VAAPI_ENCODER_MBBRC_ON = 1,
+  GST_VAAPI_ENCODER_MBBRC_OFF = 2,
+} GstVaapiEncoderMbbrc;
+
+GType
+gst_vaapi_encoder_tune_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapi_encoder_mbbrc_get_type (void) G_GNUC_CONST;
+
+void
+gst_vaapi_encoder_replace (GstVaapiEncoder ** old_encoder_ptr,
+    GstVaapiEncoder * new_encoder);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_get_codec_data (GstVaapiEncoder * encoder,
+    GstBuffer ** out_codec_data_ptr);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_codec_state (GstVaapiEncoder * encoder,
+    GstVideoCodecState * state);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_rate_control (GstVaapiEncoder * encoder,
+    GstVaapiRateControl rate_control);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_bitrate (GstVaapiEncoder * encoder, guint bitrate);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_target_percentage (GstVaapiEncoder * encoder,
+    guint target_percentage);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_put_frame (GstVaapiEncoder * encoder,
+    GstVideoCodecFrame * frame);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_keyframe_period (GstVaapiEncoder * encoder,
+    guint keyframe_period);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_tuning (GstVaapiEncoder * encoder,
+    GstVaapiEncoderTune tuning);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_quality_level (GstVaapiEncoder * encoder,
+    guint quality_level);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_set_trellis (GstVaapiEncoder * encoder, gboolean trellis);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_get_buffer_with_timeout (GstVaapiEncoder * encoder,
+    GstVaapiCodedBufferProxy ** out_codedbuf_proxy_ptr, guint64 timeout);
+
+GstVaapiEncoderStatus
+gst_vaapi_encoder_flush (GstVaapiEncoder * encoder);
+
+GArray *
+gst_vaapi_encoder_get_surface_attributes (GstVaapiEncoder * encoder,
+    GArray * profiles, gint * min_width, gint * min_height,
+    gint * max_width, gint * max_height, guint * mem_types);
+
+GstVaapiProfile
+gst_vaapi_encoder_get_profile (GstVaapiEncoder * encoder);
+
+GstVaapiEntrypoint
+gst_vaapi_encoder_get_entrypoint (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile);
+
+GArray *
+gst_vaapi_encoder_get_available_profiles (GstVaapiEncoder * encoder);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoder, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_ENCODER_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h264.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h264.c
new file mode 100644 (file)
index 0000000..ad56cca
--- /dev/null
@@ -0,0 +1,4166 @@
+/*
+ *  gstvaapiencoder_h264.c - H.264 encoder
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#define GLIB_DISABLE_DEPRECATION_WARNINGS
+
+#include "sysdeps.h"
+#include <gst/base/gstbitwriter.h>
+#include <gst/codecparsers/gsth264parser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiencoder_priv.h"
+#include "gstvaapiencoder_h264.h"
+#include "gstvaapiutils_h264.h"
+#include "gstvaapiutils_h264_priv.h"
+#include "gstvaapiutils_h26x_priv.h"
+#include "gstvaapicodedbufferproxy_priv.h"
+#include "gstvaapisurface.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+
+/* Define the maximum number of views supported */
+#define MAX_NUM_VIEWS 10
+
+/* Define the maximum value for view-id */
+#define MAX_VIEW_ID 1023
+
+/* Define default temporal levels */
+#define MIN_TEMPORAL_LEVELS 1
+#define MAX_TEMPORAL_LEVELS 4
+
+/* Supported set of VA rate controls, within this implementation */
+#define SUPPORTED_RATECONTROLS                          \
+  (GST_VAAPI_RATECONTROL_MASK (CQP)  |                  \
+   GST_VAAPI_RATECONTROL_MASK (CBR)  |                  \
+   GST_VAAPI_RATECONTROL_MASK (VBR)  |                  \
+   GST_VAAPI_RATECONTROL_MASK (VBR_CONSTRAINED)  |      \
+   GST_VAAPI_RATECONTROL_MASK (ICQ)  |                  \
+   GST_VAAPI_RATECONTROL_MASK (QVBR))
+
+/* Supported set of tuning options, within this implementation */
+#define SUPPORTED_TUNE_OPTIONS                          \
+  (GST_VAAPI_ENCODER_TUNE_MASK (NONE) |                 \
+   GST_VAAPI_ENCODER_TUNE_MASK (HIGH_COMPRESSION) |     \
+   GST_VAAPI_ENCODER_TUNE_MASK (LOW_POWER))
+
+/* Supported set of VA packed headers, within this implementation */
+#define SUPPORTED_PACKED_HEADERS                \
+  (VA_ENC_PACKED_HEADER_SEQUENCE |              \
+   VA_ENC_PACKED_HEADER_PICTURE  |              \
+   VA_ENC_PACKED_HEADER_SLICE    |              \
+   VA_ENC_PACKED_HEADER_RAW_DATA |              \
+   VA_ENC_PACKED_HEADER_MISC)
+
+#define GST_H264_NAL_REF_IDC_NONE        0
+#define GST_H264_NAL_REF_IDC_LOW         1
+#define GST_H264_NAL_REF_IDC_MEDIUM      2
+#define GST_H264_NAL_REF_IDC_HIGH        3
+
+typedef enum
+{
+  GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_STRICT = 0,
+  GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_RESTRICT_CODED_BUFFER_ALLOC = 1,
+} GstVaapiEncoderH264ComplianceMode;
+
+static GType
+gst_vaapi_encoder_h264_compliance_mode_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_STRICT,
+            "Strict compliance to the H264 Specification ",
+          "strict"},
+      /* The main intention is to reduce the CodedBuffer Size allocation.
+       * This will help to get better performance in some of the Intel
+       * platforms which has LLC restirictions */
+      {GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_RESTRICT_CODED_BUFFER_ALLOC,
+            "Restrict the allocation size of coded-buffer",
+          "restrict-buf-alloc"},
+      {0, NULL, NULL},
+    };
+
+    gtype =
+        g_enum_register_static ("GstVaapiEncoderH264ComplianceMode", values);
+  }
+  return gtype;
+}
+
+typedef enum
+{
+  GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT,
+  GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_P,
+  GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B
+} GstVaapiEncoderH264PredictionType;
+
+static GType
+gst_vaapi_encoder_h264_prediction_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT,
+            "Default encode, prev/next frame as ref ",
+          "default"},
+      {GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_P,
+            "Hierarchical P frame encode",
+          "hierarchical-p"},
+      {GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B,
+            "Hierarchical B frame encode",
+          "hierarchical-b"},
+      {0, NULL, NULL},
+    };
+
+    gtype =
+        g_enum_register_static ("GstVaapiEncoderH264PredictionType", values);
+  }
+  return gtype;
+}
+
+/* only for internal usage, values won't be equal to actual payload type */
+typedef enum
+{
+  GST_VAAPI_H264_SEI_UNKNOWN = 0,
+  GST_VAAPI_H264_SEI_BUF_PERIOD = (1 << 0),
+  GST_VAAPI_H264_SEI_PIC_TIMING = (1 << 1)
+} GstVaapiH264SeiPayloadType;
+
+typedef struct
+{
+  GstVaapiSurfaceProxy *pic;
+  guint poc;
+  guint frame_num;
+  guint temporal_id;
+} GstVaapiEncoderH264Ref;
+
+typedef enum
+{
+  GST_VAAPI_ENC_H264_REORD_NONE = 0,
+  GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES = 1,
+  GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES = 2
+} GstVaapiEncH264ReorderState;
+
+typedef struct _GstVaapiH264ViewRefPool
+{
+  GQueue ref_list;
+  guint max_ref_frames;
+  guint max_reflist0_count;
+  guint max_reflist1_count;
+} GstVaapiH264ViewRefPool;
+
+typedef struct _GstVaapiH264ViewReorderPool
+{
+  GQueue reorder_frame_list;
+  guint reorder_state;
+  guint frame_index;
+  guint frame_count;            /* monotonically increasing with in every idr period */
+  guint cur_frame_num;
+  guint cur_present_index;
+  gboolean prev_frame_is_ref;   /* previous frame is ref or not */
+} GstVaapiH264ViewReorderPool;
+
+static inline gboolean
+_poc_greater_than (guint poc1, guint poc2, guint max_poc)
+{
+  return (((poc1 - poc2) & (max_poc - 1)) < max_poc / 2);
+}
+
+/* Get slice_type value for H.264 specification */
+static guint8
+h264_get_slice_type (GstVaapiPictureType type)
+{
+  switch (type) {
+    case GST_VAAPI_PICTURE_TYPE_I:
+      return GST_H264_I_SLICE;
+    case GST_VAAPI_PICTURE_TYPE_P:
+      return GST_H264_P_SLICE;
+    case GST_VAAPI_PICTURE_TYPE_B:
+      return GST_H264_B_SLICE;
+    default:
+      break;
+  }
+  return -1;
+}
+
+/* Get log2_max_frame_num value for H.264 specification */
+static guint
+h264_get_log2_max_frame_num (guint num)
+{
+  guint ret = 0;
+
+  while (num) {
+    ++ret;
+    num >>= 1;
+  }
+  if (ret <= 4)
+    ret = 4;
+  else if (ret > 10)
+    ret = 10;
+  /* must be greater than 4 */
+  return ret;
+}
+
+/* Determines the cpbBrNalFactor based on the supplied profile */
+static guint
+h264_get_cpb_nal_factor (GstVaapiProfile profile)
+{
+  guint f;
+
+  /* Table A-2 */
+  switch (profile) {
+    case GST_VAAPI_PROFILE_H264_HIGH:
+      f = 1500;
+      break;
+    case GST_VAAPI_PROFILE_H264_HIGH10:
+      f = 3600;
+      break;
+    case GST_VAAPI_PROFILE_H264_HIGH_422:
+    case GST_VAAPI_PROFILE_H264_HIGH_444:
+      f = 4800;
+      break;
+    case GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH:
+    case GST_VAAPI_PROFILE_H264_STEREO_HIGH:
+      f = 1500;                 /* H.10.2.1 (r) */
+      break;
+    default:
+      f = 1200;
+      break;
+  }
+  return f;
+}
+
+/* Write the NAL unit header */
+static gboolean
+bs_write_nal_header (GstBitWriter * bs, guint32 nal_ref_idc,
+    guint32 nal_unit_type)
+{
+  WRITE_UINT32 (bs, 0, 1);
+  WRITE_UINT32 (bs, nal_ref_idc, 2);
+  WRITE_UINT32 (bs, nal_unit_type, 5);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write NAL unit header");
+    return FALSE;
+  }
+}
+
+/* Write the MVC NAL unit header extension */
+static gboolean
+bs_write_nal_header_mvc_extension (GstBitWriter * bs,
+    GstVaapiEncPicture * picture, guint32 view_id)
+{
+  guint32 svc_extension_flag = 0;
+  guint32 non_idr_flag = 1;
+  guint32 priority_id = 0;
+  guint32 temporal_id = 0;
+  guint32 anchor_pic_flag = 0;
+  guint32 inter_view_flag = 0;
+
+  if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
+    non_idr_flag = 0;
+
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
+    anchor_pic_flag = 1;
+  /* svc_extension_flag == 0 for mvc stream */
+  WRITE_UINT32 (bs, svc_extension_flag, 1);
+
+  WRITE_UINT32 (bs, non_idr_flag, 1);
+  WRITE_UINT32 (bs, priority_id, 6);
+  WRITE_UINT32 (bs, view_id, 10);
+  WRITE_UINT32 (bs, temporal_id, 3);
+  WRITE_UINT32 (bs, anchor_pic_flag, 1);
+  WRITE_UINT32 (bs, inter_view_flag, 1);
+  WRITE_UINT32 (bs, 1, 1);
+
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write NAL unit header");
+    return FALSE;
+  }
+}
+
+/* Write the NAL unit trailing bits */
+static gboolean
+bs_write_trailing_bits (GstBitWriter * bs)
+{
+  if (!gst_bit_writer_put_bits_uint32 (bs, 1, 1))
+    goto bs_error;
+  gst_bit_writer_align_bytes_unchecked (bs, 0);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write NAL unit trailing bits");
+    return FALSE;
+  }
+}
+
+/* Write an SPS NAL unit */
+static gboolean
+bs_write_sps_data (GstBitWriter * bs,
+    const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile,
+    GstVaapiRateControl rate_control, const VAEncMiscParameterHRD * hrd_params)
+{
+  guint8 profile_idc;
+  guint32 constraint_set0_flag, constraint_set1_flag;
+  guint32 constraint_set2_flag, constraint_set3_flag;
+  guint32 gaps_in_frame_num_value_allowed_flag = 0;     // ??
+  gboolean nal_hrd_parameters_present_flag;
+
+  guint32 b_qpprime_y_zero_transform_bypass = 0;
+  guint32 residual_color_transform_flag = 0;
+  guint32 cbr_flag = rate_control == GST_VAAPI_RATECONTROL_CBR ? 1 : 0;
+  guint32 pic_height_in_map_units =
+      (seq_param->seq_fields.bits.frame_mbs_only_flag ?
+      seq_param->picture_height_in_mbs : seq_param->picture_height_in_mbs / 2);
+  guint32 mb_adaptive_frame_field =
+      !seq_param->seq_fields.bits.frame_mbs_only_flag;
+  guint32 i = 0;
+
+  profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
+  constraint_set0_flag =        /* A.2.1 (baseline profile constraints) */
+      profile == GST_VAAPI_PROFILE_H264_BASELINE ||
+      profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
+  constraint_set1_flag =        /* A.2.2 (main profile constraints) */
+      profile == GST_VAAPI_PROFILE_H264_MAIN ||
+      profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
+  constraint_set2_flag = 0;
+  constraint_set3_flag = 0;
+
+  /* profile_idc */
+  WRITE_UINT32 (bs, profile_idc, 8);
+  /* constraint_set0_flag */
+  WRITE_UINT32 (bs, constraint_set0_flag, 1);
+  /* constraint_set1_flag */
+  WRITE_UINT32 (bs, constraint_set1_flag, 1);
+  /* constraint_set2_flag */
+  WRITE_UINT32 (bs, constraint_set2_flag, 1);
+  /* constraint_set3_flag */
+  WRITE_UINT32 (bs, constraint_set3_flag, 1);
+  /* reserved_zero_4bits */
+  WRITE_UINT32 (bs, 0, 4);
+  /* level_idc */
+  WRITE_UINT32 (bs, seq_param->level_idc, 8);
+  /* seq_parameter_set_id */
+  WRITE_UE (bs, seq_param->seq_parameter_set_id);
+
+  if (profile == GST_VAAPI_PROFILE_H264_HIGH ||
+      profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH ||
+      profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) {
+    /* for high profile */
+    /* chroma_format_idc  = 1, 4:2:0 */
+    WRITE_UE (bs, seq_param->seq_fields.bits.chroma_format_idc);
+    if (3 == seq_param->seq_fields.bits.chroma_format_idc) {
+      WRITE_UINT32 (bs, residual_color_transform_flag, 1);
+    }
+    /* bit_depth_luma_minus8 */
+    WRITE_UE (bs, seq_param->bit_depth_luma_minus8);
+    /* bit_depth_chroma_minus8 */
+    WRITE_UE (bs, seq_param->bit_depth_chroma_minus8);
+    /* b_qpprime_y_zero_transform_bypass */
+    WRITE_UINT32 (bs, b_qpprime_y_zero_transform_bypass, 1);
+
+    /* seq_scaling_matrix_present_flag  */
+    g_assert (seq_param->seq_fields.bits.seq_scaling_matrix_present_flag == 0);
+    WRITE_UINT32 (bs,
+        seq_param->seq_fields.bits.seq_scaling_matrix_present_flag, 1);
+
+#if 0
+    if (seq_param->seq_fields.bits.seq_scaling_matrix_present_flag) {
+      for (i = 0;
+          i < (seq_param->seq_fields.bits.chroma_format_idc != 3 ? 8 : 12);
+          i++) {
+        gst_bit_writer_put_bits_uint8 (bs,
+            seq_param->seq_fields.bits.seq_scaling_list_present_flag, 1);
+        if (seq_param->seq_fields.bits.seq_scaling_list_present_flag) {
+          g_assert (0);
+          /* FIXME, need write scaling list if seq_scaling_matrix_present_flag ==1 */
+        }
+      }
+    }
+#endif
+  }
+
+  /* log2_max_frame_num_minus4 */
+  WRITE_UE (bs, seq_param->seq_fields.bits.log2_max_frame_num_minus4);
+  /* pic_order_cnt_type */
+  WRITE_UE (bs, seq_param->seq_fields.bits.pic_order_cnt_type);
+
+  if (seq_param->seq_fields.bits.pic_order_cnt_type == 0) {
+    /* log2_max_pic_order_cnt_lsb_minus4 */
+    WRITE_UE (bs, seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);
+  } else if (seq_param->seq_fields.bits.pic_order_cnt_type == 1) {
+    g_assert (0 && "only POC type 0 is supported");
+    WRITE_UINT32 (bs,
+        seq_param->seq_fields.bits.delta_pic_order_always_zero_flag, 1);
+    WRITE_SE (bs, seq_param->offset_for_non_ref_pic);
+    WRITE_SE (bs, seq_param->offset_for_top_to_bottom_field);
+    WRITE_UE (bs, seq_param->num_ref_frames_in_pic_order_cnt_cycle);
+    for (i = 0; i < seq_param->num_ref_frames_in_pic_order_cnt_cycle; i++) {
+      WRITE_SE (bs, seq_param->offset_for_ref_frame[i]);
+    }
+  }
+
+  /* num_ref_frames */
+  WRITE_UE (bs, seq_param->max_num_ref_frames);
+  /* gaps_in_frame_num_value_allowed_flag */
+  WRITE_UINT32 (bs, gaps_in_frame_num_value_allowed_flag, 1);
+
+  /* pic_width_in_mbs_minus1 */
+  WRITE_UE (bs, seq_param->picture_width_in_mbs - 1);
+  /* pic_height_in_map_units_minus1 */
+  WRITE_UE (bs, pic_height_in_map_units - 1);
+  /* frame_mbs_only_flag */
+  WRITE_UINT32 (bs, seq_param->seq_fields.bits.frame_mbs_only_flag, 1);
+
+  if (!seq_param->seq_fields.bits.frame_mbs_only_flag) {        //ONLY mbs
+    g_assert (0 && "only progressive frames encoding is supported");
+    WRITE_UINT32 (bs, mb_adaptive_frame_field, 1);
+  }
+
+  /* direct_8x8_inference_flag */
+  WRITE_UINT32 (bs, 0, 1);
+  /* frame_cropping_flag */
+  WRITE_UINT32 (bs, seq_param->frame_cropping_flag, 1);
+
+  if (seq_param->frame_cropping_flag) {
+    /* frame_crop_left_offset */
+    WRITE_UE (bs, seq_param->frame_crop_left_offset);
+    /* frame_crop_right_offset */
+    WRITE_UE (bs, seq_param->frame_crop_right_offset);
+    /* frame_crop_top_offset */
+    WRITE_UE (bs, seq_param->frame_crop_top_offset);
+    /* frame_crop_bottom_offset */
+    WRITE_UE (bs, seq_param->frame_crop_bottom_offset);
+  }
+
+  /* vui_parameters_present_flag */
+  WRITE_UINT32 (bs, seq_param->vui_parameters_present_flag, 1);
+  if (seq_param->vui_parameters_present_flag) {
+    /* aspect_ratio_info_present_flag */
+    WRITE_UINT32 (bs,
+        seq_param->vui_fields.bits.aspect_ratio_info_present_flag, 1);
+    if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) {
+      WRITE_UINT32 (bs, seq_param->aspect_ratio_idc, 8);
+      if (seq_param->aspect_ratio_idc == 0xFF) {
+        WRITE_UINT32 (bs, seq_param->sar_width, 16);
+        WRITE_UINT32 (bs, seq_param->sar_height, 16);
+      }
+    }
+
+    /* overscan_info_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* video_signal_type_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* chroma_loc_info_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+
+    /* timing_info_present_flag */
+    WRITE_UINT32 (bs, seq_param->vui_fields.bits.timing_info_present_flag, 1);
+    if (seq_param->vui_fields.bits.timing_info_present_flag) {
+      WRITE_UINT32 (bs, seq_param->num_units_in_tick, 32);
+      WRITE_UINT32 (bs, seq_param->time_scale, 32);
+      WRITE_UINT32 (bs, 1, 1);  /* fixed_frame_rate_flag */
+    }
+
+    /* nal_hrd_parameters_present_flag */
+    nal_hrd_parameters_present_flag = seq_param->bits_per_second > 0;
+    WRITE_UINT32 (bs, nal_hrd_parameters_present_flag, 1);
+    if (nal_hrd_parameters_present_flag) {
+      /* hrd_parameters */
+      /* cpb_cnt_minus1 */
+      WRITE_UE (bs, 0);
+      WRITE_UINT32 (bs, SX_BITRATE - 6, 4);     /* bit_rate_scale */
+      WRITE_UINT32 (bs, SX_CPB_SIZE - 4, 4);    /* cpb_size_scale */
+
+      for (i = 0; i < 1; ++i) {
+        /* bit_rate_value_minus1[0] */
+        WRITE_UE (bs, (seq_param->bits_per_second >> SX_BITRATE) - 1);
+        /* cpb_size_value_minus1[0] */
+        WRITE_UE (bs, (hrd_params->buffer_size >> SX_CPB_SIZE) - 1);
+        /* cbr_flag[0] */
+        WRITE_UINT32 (bs, cbr_flag, 1);
+      }
+      /* initial_cpb_removal_delay_length_minus1 */
+      WRITE_UINT32 (bs, 23, 5);
+      /* cpb_removal_delay_length_minus1 */
+      WRITE_UINT32 (bs, 23, 5);
+      /* dpb_output_delay_length_minus1 */
+      WRITE_UINT32 (bs, 23, 5);
+      /* time_offset_length  */
+      WRITE_UINT32 (bs, 23, 5);
+    }
+
+    /* vcl_hrd_parameters_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+
+    if (nal_hrd_parameters_present_flag
+        || 0 /*vcl_hrd_parameters_present_flag */ ) {
+      /* low_delay_hrd_flag */
+      WRITE_UINT32 (bs, 0, 1);
+    }
+    /* pic_struct_present_flag */
+    WRITE_UINT32 (bs, 1, 1);
+    /* bs_restriction_flag */
+    WRITE_UINT32 (bs, 0, 1);
+  }
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write SPS NAL unit");
+    return FALSE;
+  }
+}
+
+static gboolean
+bs_write_sps (GstBitWriter * bs,
+    const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile,
+    GstVaapiRateControl rate_control, const VAEncMiscParameterHRD * hrd_params)
+{
+  if (!bs_write_sps_data (bs, seq_param, profile, rate_control, hrd_params))
+    return FALSE;
+
+  /* rbsp_trailing_bits */
+  bs_write_trailing_bits (bs);
+
+  return FALSE;
+}
+
+static gboolean
+bs_write_subset_sps (GstBitWriter * bs,
+    const VAEncSequenceParameterBufferH264 * seq_param, GstVaapiProfile profile,
+    GstVaapiRateControl rate_control, guint num_views, guint16 * view_ids,
+    const VAEncMiscParameterHRD * hrd_params)
+{
+  guint32 i, j, k;
+
+  if (!bs_write_sps_data (bs, seq_param, profile, rate_control, hrd_params))
+    return FALSE;
+
+  if (profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH ||
+      profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH) {
+    guint32 num_views_minus1, num_level_values_signalled_minus1;
+
+    num_views_minus1 = num_views - 1;
+    g_assert (num_views_minus1 < 1024);
+
+    /* bit equal to one */
+    WRITE_UINT32 (bs, 1, 1);
+
+    WRITE_UE (bs, num_views_minus1);
+
+    for (i = 0; i <= num_views_minus1; i++)
+      WRITE_UE (bs, view_ids[i]);
+
+    for (i = 1; i <= num_views_minus1; i++) {
+      guint32 num_anchor_refs_l0 = 0;
+      guint32 num_anchor_refs_l1 = 0;
+
+      WRITE_UE (bs, num_anchor_refs_l0);
+      for (j = 0; j < num_anchor_refs_l0; j++)
+        WRITE_UE (bs, 0);
+
+      WRITE_UE (bs, num_anchor_refs_l1);
+      for (j = 0; j < num_anchor_refs_l1; j++)
+        WRITE_UE (bs, 0);
+    }
+
+    for (i = 1; i <= num_views_minus1; i++) {
+      guint32 num_non_anchor_refs_l0 = 0;
+      guint32 num_non_anchor_refs_l1 = 0;
+
+      WRITE_UE (bs, num_non_anchor_refs_l0);
+      for (j = 0; j < num_non_anchor_refs_l0; j++)
+        WRITE_UE (bs, 0);
+
+      WRITE_UE (bs, num_non_anchor_refs_l1);
+      for (j = 0; j < num_non_anchor_refs_l1; j++)
+        WRITE_UE (bs, 0);
+    }
+
+    /* num level values signalled minus1 */
+    num_level_values_signalled_minus1 = 0;
+    g_assert (num_level_values_signalled_minus1 < 64);
+    WRITE_UE (bs, num_level_values_signalled_minus1);
+
+    for (i = 0; i <= num_level_values_signalled_minus1; i++) {
+      guint16 num_applicable_ops_minus1 = 0;
+      g_assert (num_applicable_ops_minus1 < 1024);
+
+      WRITE_UINT32 (bs, seq_param->level_idc, 8);
+      WRITE_UE (bs, num_applicable_ops_minus1);
+
+      for (j = 0; j <= num_applicable_ops_minus1; j++) {
+        guint8 temporal_id = 0;
+        guint16 num_target_views_minus1 = 1;
+
+        WRITE_UINT32 (bs, temporal_id, 3);
+        WRITE_UE (bs, num_target_views_minus1);
+
+        for (k = 0; k <= num_target_views_minus1; k++)
+          WRITE_UE (bs, k);
+
+        WRITE_UE (bs, num_views_minus1);
+      }
+    }
+
+    /* mvc_vui_parameters_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+  }
+
+  /* additional_extension2_flag */
+  WRITE_UINT32 (bs, 0, 1);
+
+  /* rbsp_trailing_bits */
+  bs_write_trailing_bits (bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write subset SPS NAL unit");
+    return FALSE;
+  }
+  return FALSE;
+}
+
+/* Write a PPS NAL unit */
+static gboolean
+bs_write_pps (GstBitWriter * bs,
+    const VAEncPictureParameterBufferH264 * pic_param, GstVaapiProfile profile)
+{
+  guint32 num_slice_groups_minus1 = 0;
+  guint32 pic_init_qs_minus26 = 0;
+  guint32 redundant_pic_cnt_present_flag = 0;
+
+  /* pic_parameter_set_id */
+  WRITE_UE (bs, pic_param->pic_parameter_set_id);
+  /* seq_parameter_set_id */
+  WRITE_UE (bs, pic_param->seq_parameter_set_id);
+  /* entropy_coding_mode_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.entropy_coding_mode_flag, 1);
+  /* pic_order_present_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.pic_order_present_flag, 1);
+  /* slice_groups-1 */
+  WRITE_UE (bs, num_slice_groups_minus1);
+
+  if (num_slice_groups_minus1 > 0) {
+     /*FIXME*/ g_assert (0 && "unsupported arbitrary slice ordering (ASO)");
+  }
+  WRITE_UE (bs, pic_param->num_ref_idx_l0_active_minus1);
+  WRITE_UE (bs, pic_param->num_ref_idx_l1_active_minus1);
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_pred_flag, 1);
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_bipred_idc, 2);
+  /* pic_init_qp_minus26 */
+  WRITE_SE (bs, pic_param->pic_init_qp - 26);
+  /* pic_init_qs_minus26 */
+  WRITE_SE (bs, pic_init_qs_minus26);
+  /* chroma_qp_index_offset */
+  WRITE_SE (bs, pic_param->chroma_qp_index_offset);
+
+  WRITE_UINT32 (bs,
+      pic_param->pic_fields.bits.deblocking_filter_control_present_flag, 1);
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.constrained_intra_pred_flag, 1);
+  WRITE_UINT32 (bs, redundant_pic_cnt_present_flag, 1);
+
+  /* more_rbsp_data */
+  if (profile == GST_VAAPI_PROFILE_H264_HIGH
+      || profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH
+      || profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH) {
+    WRITE_UINT32 (bs, pic_param->pic_fields.bits.transform_8x8_mode_flag, 1);
+    WRITE_UINT32 (bs,
+        pic_param->pic_fields.bits.pic_scaling_matrix_present_flag, 1);
+    if (pic_param->pic_fields.bits.pic_scaling_matrix_present_flag) {
+      g_assert (0 && "unsupported scaling lists");
+      /* FIXME */
+      /*
+         for (i = 0; i <
+         (6+(-( (chroma_format_idc ! = 3) ? 2 : 6) * -pic_param->pic_fields.bits.transform_8x8_mode_flag));
+         i++) {
+         gst_bit_writer_put_bits_uint8(bs, pic_param->pic_fields.bits.pic_scaling_list_present_flag, 1);
+         }
+       */
+    }
+    WRITE_SE (bs, pic_param->second_chroma_qp_index_offset);
+  }
+
+  /* rbsp_trailing_bits */
+  bs_write_trailing_bits (bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write PPS NAL unit");
+    return FALSE;
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- H.264 Encoder                                                     --- */
+/* ------------------------------------------------------------------------- */
+
+struct _GstVaapiEncoderH264
+{
+  GstVaapiEncoder parent_instance;
+
+  GstVaapiProfile profile;
+  GstVaapiLevelH264 level;
+  GstVaapiEntrypoint entrypoint;
+  guint8 profile_idc;
+  guint8 max_profile_idc;
+  guint8 hw_max_profile_idc;
+  guint8 level_idc;
+  guint32 idr_period;
+  guint32 ip_period;
+  guint32 init_qp;
+  guint32 min_qp;
+  guint32 max_qp;
+  guint32 qp_i;
+  guint32 qp_ip;
+  guint32 qp_ib;
+  guint32 num_slices;
+  guint32 num_bframes;
+  guint32 mb_width;
+  guint32 mb_height;
+  guint32 quality_factor;
+  gboolean use_cabac;
+  gboolean use_dct8x8;
+  guint temporal_levels;        /* Number of temporal levels */
+  guint temporal_level_div[MAX_TEMPORAL_LEVELS];        /* to find the temporal id */
+  guint prediction_type;
+  guint abs_diff_pic_num_list0;
+  guint abs_diff_pic_num_list1;
+  GstClockTime cts_offset;
+  gboolean config_changed;
+
+  /* frame, poc */
+  guint32 max_frame_num;
+  guint32 log2_max_frame_num;
+  guint32 max_pic_order_cnt;
+  guint32 log2_max_pic_order_cnt;
+  guint32 idr_num;
+  guint8 pic_order_cnt_type;
+  guint8 delta_pic_order_always_zero_flag;
+  guint num_ref_frames;
+
+  GstBuffer *sps_data;
+  GstBuffer *subset_sps_data;
+  GstBuffer *pps_data;
+
+  guint bitrate_bits;           // bitrate (bits)
+  guint cpb_length;             // length of CPB buffer (ms)
+  guint cpb_length_bits;        // length of CPB buffer (bits)
+  GstVaapiEncoderMbbrc mbbrc;   // macroblock bitrate control
+
+  /* MVC */
+  gboolean is_mvc;
+  guint32 view_idx;             /* View Order Index (VOIdx) */
+  guint32 num_views;
+  guint16 view_ids[MAX_NUM_VIEWS];
+  GstVaapiH264ViewRefPool ref_pools[MAX_NUM_VIEWS];
+  GstVaapiH264ViewReorderPool reorder_pools[MAX_NUM_VIEWS];
+
+  gboolean use_aud;
+
+  /* Complance mode */
+  GstVaapiEncoderH264ComplianceMode compliance_mode;
+  guint min_cr;                 // Minimum Compression Ratio (A.3.1)
+};
+
+/* Write a SEI buffering period payload */
+static gboolean
+bs_write_sei_buf_period (GstBitWriter * bs,
+    GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
+{
+  guint initial_cpb_removal_delay = 0;
+  guint initial_cpb_removal_delay_offset = 0;
+  guint8 initial_cpb_removal_delay_length = 24;
+
+  /* sequence_parameter_set_id */
+  WRITE_UE (bs, encoder->view_idx);
+  /* NalHrdBpPresentFlag == TRUE */
+  /* cpb_cnt_minus1 == 0 */
+
+  /* decoding should start when the CPB fullness reaches half of cpb size
+   * initial_cpb_remvoal_delay = (((cpb_length / 2) * 90000) / 1000) */
+  initial_cpb_removal_delay = encoder->cpb_length * 45;
+
+  /* initial_cpb_remvoal_dealy */
+  WRITE_UINT32 (bs, initial_cpb_removal_delay,
+      initial_cpb_removal_delay_length);
+
+  /* initial_cpb_removal_delay_offset */
+  WRITE_UINT32 (bs, initial_cpb_removal_delay_offset,
+      initial_cpb_removal_delay_length);
+
+  /* VclHrdBpPresentFlag == FALSE */
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write Buffering Period SEI message");
+    return FALSE;
+  }
+}
+
+/* Write a SEI picture timing payload */
+static gboolean
+bs_write_sei_pic_timing (GstBitWriter * bs,
+    GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiH264ViewReorderPool *reorder_pool = NULL;
+  guint cpb_removal_delay;
+  guint dpb_output_delay;
+  guint8 cpb_removal_delay_length = 24;
+  guint8 dpb_output_delay_length = 24;
+  guint pic_struct = 0;
+  guint clock_timestamp_flag = 0;
+
+  reorder_pool = &encoder->reorder_pools[encoder->view_idx];
+  if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
+    reorder_pool->frame_count = 0;
+  else
+    reorder_pool->frame_count++;
+
+  /* clock-tick = no_units_in_tick/time_scale (C-1)
+   * time_scale = FPS_N * 2  (E.2.1)
+   * num_units_in_tick = FPS_D (E.2.1)
+   * frame_duration = clock-tick * 2
+   * so removal time for one frame is 2 clock-ticks.
+   * but adding a tolerance of one frame duration,
+   * which is 2 more clock-ticks */
+  cpb_removal_delay = (reorder_pool->frame_count * 2 + 2);
+
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_B)
+    dpb_output_delay = 0;
+  else
+    dpb_output_delay = picture->poc - reorder_pool->frame_count * 2;
+
+  /* CpbDpbDelaysPresentFlag == 1 */
+  WRITE_UINT32 (bs, cpb_removal_delay, cpb_removal_delay_length);
+  WRITE_UINT32 (bs, dpb_output_delay, dpb_output_delay_length);
+
+  /* pic_struct_present_flag == 1 */
+  /* pic_struct */
+  WRITE_UINT32 (bs, pic_struct, 4);
+  /* clock_timestamp_flag */
+  WRITE_UINT32 (bs, clock_timestamp_flag, 1);
+
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write Picture Timing SEI message");
+    return FALSE;
+  }
+}
+
+/* Write a Slice NAL unit */
+static gboolean
+bs_write_slice (GstBitWriter * bs,
+    const VAEncSliceParameterBufferH264 * slice_param,
+    GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
+{
+  const VAEncPictureParameterBufferH264 *const pic_param = picture->param;
+  guint32 field_pic_flag = 0;
+  guint32 ref_pic_list_modification_flag_l0 = 0;
+  guint32 ref_pic_list_modification_flag_l1 = 0;
+  guint32 no_output_of_prior_pics_flag = 0;
+  guint32 long_term_reference_flag = 0;
+  guint32 adaptive_ref_pic_marking_mode_flag = 0;
+
+  /* first_mb_in_slice */
+  WRITE_UE (bs, slice_param->macroblock_address);
+  /* slice_type */
+  WRITE_UE (bs, slice_param->slice_type);
+  /* pic_parameter_set_id */
+  WRITE_UE (bs, slice_param->pic_parameter_set_id);
+  /* frame_num */
+  WRITE_UINT32 (bs, picture->frame_num, encoder->log2_max_frame_num);
+
+  /* XXX: only frames (i.e. non-interlaced) are supported for now */
+  /* frame_mbs_only_flag == 0 */
+
+  /* idr_pic_id */
+  if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
+    WRITE_UE (bs, slice_param->idr_pic_id);
+
+  /* XXX: only POC type 0 is supported */
+  if (!encoder->pic_order_cnt_type) {
+    WRITE_UINT32 (bs, slice_param->pic_order_cnt_lsb,
+        encoder->log2_max_pic_order_cnt);
+    /* bottom_field_pic_order_in_frame_present_flag is FALSE */
+    if (pic_param->pic_fields.bits.pic_order_present_flag && !field_pic_flag)
+      WRITE_SE (bs, slice_param->delta_pic_order_cnt_bottom);
+  } else if (encoder->pic_order_cnt_type == 1 &&
+      !encoder->delta_pic_order_always_zero_flag) {
+    WRITE_SE (bs, slice_param->delta_pic_order_cnt[0]);
+    if (pic_param->pic_fields.bits.pic_order_present_flag && !field_pic_flag)
+      WRITE_SE (bs, slice_param->delta_pic_order_cnt[1]);
+  }
+  /* redundant_pic_cnt_present_flag is FALSE, no redundant coded pictures */
+
+  /* only works for B-frames */
+  if (slice_param->slice_type == 1)
+    WRITE_UINT32 (bs, slice_param->direct_spatial_mv_pred_flag, 1);
+
+  /* not supporting SP slices */
+  if (slice_param->slice_type == 0 || slice_param->slice_type == 1) {
+    WRITE_UINT32 (bs, slice_param->num_ref_idx_active_override_flag, 1);
+    if (slice_param->num_ref_idx_active_override_flag) {
+      WRITE_UE (bs, slice_param->num_ref_idx_l0_active_minus1);
+      if (slice_param->slice_type == 1)
+        WRITE_UE (bs, slice_param->num_ref_idx_l1_active_minus1);
+    }
+  }
+
+  if ((slice_param->slice_type != 2) && (slice_param->slice_type != 4)) {
+    if ((encoder->prediction_type != GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT)
+        && (encoder->abs_diff_pic_num_list0 > 1))
+      ref_pic_list_modification_flag_l0 = 1;
+
+    WRITE_UINT32 (bs, ref_pic_list_modification_flag_l0, 1);
+
+    if (ref_pic_list_modification_flag_l0) {
+      /*modification_of_pic_num_idc */
+      WRITE_UE (bs, 0);
+      /* abs_diff_pic_num_minus1 */
+      WRITE_UE (bs, encoder->abs_diff_pic_num_list0 - 1);
+      /*modification_of_pic_num_idc */
+      WRITE_UE (bs, 3);
+    }
+  }
+
+  /* B-frame */
+  if (slice_param->slice_type == 1) {
+    if ((encoder->prediction_type ==
+            GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B)
+        && (encoder->abs_diff_pic_num_list1 > 1))
+      ref_pic_list_modification_flag_l1 = 1;
+
+    WRITE_UINT32 (bs, ref_pic_list_modification_flag_l1, 1);
+
+    if (ref_pic_list_modification_flag_l1) {
+      /*modification_of_pic_num_idc */
+      WRITE_UE (bs, 0);
+      /* abs_diff_pic_num_minus1 */
+      WRITE_UE (bs, encoder->abs_diff_pic_num_list1 - 1);
+      /*modification_of_pic_num_idc */
+      WRITE_UE (bs, 3);
+    }
+  }
+
+  /* we have: weighted_pred_flag == FALSE and */
+  /*        : weighted_bipred_idc == FALSE */
+  if ((pic_param->pic_fields.bits.weighted_pred_flag &&
+          (slice_param->slice_type == 0)) ||
+      ((pic_param->pic_fields.bits.weighted_bipred_idc == 1) &&
+          (slice_param->slice_type == 1))) {
+    /* XXXX: add pred_weight_table() */
+  }
+
+  /* dec_ref_pic_marking() */
+  if (GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture)) {
+    if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) {
+      /* no_output_of_prior_pics_flag = 0 */
+      WRITE_UINT32 (bs, no_output_of_prior_pics_flag, 1);
+      /* long_term_reference_flag = 0 */
+      WRITE_UINT32 (bs, long_term_reference_flag, 1);
+    } else {
+      /* only sliding_window reference picture marking mode is supported */
+      /* adpative_ref_pic_marking_mode_flag = 0 */
+      WRITE_UINT32 (bs, adaptive_ref_pic_marking_mode_flag, 1);
+    }
+  }
+
+  /* cabac_init_idc */
+  if (pic_param->pic_fields.bits.entropy_coding_mode_flag &&
+      slice_param->slice_type != 2)
+    WRITE_UE (bs, slice_param->cabac_init_idc);
+  /*slice_qp_delta */
+  WRITE_SE (bs, slice_param->slice_qp_delta);
+
+  /* XXX: only supporting I, P and B type slices */
+  /* no sp_for_switch_flag and no slice_qs_delta */
+
+  if (pic_param->pic_fields.bits.deblocking_filter_control_present_flag) {
+    /* disable_deblocking_filter_idc */
+    WRITE_UE (bs, slice_param->disable_deblocking_filter_idc);
+    if (slice_param->disable_deblocking_filter_idc != 1) {
+      WRITE_SE (bs, slice_param->slice_alpha_c0_offset_div2);
+      WRITE_SE (bs, slice_param->slice_beta_offset_div2);
+    }
+  }
+
+  /* XXX: unsupported arbitrary slice ordering (ASO) */
+  /* num_slic_groups_minus1 should be zero */
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write Slice NAL unit");
+    return FALSE;
+  }
+}
+
+static inline void
+_check_sps_pps_status (GstVaapiEncoderH264 * encoder,
+    const guint8 * nal, guint32 size)
+{
+  guint8 nal_type;
+  G_GNUC_UNUSED gsize ret;      /* FIXME */
+  gboolean has_subset_sps;
+
+  g_assert (size);
+
+  has_subset_sps = !encoder->is_mvc || (encoder->subset_sps_data != NULL);
+  if (encoder->sps_data && encoder->pps_data && has_subset_sps)
+    return;
+
+  nal_type = nal[0] & 0x1F;
+  switch (nal_type) {
+    case GST_H264_NAL_SPS:
+      encoder->sps_data = gst_buffer_new_allocate (NULL, size, NULL);
+      ret = gst_buffer_fill (encoder->sps_data, 0, nal, size);
+      g_assert (ret == size);
+      break;
+    case GST_H264_NAL_SUBSET_SPS:
+      encoder->subset_sps_data = gst_buffer_new_allocate (NULL, size, NULL);
+      ret = gst_buffer_fill (encoder->subset_sps_data, 0, nal, size);
+      g_assert (ret == size);
+      break;
+    case GST_H264_NAL_PPS:
+      encoder->pps_data = gst_buffer_new_allocate (NULL, size, NULL);
+      ret = gst_buffer_fill (encoder->pps_data, 0, nal, size);
+      g_assert (ret == size);
+      break;
+    default:
+      break;
+  }
+}
+
+/* Determines the largest supported profile by the underlying hardware */
+static gboolean
+ensure_hw_profile_limits (GstVaapiEncoderH264 * encoder)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+  GArray *profiles;
+  guint i, profile_idc, max_profile_idc;
+
+  if (encoder->hw_max_profile_idc)
+    return TRUE;
+
+  profiles = gst_vaapi_display_get_encode_profiles (display);
+  if (!profiles)
+    return FALSE;
+
+  max_profile_idc = 0;
+  for (i = 0; i < profiles->len; i++) {
+    const GstVaapiProfile profile =
+        g_array_index (profiles, GstVaapiProfile, i);
+    profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
+    if (!profile_idc)
+      continue;
+    if (max_profile_idc < profile_idc)
+      max_profile_idc = profile_idc;
+  }
+  g_array_unref (profiles);
+
+  encoder->hw_max_profile_idc = max_profile_idc;
+  return TRUE;
+}
+
+/* Derives the profile supported by the underlying hardware */
+static gboolean
+ensure_hw_profile (GstVaapiEncoderH264 * encoder)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+  GstVaapiEntrypoint entrypoint = encoder->entrypoint;
+  GstVaapiProfile profile, profiles[4];
+  guint i, num_profiles = 0;
+
+  profiles[num_profiles++] = encoder->profile;
+  switch (encoder->profile) {
+    case GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE:
+      profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_BASELINE;
+      profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_MAIN;
+      // fall-through
+    case GST_VAAPI_PROFILE_H264_MAIN:
+      profiles[num_profiles++] = GST_VAAPI_PROFILE_H264_HIGH;
+      break;
+    default:
+      break;
+  }
+
+  profile = GST_VAAPI_PROFILE_UNKNOWN;
+  for (i = 0; i < num_profiles; i++) {
+    if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
+      profile = profiles[i];
+      break;
+    }
+  }
+  if (profile == GST_VAAPI_PROFILE_UNKNOWN)
+    goto error_unsupported_profile;
+
+  GST_VAAPI_ENCODER_CAST (encoder)->profile = profile;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_profile:
+  {
+    GST_ERROR ("unsupported HW profile %s",
+        gst_vaapi_profile_get_va_name (encoder->profile));
+    return FALSE;
+  }
+}
+
+/* Check target decoder constraints */
+static gboolean
+ensure_profile_limits (GstVaapiEncoderH264 * encoder)
+{
+  GstVaapiProfile profile;
+
+  if (!encoder->max_profile_idc
+      || encoder->profile_idc == encoder->max_profile_idc)
+    return TRUE;
+
+  /* Give an error if the given parameters are invalid for requested
+   * profile rather than lowering profile.
+   */
+  if (encoder->profile_idc > encoder->max_profile_idc) {
+    GST_WARNING ("Invalid parameter for maximum profile");
+    return FALSE;
+  }
+
+  profile = GST_VAAPI_PROFILE_UNKNOWN;
+
+  if (encoder->profile_idc < encoder->max_profile_idc) {
+    /* Let profile be higher to fit in the maximum profile
+     * without changing parameters */
+    if (encoder->max_profile_idc > GST_H264_PROFILE_BASELINE)
+      profile = GST_VAAPI_PROFILE_H264_MAIN;
+
+    if (encoder->max_profile_idc > GST_H264_PROFILE_MAIN)
+      profile = GST_VAAPI_PROFILE_H264_HIGH;
+
+    if (encoder->max_profile_idc > GST_H264_PROFILE_HIGH) {
+      if (encoder->num_views > 2)
+        profile = GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH;
+      else if (encoder->num_views == 2)
+        profile = GST_VAAPI_PROFILE_H264_STEREO_HIGH;
+    }
+  }
+
+  if (profile) {
+    encoder->profile = profile;
+    encoder->profile_idc = encoder->max_profile_idc;
+  }
+  return TRUE;
+}
+
+/* Derives the minimum profile from the active coding tools */
+static gboolean
+ensure_profile (GstVaapiEncoderH264 * encoder)
+{
+  GstVaapiProfile profile;
+
+  /* Always start from "constrained-baseline" profile for maximum
+     compatibility */
+  profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
+
+  /* Main profile coding tools */
+  if (encoder->num_bframes > 0 || encoder->use_cabac)
+    profile = GST_VAAPI_PROFILE_H264_MAIN;
+
+  /* High profile coding tools */
+  if (encoder->use_dct8x8)
+    profile = GST_VAAPI_PROFILE_H264_HIGH;
+
+  /* MVC profiles coding tools */
+  if (encoder->num_views == 2)
+    profile = GST_VAAPI_PROFILE_H264_STEREO_HIGH;
+  else if (encoder->num_views > 2)
+    profile = GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH;
+
+  encoder->profile = profile;
+  encoder->profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
+  return TRUE;
+}
+
+/* Derives the level from the currently set limits */
+static gboolean
+ensure_level (GstVaapiEncoderH264 * encoder)
+{
+  const guint cpb_factor = h264_get_cpb_nal_factor (encoder->profile);
+  const GstVaapiH264LevelLimits *limits_table;
+  guint i, num_limits, PicSizeMbs, MaxDpbMbs, MaxMBPS;
+
+  PicSizeMbs = encoder->mb_width * encoder->mb_height;
+  MaxDpbMbs = PicSizeMbs * ((encoder->num_bframes) ? 2 : 1);
+  MaxMBPS = gst_util_uint64_scale_int_ceil (PicSizeMbs,
+      GST_VAAPI_ENCODER_FPS_N (encoder), GST_VAAPI_ENCODER_FPS_D (encoder));
+
+  limits_table = gst_vaapi_utils_h264_get_level_limits_table (&num_limits);
+  for (i = 0; i < num_limits; i++) {
+    const GstVaapiH264LevelLimits *const limits = &limits_table[i];
+    if (PicSizeMbs <= limits->MaxFS &&
+        MaxDpbMbs <= limits->MaxDpbMbs &&
+        MaxMBPS <= limits->MaxMBPS && (!encoder->bitrate_bits
+            || encoder->bitrate_bits <= (limits->MaxBR * cpb_factor)) &&
+        (!encoder->cpb_length_bits ||
+            encoder->cpb_length_bits <= (limits->MaxCPB * cpb_factor)))
+      break;
+  }
+  if (i == num_limits)
+    goto error_unsupported_level;
+
+  encoder->level = limits_table[i].level;
+  encoder->level_idc = limits_table[i].level_idc;
+  encoder->min_cr = limits_table[i].MinCR;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_level:
+  {
+    GST_ERROR ("failed to find a suitable level matching codec config");
+    return FALSE;
+  }
+}
+
+/* Enable "high-compression" tuning options */
+static gboolean
+ensure_tuning_high_compression (GstVaapiEncoderH264 * encoder)
+{
+  guint8 profile_idc;
+
+  if (!ensure_hw_profile_limits (encoder))
+    return FALSE;
+
+  profile_idc = encoder->hw_max_profile_idc;
+  if (encoder->max_profile_idc && encoder->max_profile_idc < profile_idc)
+    profile_idc = encoder->max_profile_idc;
+
+  /* Tuning options to enable Main profile */
+  if (profile_idc >= GST_H264_PROFILE_MAIN
+      && profile_idc != GST_H264_PROFILE_EXTENDED) {
+    encoder->use_cabac = TRUE;
+    if (!encoder->num_bframes)
+      encoder->num_bframes = 1;
+  }
+
+  /* Tuning options to enable High profile */
+  if (profile_idc >= GST_H264_PROFILE_HIGH) {
+    encoder->use_dct8x8 = TRUE;
+  }
+  return TRUE;
+}
+
+/* Ensure tuning options */
+static gboolean
+ensure_tuning (GstVaapiEncoderH264 * encoder)
+{
+  gboolean success;
+
+  switch (GST_VAAPI_ENCODER_TUNE (encoder)) {
+    case GST_VAAPI_ENCODER_TUNE_HIGH_COMPRESSION:
+      success = ensure_tuning_high_compression (encoder);
+      break;
+    default:
+      success = TRUE;
+      break;
+  }
+  return success;
+}
+
+static gboolean
+is_temporal_id_max (GstVaapiEncoderH264 * encoder, guint32 temporal_id)
+{
+  g_assert (temporal_id < encoder->temporal_levels);
+  return temporal_id == encoder->temporal_levels - 1;
+}
+
+/* Handle new GOP starts */
+static void
+reset_gop_start (GstVaapiEncoderH264 * encoder)
+{
+  GstVaapiH264ViewReorderPool *const reorder_pool =
+      &encoder->reorder_pools[encoder->view_idx];
+
+  reorder_pool->frame_index = 1;
+  reorder_pool->cur_present_index = 0;
+  ++encoder->idr_num;
+}
+
+/* Marks the supplied picture as a B-frame */
+static void
+set_b_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264 * encoder)
+{
+  g_assert (pic && encoder);
+  g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
+  pic->type = GST_VAAPI_PICTURE_TYPE_B;
+
+  if (encoder->temporal_levels > 1) {
+    /* while doing temporal encoding,  b frames are allowded
+     * only in hierarchical-b mode */
+    g_assert (encoder->prediction_type ==
+        GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B);
+    /* temporal_encode: set b-frame as reference frames in
+     * hierarchical-b encode unless they belongs to highest level */
+    if (!is_temporal_id_max (encoder, pic->temporal_id))
+      GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE);
+  }
+}
+
+/* Marks the supplied picture as a P-frame */
+static void
+set_p_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264 * encoder)
+{
+  g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
+  pic->type = GST_VAAPI_PICTURE_TYPE_P;
+
+  if (encoder->temporal_levels == 1) {
+    /* Default prediction mode */
+    GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE);
+  } else {
+    /* temporal_encode: all frames in highest level are not reference frames
+     * for hierarhical-p and hierarchical-b prediction mode */
+    if (!is_temporal_id_max (encoder, pic->temporal_id))
+      GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE);
+  }
+}
+
+/* Marks the supplied picture as an I-frame */
+static void
+set_i_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264 * encoder)
+{
+  g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
+  pic->type = GST_VAAPI_PICTURE_TYPE_I;
+  GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE);
+
+  g_assert (pic->frame);
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame);
+}
+
+/* Marks the supplied picture as an IDR frame */
+static void
+set_idr_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH264 * encoder)
+{
+  g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
+  pic->type = GST_VAAPI_PICTURE_TYPE_I;
+  pic->poc = 0;
+  GST_VAAPI_ENC_PICTURE_FLAG_SET (pic,
+      GST_VAAPI_ENC_PICTURE_FLAG_IDR | GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE);
+
+  g_assert (pic->frame);
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame);
+}
+
+/* Marks the supplied picture a a key-frame */
+static void
+set_key_frame (GstVaapiEncPicture * picture,
+    GstVaapiEncoderH264 * encoder, gboolean is_idr)
+{
+  if (is_idr) {
+    reset_gop_start (encoder);
+    set_idr_frame (picture, encoder);
+  } else
+    set_i_frame (picture, encoder);
+}
+
+static void
+set_frame_num (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiH264ViewReorderPool *reorder_pool = NULL;
+
+  reorder_pool = &encoder->reorder_pools[encoder->view_idx];
+
+  picture->frame_num = (reorder_pool->cur_frame_num % encoder->max_frame_num);
+
+  if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) {
+    picture->frame_num = 0;
+    reorder_pool->cur_frame_num = 0;
+  }
+
+  reorder_pool->prev_frame_is_ref = GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture);
+
+  if (reorder_pool->prev_frame_is_ref)
+    ++reorder_pool->cur_frame_num;
+}
+
+/* Fills in VA HRD parameters */
+static void
+fill_hrd_params (GstVaapiEncoderH264 * encoder, VAEncMiscParameterHRD * hrd)
+{
+  if (encoder->bitrate_bits > 0) {
+    hrd->buffer_size = encoder->cpb_length_bits;
+    hrd->initial_buffer_fullness = hrd->buffer_size / 2;
+  } else {
+    hrd->buffer_size = 0;
+    hrd->initial_buffer_fullness = 0;
+  }
+}
+
+static gboolean
+add_packed_au_delimiter (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture)
+{
+  GstVaapiEncPackedHeader *packed_aud;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
+  guint32 data_bit_size;
+  guint8 *data;
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+  bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_NONE,
+      GST_H264_NAL_AU_DELIMITER);
+  WRITE_UINT32 (&bs, picture->type - 1, 3);
+  if (!bs_write_trailing_bits (&bs))
+    goto bs_error;
+
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_header_param_buffer.type = VAEncPackedHeaderRawData;
+  packed_header_param_buffer.bit_length = data_bit_size;
+  packed_header_param_buffer.has_emulation_bytes = 0;
+
+  packed_aud = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_header_param_buffer, sizeof (packed_header_param_buffer),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_aud);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_aud);
+  gst_vaapi_codec_object_replace (&packed_aud, NULL);
+
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write AU Delimiter  NAL unit");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+/* Adds the supplied sequence header (SPS) to the list of packed
+   headers to pass down as-is to the encoder */
+static gboolean
+add_packed_sequence_header (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  GstVaapiEncPackedHeader *packed_seq;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_seq_param = { 0 };
+  const VAEncSequenceParameterBufferH264 *const seq_param = sequence->param;
+  GstVaapiProfile profile = encoder->profile;
+
+  VAEncMiscParameterHRD hrd_params;
+  guint32 data_bit_size;
+  guint8 *data;
+
+  fill_hrd_params (encoder, &hrd_params);
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+  bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_HIGH, GST_H264_NAL_SPS);
+
+  /* Set High profile for encoding the MVC base view. Otherwise, some
+     traditional decoder cannot recognize MVC profile streams with
+     only the base view in there */
+  if (profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH ||
+      profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH)
+    profile = GST_VAAPI_PROFILE_H264_HIGH;
+
+  bs_write_sps (&bs, seq_param, profile, base_encoder->rate_control,
+      &hrd_params);
+
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_seq_param.type = VAEncPackedHeaderSequence;
+  packed_seq_param.bit_length = data_bit_size;
+  packed_seq_param.has_emulation_bytes = 0;
+
+  packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_seq_param, sizeof (packed_seq_param),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_seq);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_seq);
+  gst_vaapi_codec_object_replace (&packed_seq, NULL);
+
+  /* store sps data */
+  _check_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4);
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write SPS NAL unit");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+static gboolean
+add_packed_sequence_header_mvc (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  GstVaapiEncPackedHeader *packed_seq;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
+  const VAEncSequenceParameterBufferH264 *const seq_param = sequence->param;
+  VAEncMiscParameterHRD hrd_params;
+  guint32 data_bit_size;
+  guint8 *data;
+
+  fill_hrd_params (encoder, &hrd_params);
+
+  /* non-base layer, pack one subset sps */
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+  bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_HIGH, GST_H264_NAL_SUBSET_SPS);
+
+  bs_write_subset_sps (&bs, seq_param, encoder->profile,
+      base_encoder->rate_control, encoder->num_views, encoder->view_ids,
+      &hrd_params);
+
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_header_param_buffer.type = VAEncPackedHeaderSequence;
+  packed_header_param_buffer.bit_length = data_bit_size;
+  packed_header_param_buffer.has_emulation_bytes = 0;
+
+  packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_header_param_buffer, sizeof (packed_header_param_buffer),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_seq);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_seq);
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) & packed_seq, NULL);
+
+  /* store subset sps data */
+  _check_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4);
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write SPS NAL unit");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+/* Adds the supplied picture header (PPS) to the list of packed
+   headers to pass down as-is to the encoder */
+static gboolean
+add_packed_picture_header (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture)
+{
+  GstVaapiEncPackedHeader *packed_pic;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_pic_param = { 0 };
+  const VAEncPictureParameterBufferH264 *const pic_param = picture->param;
+  guint32 data_bit_size;
+  guint8 *data;
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+  bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_HIGH, GST_H264_NAL_PPS);
+  bs_write_pps (&bs, pic_param, encoder->profile);
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_pic_param.type = VAEncPackedHeaderPicture;
+  packed_pic_param.bit_length = data_bit_size;
+  packed_pic_param.has_emulation_bytes = 0;
+
+  packed_pic = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_pic_param, sizeof (packed_pic_param),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_pic);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_pic);
+  gst_vaapi_codec_object_replace (&packed_pic, NULL);
+
+  /* store pps data */
+  _check_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4);
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write PPS NAL unit");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+static gboolean
+add_packed_sei_header (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiH264SeiPayloadType payloadtype)
+{
+  GstVaapiEncPackedHeader *packed_sei;
+  GstBitWriter bs, bs_buf_period, bs_pic_timing;
+  VAEncPackedHeaderParameterBuffer packed_sei_param = { 0 };
+  guint32 data_bit_size;
+  guint8 buf_period_payload_size = 0, pic_timing_payload_size = 0;
+  guint8 *data, *buf_period_payload = NULL, *pic_timing_payload = NULL;
+  gboolean need_buf_period, need_pic_timing;
+
+  gst_bit_writer_init_with_size (&bs_buf_period, 128, FALSE);
+  gst_bit_writer_init_with_size (&bs_pic_timing, 128, FALSE);
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+
+  need_buf_period = GST_VAAPI_H264_SEI_BUF_PERIOD & payloadtype;
+  need_pic_timing = GST_VAAPI_H264_SEI_PIC_TIMING & payloadtype;
+
+  if (need_buf_period) {
+    /* Write a Buffering Period SEI message */
+    bs_write_sei_buf_period (&bs_buf_period, encoder, picture);
+    /* Write byte alignment bits */
+    if (GST_BIT_WRITER_BIT_SIZE (&bs_buf_period) % 8 != 0)
+      bs_write_trailing_bits (&bs_buf_period);
+    buf_period_payload_size = (GST_BIT_WRITER_BIT_SIZE (&bs_buf_period)) / 8;
+    buf_period_payload = GST_BIT_WRITER_DATA (&bs_buf_period);
+  }
+
+  if (need_pic_timing) {
+    /* Write a Picture Timing SEI message */
+    if (GST_VAAPI_H264_SEI_PIC_TIMING & payloadtype)
+      bs_write_sei_pic_timing (&bs_pic_timing, encoder, picture);
+    /* Write byte alignment bits */
+    if (GST_BIT_WRITER_BIT_SIZE (&bs_pic_timing) % 8 != 0)
+      bs_write_trailing_bits (&bs_pic_timing);
+    pic_timing_payload_size = (GST_BIT_WRITER_BIT_SIZE (&bs_pic_timing)) / 8;
+    pic_timing_payload = GST_BIT_WRITER_DATA (&bs_pic_timing);
+  }
+
+  /* Write the SEI message */
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+  bs_write_nal_header (&bs, GST_H264_NAL_REF_IDC_NONE, GST_H264_NAL_SEI);
+
+  if (need_buf_period) {
+    WRITE_UINT32 (&bs, GST_H264_SEI_BUF_PERIOD, 8);
+    WRITE_UINT32 (&bs, buf_period_payload_size, 8);
+    /* Add buffering period sei message */
+    gst_bit_writer_put_bytes (&bs, buf_period_payload, buf_period_payload_size);
+  }
+
+  if (need_pic_timing) {
+    WRITE_UINT32 (&bs, GST_H264_SEI_PIC_TIMING, 8);
+    WRITE_UINT32 (&bs, pic_timing_payload_size, 8);
+    /* Add picture timing sei message */
+    gst_bit_writer_put_bytes (&bs, pic_timing_payload, pic_timing_payload_size);
+  }
+
+  /* rbsp_trailing_bits */
+  bs_write_trailing_bits (&bs);
+
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_sei_param.type = VA_ENC_PACKED_HEADER_H264_SEI;
+  packed_sei_param.bit_length = data_bit_size;
+  packed_sei_param.has_emulation_bytes = 0;
+
+  packed_sei = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_sei_param, sizeof (packed_sei_param),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_sei);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_sei);
+  gst_vaapi_codec_object_replace (&packed_sei, NULL);
+
+  gst_bit_writer_reset (&bs_buf_period);
+  gst_bit_writer_reset (&bs_pic_timing);
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write SEI NAL unit");
+    gst_bit_writer_reset (&bs_buf_period);
+    gst_bit_writer_reset (&bs_pic_timing);
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+static gboolean
+get_nal_hdr_attributes (GstVaapiEncPicture * picture,
+    guint8 * nal_ref_idc, guint8 * nal_unit_type)
+{
+  switch (picture->type) {
+    case GST_VAAPI_PICTURE_TYPE_I:
+      *nal_ref_idc = GST_H264_NAL_REF_IDC_HIGH;
+      if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
+        *nal_unit_type = GST_H264_NAL_SLICE_IDR;
+      else
+        *nal_unit_type = GST_H264_NAL_SLICE;
+      break;
+    case GST_VAAPI_PICTURE_TYPE_P:
+      if (!GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture))
+        *nal_ref_idc = GST_H264_NAL_REF_IDC_NONE;
+      else
+        *nal_ref_idc = GST_H264_NAL_REF_IDC_MEDIUM;
+
+      *nal_unit_type = GST_H264_NAL_SLICE;
+      break;
+    case GST_VAAPI_PICTURE_TYPE_B:
+      if (!GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture))
+        *nal_ref_idc = GST_H264_NAL_REF_IDC_NONE;
+      else
+        *nal_ref_idc = GST_H264_NAL_REF_IDC_LOW;
+
+      *nal_unit_type = GST_H264_NAL_SLICE;
+      break;
+    default:
+      return FALSE;
+  }
+  return TRUE;
+}
+
+/* Adds the supplied prefix nal header to the list of packed
+   headers to pass down as-is to the encoder */
+static gboolean
+add_packed_prefix_nal_header (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiEncSlice * slice)
+{
+  GstVaapiEncPackedHeader *packed_prefix_nal;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_prefix_nal_param = { 0 };
+  guint32 data_bit_size;
+  guint8 *data;
+  guint8 nal_ref_idc, nal_unit_type;
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+
+  if (!get_nal_hdr_attributes (picture, &nal_ref_idc, &nal_unit_type))
+    goto bs_error;
+  nal_unit_type = GST_H264_NAL_PREFIX_UNIT;
+
+  bs_write_nal_header (&bs, nal_ref_idc, nal_unit_type);
+  bs_write_nal_header_mvc_extension (&bs, picture, encoder->view_idx);
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_prefix_nal_param.type = VAEncPackedHeaderRawData;
+  packed_prefix_nal_param.bit_length = data_bit_size;
+  packed_prefix_nal_param.has_emulation_bytes = 0;
+
+  packed_prefix_nal =
+      gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_prefix_nal_param, sizeof (packed_prefix_nal_param), data,
+      (data_bit_size + 7) / 8);
+  g_assert (packed_prefix_nal);
+
+  gst_vaapi_enc_slice_add_packed_header (slice, packed_prefix_nal);
+  gst_vaapi_codec_object_replace (&packed_prefix_nal, NULL);
+
+  gst_bit_writer_reset (&bs);
+
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write Prefix NAL unit header");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+/* Adds the supplied slice header to the list of packed
+   headers to pass down as-is to the encoder */
+static gboolean
+add_packed_slice_header (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiEncSlice * slice)
+{
+  GstVaapiEncPackedHeader *packed_slice;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_slice_param = { 0 };
+  const VAEncSliceParameterBufferH264 *const slice_param = slice->param;
+  guint32 data_bit_size;
+  guint8 *data;
+  guint8 nal_ref_idc, nal_unit_type;
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+
+  if (!get_nal_hdr_attributes (picture, &nal_ref_idc, &nal_unit_type))
+    goto bs_error;
+  /* pack nal_unit_header_mvc_extension() for the non base view */
+  if (encoder->is_mvc && encoder->view_idx) {
+    bs_write_nal_header (&bs, nal_ref_idc, GST_H264_NAL_SLICE_EXT);
+    bs_write_nal_header_mvc_extension (&bs, picture,
+        encoder->view_ids[encoder->view_idx]);
+  } else
+    bs_write_nal_header (&bs, nal_ref_idc, nal_unit_type);
+
+  bs_write_slice (&bs, slice_param, encoder, picture);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_slice_param.type = VAEncPackedHeaderSlice;
+  packed_slice_param.bit_length = data_bit_size;
+  packed_slice_param.has_emulation_bytes = 0;
+
+  packed_slice = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_slice_param, sizeof (packed_slice_param),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_slice);
+
+  gst_vaapi_enc_slice_add_packed_header (slice, packed_slice);
+  gst_vaapi_codec_object_replace (&packed_slice, NULL);
+
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write Slice NAL unit header");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+/* Reference picture management */
+static void
+reference_pic_free (GstVaapiEncoderH264 * encoder, GstVaapiEncoderH264Ref * ref)
+{
+  if (!ref)
+    return;
+  if (ref->pic)
+    gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), ref->pic);
+  g_slice_free (GstVaapiEncoderH264Ref, ref);
+}
+
+static inline GstVaapiEncoderH264Ref *
+reference_pic_create (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiEncoderH264Ref *const ref = g_slice_new0 (GstVaapiEncoderH264Ref);
+
+  ref->pic = surface;
+  ref->frame_num = picture->frame_num;
+  ref->poc = picture->poc;
+  ref->temporal_id = picture->temporal_id;
+  return ref;
+}
+
+static gboolean
+reference_list_update (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiEncoderH264Ref *ref;
+  GstVaapiH264ViewRefPool *const ref_pool =
+      &encoder->ref_pools[encoder->view_idx];
+
+  if (encoder->prediction_type == GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT
+      && GST_VAAPI_PICTURE_TYPE_B == picture->type) {
+    gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), surface);
+    return TRUE;
+  }
+  if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) {
+    while (!g_queue_is_empty (&ref_pool->ref_list))
+      reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list));
+  } else if (g_queue_get_length (&ref_pool->ref_list) >=
+      ref_pool->max_ref_frames) {
+    reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list));
+  }
+  ref = reference_pic_create (encoder, picture, surface);
+  g_queue_push_tail (&ref_pool->ref_list, ref);
+  g_assert (g_queue_get_length (&ref_pool->ref_list) <=
+      ref_pool->max_ref_frames);
+  return TRUE;
+}
+
+/* update reflist0 for hierarchical-p and hierarchical-b encode */
+static void
+reflist0_init_hierarchical (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture, GQueue * ref_list,
+    GstVaapiEncoderH264Ref ** reflist_0, guint * reflist_0_count)
+{
+  GstVaapiEncoderH264Ref *tmp = NULL;
+  GList *iter;
+  guint count = 0, i;
+
+  iter = g_queue_peek_tail_link (ref_list);
+  for (; iter; iter = g_list_previous (iter)) {
+    tmp = (GstVaapiEncoderH264Ref *) iter->data;
+
+    g_assert (tmp && tmp->poc != picture->poc);
+
+    if (_poc_greater_than (picture->poc, tmp->poc, encoder->max_pic_order_cnt)
+        && ((picture->temporal_id && (tmp->temporal_id < picture->temporal_id))
+            || (!picture->temporal_id
+                && (tmp->temporal_id == picture->temporal_id)))) {
+      reflist_0[count++] = tmp;
+    }
+  }
+
+  g_assert (count != 0);
+
+  /* Only need one ref frame */
+  tmp = reflist_0[0];
+  for (i = 1; i < count; i++) {
+    if (tmp->poc < reflist_0[i]->poc)
+      tmp = reflist_0[i];
+  }
+  reflist_0[0] = tmp;
+  *reflist_0_count = 1;
+  encoder->abs_diff_pic_num_list0 = picture->frame_num - tmp->frame_num;
+}
+
+/* update reflist1 for hierarchical-b encode */
+static void
+reflist1_init_hierarchical_b (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture, GQueue * ref_list,
+    GstVaapiEncoderH264Ref ** reflist_1, guint * reflist_1_count)
+{
+  GstVaapiEncoderH264Ref *tmp = NULL;
+  GList *iter;
+  guint count = 0, i;
+
+  /* base layer should have only P frames */
+  g_assert (picture->temporal_id != 0);
+
+  iter = g_queue_peek_tail_link (ref_list);
+  for (; iter; iter = g_list_previous (iter)) {
+    tmp = (GstVaapiEncoderH264Ref *) iter->data;
+
+    g_assert (tmp && tmp->poc != picture->poc);
+
+    if (_poc_greater_than (tmp->poc, picture->poc, encoder->max_pic_order_cnt)
+        && (tmp->temporal_id < picture->temporal_id)) {
+      reflist_1[count++] = tmp;
+    }
+  }
+
+  g_assert (count != 0);
+
+  /* Only need one ref frame */
+  tmp = reflist_1[0];
+  for (i = 1; i < count; i++) {
+    if (tmp->poc > reflist_1[i]->poc)
+      tmp = reflist_1[i];
+  }
+  reflist_1[0] = tmp;
+  *reflist_1_count = 1;
+  encoder->abs_diff_pic_num_list1 = picture->frame_num - tmp->frame_num;
+}
+
+static gboolean
+reference_list_init_hierarchical (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture,
+    GQueue * ref_list,
+    GstVaapiEncoderH264Ref ** reflist_0,
+    guint * reflist_0_count,
+    GstVaapiEncoderH264Ref ** reflist_1, guint * reflist_1_count)
+{
+  /* reflist_0 ordering is same for hierarchical-P and hierarchical-B */
+  reflist0_init_hierarchical (encoder, picture, ref_list, reflist_0,
+      reflist_0_count);
+
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_B)
+    return TRUE;
+
+  g_assert (encoder->prediction_type ==
+      GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B);
+
+  reflist1_init_hierarchical_b (encoder, picture, ref_list,
+      reflist_1, reflist_1_count);
+
+  /* FIXME: Combine and optimize reflist_0_init and reflist_1_init.
+   * Keeping separate blocks for now to make it more
+   * readable and easy to debug */
+
+  return TRUE;
+}
+
+static gboolean
+reference_list_init (GstVaapiEncoderH264 * encoder,
+    GstVaapiEncPicture * picture,
+    GstVaapiEncoderH264Ref ** reflist_0,
+    guint * reflist_0_count,
+    GstVaapiEncoderH264Ref ** reflist_1, guint * reflist_1_count)
+{
+  GstVaapiEncoderH264Ref *tmp;
+  GstVaapiH264ViewRefPool *const ref_pool =
+      &encoder->ref_pools[encoder->view_idx];
+  GList *iter, *list_0_start = NULL, *list_1_start = NULL;
+  guint count;
+
+  *reflist_0_count = 0;
+  *reflist_1_count = 0;
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
+    return TRUE;
+
+  /* reference picture handling for hierarchial encode */
+  if (encoder->prediction_type != GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT) {
+    return reference_list_init_hierarchical (encoder, picture,
+        &ref_pool->ref_list, reflist_0, reflist_0_count, reflist_1,
+        reflist_1_count);
+  }
+
+  iter = g_queue_peek_tail_link (&ref_pool->ref_list);
+  for (; iter; iter = g_list_previous (iter)) {
+    tmp = (GstVaapiEncoderH264Ref *) iter->data;
+    g_assert (tmp && tmp->poc != picture->poc);
+    if (_poc_greater_than (picture->poc, tmp->poc, encoder->max_pic_order_cnt)) {
+      list_0_start = iter;
+      list_1_start = g_list_next (iter);
+      break;
+    }
+  }
+
+  /* order reflist_0 */
+  g_assert (list_0_start);
+  iter = list_0_start;
+  count = 0;
+  for (; iter; iter = g_list_previous (iter)) {
+    reflist_0[count] = (GstVaapiEncoderH264Ref *) iter->data;
+    ++count;
+  }
+  *reflist_0_count = count;
+
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_B)
+    return TRUE;
+
+  /* order reflist_1 */
+  count = 0;
+  iter = list_1_start;
+  for (; iter; iter = g_list_next (iter)) {
+    reflist_1[count] = (GstVaapiEncoderH264Ref *) iter->data;
+    ++count;
+  }
+  *reflist_1_count = count;
+  return TRUE;
+}
+
+/* Fills in VA sequence parameter buffer */
+static gboolean
+fill_sequence (GstVaapiEncoderH264 * encoder, GstVaapiEncSequence * sequence)
+{
+  VAEncSequenceParameterBufferH264 *const seq_param = sequence->param;
+  GstVaapiH264ViewRefPool *const ref_pool =
+      &encoder->ref_pools[encoder->view_idx];
+
+  memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferH264));
+  seq_param->seq_parameter_set_id = encoder->view_idx;
+  seq_param->level_idc = encoder->level_idc;
+  seq_param->intra_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder);
+  seq_param->intra_idr_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder);
+  seq_param->ip_period = encoder->ip_period;
+  seq_param->bits_per_second = encoder->bitrate_bits;
+
+  seq_param->max_num_ref_frames = ref_pool->max_ref_frames;
+  seq_param->picture_width_in_mbs = encoder->mb_width;
+  seq_param->picture_height_in_mbs = encoder->mb_height;
+
+  /*sequence field values */
+  seq_param->seq_fields.value = 0;
+  seq_param->seq_fields.bits.chroma_format_idc = 1;
+  seq_param->seq_fields.bits.frame_mbs_only_flag = 1;
+  seq_param->seq_fields.bits.mb_adaptive_frame_field_flag = FALSE;
+  seq_param->seq_fields.bits.seq_scaling_matrix_present_flag = FALSE;
+  /* direct_8x8_inference_flag default false */
+  seq_param->seq_fields.bits.direct_8x8_inference_flag = FALSE;
+  g_assert (encoder->log2_max_frame_num >= 4);
+  seq_param->seq_fields.bits.log2_max_frame_num_minus4 =
+      encoder->log2_max_frame_num - 4;
+  /* picture order count */
+  encoder->pic_order_cnt_type = seq_param->seq_fields.bits.pic_order_cnt_type =
+      0;
+  g_assert (encoder->log2_max_pic_order_cnt >= 4);
+  seq_param->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 =
+      encoder->log2_max_pic_order_cnt - 4;
+
+  seq_param->bit_depth_luma_minus8 = 0;
+  seq_param->bit_depth_chroma_minus8 = 0;
+
+  /* not used if pic_order_cnt_type == 0 */
+  if (seq_param->seq_fields.bits.pic_order_cnt_type == 1) {
+    encoder->delta_pic_order_always_zero_flag =
+        seq_param->seq_fields.bits.delta_pic_order_always_zero_flag = TRUE;
+    seq_param->num_ref_frames_in_pic_order_cnt_cycle = 0;
+    seq_param->offset_for_non_ref_pic = 0;
+    seq_param->offset_for_top_to_bottom_field = 0;
+    memset (seq_param->offset_for_ref_frame, 0,
+        sizeof (seq_param->offset_for_ref_frame));
+  }
+
+  /* frame_cropping_flag */
+  if ((GST_VAAPI_ENCODER_WIDTH (encoder) & 15) ||
+      (GST_VAAPI_ENCODER_HEIGHT (encoder) & 15)) {
+    static const guint SubWidthC[] = { 1, 2, 2, 1 };
+    static const guint SubHeightC[] = { 1, 2, 1, 1 };
+    const guint CropUnitX =
+        SubWidthC[seq_param->seq_fields.bits.chroma_format_idc];
+    const guint CropUnitY =
+        SubHeightC[seq_param->seq_fields.bits.chroma_format_idc] *
+        (2 - seq_param->seq_fields.bits.frame_mbs_only_flag);
+
+    seq_param->frame_cropping_flag = 1;
+    seq_param->frame_crop_left_offset = 0;
+    seq_param->frame_crop_right_offset =
+        (16 * encoder->mb_width -
+        GST_VAAPI_ENCODER_WIDTH (encoder)) / CropUnitX;
+    seq_param->frame_crop_top_offset = 0;
+    seq_param->frame_crop_bottom_offset =
+        (16 * encoder->mb_height -
+        GST_VAAPI_ENCODER_HEIGHT (encoder)) / CropUnitY;
+  }
+
+  /* VUI parameters are always set, at least for timing_info (framerate) */
+  seq_param->vui_parameters_present_flag = TRUE;
+  if (seq_param->vui_parameters_present_flag) {
+    seq_param->vui_fields.bits.aspect_ratio_info_present_flag = TRUE;
+    if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) {
+      const GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+      seq_param->aspect_ratio_idc = 0xff;
+      seq_param->sar_width = GST_VIDEO_INFO_PAR_N (vip);
+      seq_param->sar_height = GST_VIDEO_INFO_PAR_D (vip);
+    }
+    seq_param->vui_fields.bits.bitstream_restriction_flag = FALSE;
+    /* if vui_parameters_present_flag is TRUE and sps data belongs to
+     * subset sps, timing_info_preset_flag should be zero (H.7.4.2.1.1) */
+    seq_param->vui_fields.bits.timing_info_present_flag = !encoder->view_idx;
+    if (seq_param->vui_fields.bits.timing_info_present_flag) {
+      seq_param->num_units_in_tick = GST_VAAPI_ENCODER_FPS_D (encoder);
+      seq_param->time_scale = GST_VAAPI_ENCODER_FPS_N (encoder) * 2;
+    }
+  }
+  return TRUE;
+}
+
+/* Fills in VA picture parameter buffer */
+static gboolean
+fill_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
+{
+  VAEncPictureParameterBufferH264 *const pic_param = picture->param;
+  GstVaapiH264ViewRefPool *const ref_pool =
+      &encoder->ref_pools[encoder->view_idx];
+  GstVaapiEncoderH264Ref *ref_pic;
+  GList *reflist;
+  guint i;
+
+  memset (pic_param, 0, sizeof (VAEncPictureParameterBufferH264));
+
+  /* reference list,  */
+  pic_param->CurrPic.picture_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
+  pic_param->CurrPic.TopFieldOrderCnt = picture->poc;
+  i = 0;
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_I) {
+    for (reflist = g_queue_peek_head_link (&ref_pool->ref_list);
+        reflist; reflist = g_list_next (reflist)) {
+      ref_pic = reflist->data;
+      g_assert (ref_pic && ref_pic->pic &&
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic) != VA_INVALID_ID);
+
+      pic_param->ReferenceFrames[i].picture_id =
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic);
+      pic_param->ReferenceFrames[i].TopFieldOrderCnt = ref_pic->poc;
+      pic_param->ReferenceFrames[i].flags |=
+          VA_PICTURE_H264_SHORT_TERM_REFERENCE;
+      pic_param->ReferenceFrames[i].frame_idx = ref_pic->frame_num;
+      ++i;
+    }
+    g_assert (i <= 16 && i <= ref_pool->max_ref_frames);
+  }
+  for (; i < 16; ++i) {
+    pic_param->ReferenceFrames[i].picture_id = VA_INVALID_ID;
+  }
+  pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf);
+
+  pic_param->pic_parameter_set_id = encoder->view_idx;
+  pic_param->seq_parameter_set_id = encoder->view_idx ? 1 : 0;
+  pic_param->last_picture = 0;  /* means last encoding picture */
+  pic_param->frame_num = picture->frame_num;
+  pic_param->pic_init_qp = encoder->qp_i;
+  pic_param->num_ref_idx_l0_active_minus1 =
+      (ref_pool->max_reflist0_count ? (ref_pool->max_reflist0_count - 1) : 0);
+  pic_param->num_ref_idx_l1_active_minus1 =
+      (ref_pool->max_reflist1_count ? (ref_pool->max_reflist1_count - 1) : 0);
+  pic_param->chroma_qp_index_offset = 0;
+  pic_param->second_chroma_qp_index_offset = 0;
+
+  /* set picture fields */
+  pic_param->pic_fields.value = 0;
+  pic_param->pic_fields.bits.idr_pic_flag =
+      GST_VAAPI_ENC_PICTURE_IS_IDR (picture);
+  pic_param->pic_fields.bits.reference_pic_flag =
+      GST_VAAPI_ENC_PICTURE_IS_REFRENCE (picture);
+  pic_param->pic_fields.bits.entropy_coding_mode_flag = encoder->use_cabac;
+  pic_param->pic_fields.bits.weighted_pred_flag = FALSE;
+  pic_param->pic_fields.bits.weighted_bipred_idc = 0;
+  pic_param->pic_fields.bits.constrained_intra_pred_flag = 0;
+  pic_param->pic_fields.bits.transform_8x8_mode_flag = encoder->use_dct8x8;
+  /* enable debloking */
+  pic_param->pic_fields.bits.deblocking_filter_control_present_flag = TRUE;
+  pic_param->pic_fields.bits.redundant_pic_cnt_present_flag = FALSE;
+  /* bottom_field_pic_order_in_frame_present_flag */
+  pic_param->pic_fields.bits.pic_order_present_flag = FALSE;
+  pic_param->pic_fields.bits.pic_scaling_matrix_present_flag = FALSE;
+
+  return TRUE;
+}
+
+/* Adds slice headers to picture */
+static gboolean
+add_slice_headers (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiEncoderH264Ref ** reflist_0, guint reflist_0_count,
+    GstVaapiEncoderH264Ref ** reflist_1, guint reflist_1_count)
+{
+  VAEncSliceParameterBufferH264 *slice_param;
+  GstVaapiEncSlice *slice;
+  guint slice_of_mbs, slice_mod_mbs, cur_slice_mbs;
+  guint mb_size;
+  guint last_mb_index;
+  guint i_slice, i_ref;
+
+  g_assert (picture);
+
+  mb_size = encoder->mb_width * encoder->mb_height;
+
+  g_assert (encoder->num_slices && encoder->num_slices < mb_size);
+  slice_of_mbs = mb_size / encoder->num_slices;
+  slice_mod_mbs = mb_size % encoder->num_slices;
+  last_mb_index = 0;
+  for (i_slice = 0; i_slice < encoder->num_slices; ++i_slice) {
+    cur_slice_mbs = slice_of_mbs;
+    if (slice_mod_mbs) {
+      ++cur_slice_mbs;
+      --slice_mod_mbs;
+    }
+    slice = GST_VAAPI_ENC_SLICE_NEW (H264, encoder);
+    g_assert (slice && slice->param_id != VA_INVALID_ID);
+    slice_param = slice->param;
+
+    memset (slice_param, 0, sizeof (VAEncSliceParameterBufferH264));
+    slice_param->macroblock_address = last_mb_index;
+    slice_param->num_macroblocks = cur_slice_mbs;
+    slice_param->macroblock_info = VA_INVALID_ID;
+    slice_param->slice_type = h264_get_slice_type (picture->type);
+    g_assert ((gint8) slice_param->slice_type != -1);
+    slice_param->pic_parameter_set_id = encoder->view_idx;
+    slice_param->idr_pic_id = encoder->idr_num;
+    slice_param->pic_order_cnt_lsb = picture->poc;
+
+    /* not used if pic_order_cnt_type = 0 */
+    slice_param->delta_pic_order_cnt_bottom = 0;
+    memset (slice_param->delta_pic_order_cnt, 0,
+        sizeof (slice_param->delta_pic_order_cnt));
+
+    /* only works for B frames */
+    slice_param->direct_spatial_mv_pred_flag = TRUE;
+    /* default equal to picture parameters */
+    slice_param->num_ref_idx_active_override_flag = reflist_0_count
+        || reflist_1_count;
+    if (picture->type != GST_VAAPI_PICTURE_TYPE_I && reflist_0_count > 0)
+      slice_param->num_ref_idx_l0_active_minus1 = reflist_0_count - 1;
+    else
+      slice_param->num_ref_idx_l0_active_minus1 = 0;
+    if (picture->type == GST_VAAPI_PICTURE_TYPE_B && reflist_1_count > 0)
+      slice_param->num_ref_idx_l1_active_minus1 = reflist_1_count - 1;
+    else
+      slice_param->num_ref_idx_l1_active_minus1 = 0;
+
+    i_ref = 0;
+    if (picture->type != GST_VAAPI_PICTURE_TYPE_I) {
+      for (; i_ref < reflist_0_count; ++i_ref) {
+        slice_param->RefPicList0[i_ref].picture_id =
+            GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_0[i_ref]->pic);
+        slice_param->RefPicList0[i_ref].TopFieldOrderCnt =
+            reflist_0[i_ref]->poc;
+        slice_param->RefPicList0[i_ref].flags |=
+            VA_PICTURE_H264_SHORT_TERM_REFERENCE;
+        slice_param->RefPicList0[i_ref].frame_idx = reflist_0[i_ref]->frame_num;
+      }
+    }
+    for (; i_ref < G_N_ELEMENTS (slice_param->RefPicList0); ++i_ref) {
+      slice_param->RefPicList0[i_ref].picture_id = VA_INVALID_SURFACE;
+      slice_param->RefPicList0[i_ref].flags = VA_PICTURE_H264_INVALID;
+    }
+
+    i_ref = 0;
+    if (picture->type == GST_VAAPI_PICTURE_TYPE_B) {
+      for (; i_ref < reflist_1_count; ++i_ref) {
+        slice_param->RefPicList1[i_ref].picture_id =
+            GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_1[i_ref]->pic);
+        slice_param->RefPicList1[i_ref].TopFieldOrderCnt =
+            reflist_1[i_ref]->poc;
+        slice_param->RefPicList1[i_ref].flags |=
+            VA_PICTURE_H264_SHORT_TERM_REFERENCE;
+        slice_param->RefPicList1[i_ref].frame_idx |=
+            reflist_1[i_ref]->frame_num;
+      }
+    }
+    for (; i_ref < G_N_ELEMENTS (slice_param->RefPicList1); ++i_ref) {
+      slice_param->RefPicList1[i_ref].picture_id = VA_INVALID_SURFACE;
+      slice_param->RefPicList1[i_ref].flags = VA_PICTURE_H264_INVALID;
+    }
+
+    /* not used if  pic_param.pic_fields.bits.weighted_pred_flag == FALSE */
+    slice_param->luma_log2_weight_denom = 0;
+    slice_param->chroma_log2_weight_denom = 0;
+    slice_param->luma_weight_l0_flag = FALSE;
+    memset (slice_param->luma_weight_l0, 0,
+        sizeof (slice_param->luma_weight_l0));
+    memset (slice_param->luma_offset_l0, 0,
+        sizeof (slice_param->luma_offset_l0));
+    slice_param->chroma_weight_l0_flag = FALSE;
+    memset (slice_param->chroma_weight_l0, 0,
+        sizeof (slice_param->chroma_weight_l0));
+    memset (slice_param->chroma_offset_l0, 0,
+        sizeof (slice_param->chroma_offset_l0));
+    slice_param->luma_weight_l1_flag = FALSE;
+    memset (slice_param->luma_weight_l1, 0,
+        sizeof (slice_param->luma_weight_l1));
+    memset (slice_param->luma_offset_l1, 0,
+        sizeof (slice_param->luma_offset_l1));
+    slice_param->chroma_weight_l1_flag = FALSE;
+    memset (slice_param->chroma_weight_l1, 0,
+        sizeof (slice_param->chroma_weight_l1));
+    memset (slice_param->chroma_offset_l1, 0,
+        sizeof (slice_param->chroma_offset_l1));
+
+    slice_param->cabac_init_idc = 0;
+    slice_param->slice_qp_delta = encoder->qp_i - encoder->init_qp;
+    if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) {
+      if (picture->type == GST_VAAPI_PICTURE_TYPE_P) {
+        slice_param->slice_qp_delta += encoder->qp_ip;
+      } else if (picture->type == GST_VAAPI_PICTURE_TYPE_B) {
+        slice_param->slice_qp_delta += encoder->qp_ib;
+      }
+      if ((gint) encoder->init_qp + slice_param->slice_qp_delta <
+          (gint) encoder->min_qp) {
+        slice_param->slice_qp_delta = encoder->min_qp - encoder->init_qp;
+      }
+      if ((gint) encoder->init_qp + slice_param->slice_qp_delta >
+          (gint) encoder->max_qp) {
+        slice_param->slice_qp_delta = encoder->max_qp - encoder->init_qp;
+      }
+    }
+    slice_param->disable_deblocking_filter_idc = 0;
+    slice_param->slice_alpha_c0_offset_div2 = 2;
+    slice_param->slice_beta_offset_div2 = 2;
+
+    /* set calculation for next slice */
+    last_mb_index += cur_slice_mbs;
+
+    /* add packed Prefix NAL unit before each Coded slice NAL in base view */
+    if (encoder->is_mvc && !encoder->view_idx &&
+        (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+            VA_ENC_PACKED_HEADER_RAW_DATA)
+        && !add_packed_prefix_nal_header (encoder, picture, slice))
+      goto error_create_packed_prefix_nal_hdr;
+    if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+            VA_ENC_PACKED_HEADER_SLICE)
+        && !add_packed_slice_header (encoder, picture, slice))
+      goto error_create_packed_slice_hdr;
+
+    gst_vaapi_enc_picture_add_slice (picture, slice);
+    gst_vaapi_codec_object_replace (&slice, NULL);
+  }
+  g_assert (last_mb_index == mb_size);
+  return TRUE;
+
+error_create_packed_slice_hdr:
+  {
+    GST_ERROR ("failed to create packed slice header buffer");
+    gst_vaapi_codec_object_replace (&slice, NULL);
+    return FALSE;
+  }
+error_create_packed_prefix_nal_hdr:
+  {
+    GST_ERROR ("failed to create packed prefix nal header buffer");
+    gst_vaapi_codec_object_replace (&slice, NULL);
+    return FALSE;
+  }
+}
+
+/* Generates and submits SPS header accordingly into the bitstream */
+static gboolean
+ensure_sequence (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncSequence *sequence = NULL;
+
+  /* Insert an AU delimiter */
+  if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+          VA_ENC_PACKED_HEADER_RAW_DATA) && encoder->use_aud) {
+    if (!add_packed_au_delimiter (encoder, picture))
+      goto error_create_packed_au_delimiter;
+  }
+
+  /* submit an SPS header before every new I-frame, if codec config changed
+   * or if the picture is IDR.
+   */
+  if ((!encoder->config_changed || picture->type != GST_VAAPI_PICTURE_TYPE_I)
+      && !GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
+    return TRUE;
+
+  sequence = GST_VAAPI_ENC_SEQUENCE_NEW (H264, encoder);
+  if (!sequence || !fill_sequence (encoder, sequence))
+    goto error_create_seq_param;
+
+  /* add subset sps for non-base view and sps for base view */
+  if (encoder->is_mvc && encoder->view_idx) {
+    if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+            VA_ENC_PACKED_HEADER_SEQUENCE)
+        && !add_packed_sequence_header_mvc (encoder, picture, sequence))
+      goto error_create_packed_seq_hdr;
+  } else {
+    if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+            VA_ENC_PACKED_HEADER_SEQUENCE)
+        && !add_packed_sequence_header (encoder, picture, sequence))
+      goto error_create_packed_seq_hdr;
+  }
+
+  if (sequence) {
+    gst_vaapi_enc_picture_set_sequence (picture, sequence);
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+  }
+
+  if (!encoder->is_mvc || encoder->view_idx > 0)
+    encoder->config_changed = FALSE;
+  return TRUE;
+
+  /* ERRORS */
+error_create_seq_param:
+  {
+    GST_ERROR ("failed to create sequence parameter buffer (SPS)");
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+    return FALSE;
+  }
+error_create_packed_au_delimiter:
+  {
+    GST_ERROR ("failed to create AU delimiter");
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+  }
+error_create_packed_seq_hdr:
+  {
+    GST_ERROR ("failed to create packed sequence header buffer");
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+    return FALSE;
+  }
+}
+
+static gboolean
+ensure_control_rate_params (GstVaapiEncoderH264 * encoder)
+{
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
+    return TRUE;
+
+#if VA_CHECK_VERSION(1,1,0)
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_ICQ) {
+    GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).ICQ_quality_factor =
+        encoder->quality_factor;
+    return TRUE;
+  }
+#endif
+
+  /* RateControl params */
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).bits_per_second =
+      encoder->bitrate_bits;
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).window_size = encoder->cpb_length;
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->init_qp;
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).min_qp = encoder->min_qp;
+
+#if VA_CHECK_VERSION(1,1,0)
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).max_qp = encoder->max_qp;
+#endif
+
+#if VA_CHECK_VERSION(1,0,0)
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).rc_flags.bits.mb_rate_control =
+      (guint) encoder->mbbrc;
+#endif
+
+#if VA_CHECK_VERSION(1,3,0)
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).quality_factor =
+      encoder->quality_factor;
+#endif
+
+  /* HRD params */
+  fill_hrd_params (encoder, &GST_VAAPI_ENCODER_VA_HRD (encoder));
+
+  return TRUE;
+}
+
+/* Generates additional control parameters */
+static gboolean
+ensure_misc_params (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture))
+    return FALSE;
+
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR ||
+      GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_VBR) {
+    if (!encoder->view_idx) {
+      if ((GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) &&
+          (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+              VA_ENC_PACKED_HEADER_MISC) &&
+          !add_packed_sei_header (encoder, picture,
+              GST_VAAPI_H264_SEI_BUF_PERIOD | GST_VAAPI_H264_SEI_PIC_TIMING))
+        goto error_create_packed_sei_hdr;
+
+      else if (!GST_VAAPI_ENC_PICTURE_IS_IDR (picture) &&
+          (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+              VA_ENC_PACKED_HEADER_MISC) &&
+          !add_packed_sei_header (encoder, picture,
+              GST_VAAPI_H264_SEI_PIC_TIMING))
+        goto error_create_packed_sei_hdr;
+    }
+  }
+
+  if (!gst_vaapi_encoder_ensure_param_trellis (base_encoder, picture))
+    return FALSE;
+
+  if (!gst_vaapi_encoder_ensure_param_roi_regions (base_encoder, picture))
+    return FALSE;
+
+  if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture))
+    return FALSE;
+
+  return TRUE;
+
+error_create_packed_sei_hdr:
+  {
+    GST_ERROR ("failed to create packed SEI header");
+    return FALSE;
+  }
+}
+
+/* Generates and submits PPS header accordingly into the bitstream */
+static gboolean
+ensure_picture (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiCodedBuffer *const codedbuf =
+      GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
+  gboolean res = FALSE;
+
+  res = fill_picture (encoder, picture, codedbuf, surface);
+
+  if (!res)
+    return FALSE;
+
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
+      (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+          VA_ENC_PACKED_HEADER_PICTURE)
+      && !add_packed_picture_header (encoder, picture)) {
+    GST_ERROR ("set picture packed header failed");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/* Generates slice headers */
+static gboolean
+ensure_slices (GstVaapiEncoderH264 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncoderH264Ref *reflist_0[16];
+  GstVaapiEncoderH264Ref *reflist_1[16];
+  GstVaapiH264ViewRefPool *const ref_pool =
+      &encoder->ref_pools[encoder->view_idx];
+  guint reflist_0_count = 0, reflist_1_count = 0;
+
+  g_assert (picture);
+
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_I &&
+      !reference_list_init (encoder, picture,
+          reflist_0, &reflist_0_count, reflist_1, &reflist_1_count)) {
+    GST_ERROR ("reference list reorder failed");
+    return FALSE;
+  }
+
+  g_assert (reflist_0_count + reflist_1_count <= ref_pool->max_ref_frames);
+  if (reflist_0_count > ref_pool->max_reflist0_count)
+    reflist_0_count = ref_pool->max_reflist0_count;
+  if (reflist_1_count > ref_pool->max_reflist1_count)
+    reflist_1_count = ref_pool->max_reflist1_count;
+
+  if (!add_slice_headers (encoder, picture,
+          reflist_0, reflist_0_count, reflist_1, reflist_1_count))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Normalizes bitrate (and CPB size) for HRD conformance */
+static void
+ensure_bitrate_hrd (GstVaapiEncoderH264 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  guint bitrate, cpb_size;
+
+  if (!base_encoder->bitrate) {
+    encoder->bitrate_bits = 0;
+    return;
+  }
+
+  /* Round down bitrate. This is a hard limit mandated by the user */
+  g_assert (SX_BITRATE >= 6);
+  bitrate = (base_encoder->bitrate * 1000) & ~((1U << SX_BITRATE) - 1);
+  if (bitrate != encoder->bitrate_bits) {
+    GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate);
+    encoder->bitrate_bits = bitrate;
+    encoder->config_changed = TRUE;
+  }
+
+  /* Round up CPB size. This is an HRD compliance detail */
+  g_assert (SX_CPB_SIZE >= 4);
+  cpb_size = gst_util_uint64_scale (bitrate, encoder->cpb_length, 1000) &
+      ~((1U << SX_CPB_SIZE) - 1);
+  if (cpb_size != encoder->cpb_length_bits) {
+    GST_DEBUG ("HRD CPB size: %u bits", cpb_size);
+    encoder->cpb_length_bits = cpb_size;
+    encoder->config_changed = TRUE;
+  }
+}
+
+/* Estimates a good enough bitrate if none was supplied */
+static void
+ensure_bitrate (GstVaapiEncoderH264 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  /* Default compression: 48 bits per macroblock in "high-compression" mode */
+  switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
+    case GST_VAAPI_RATECONTROL_CBR:
+    case GST_VAAPI_RATECONTROL_VBR:
+    case GST_VAAPI_RATECONTROL_VBR_CONSTRAINED:
+    case GST_VAAPI_RATECONTROL_QVBR:
+      if (!base_encoder->bitrate) {
+        /* According to the literature and testing, CABAC entropy coding
+           mode could provide for +10% to +18% improvement in general,
+           thus estimating +15% here ; and using adaptive 8x8 transforms
+           in I-frames could bring up to +10% improvement. */
+        guint bits_per_mb = 48;
+        guint64 factor;
+
+        if (!encoder->use_cabac)
+          bits_per_mb += (bits_per_mb * 15) / 100;
+        if (!encoder->use_dct8x8)
+          bits_per_mb += (bits_per_mb * 10) / 100;
+
+        factor = (guint64) encoder->mb_width * encoder->mb_height * bits_per_mb;
+        base_encoder->bitrate =
+            gst_util_uint64_scale (factor, GST_VAAPI_ENCODER_FPS_N (encoder),
+            GST_VAAPI_ENCODER_FPS_D (encoder)) / 1000;
+        GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate);
+      }
+      break;
+    default:
+      base_encoder->bitrate = 0;
+      break;
+  }
+  ensure_bitrate_hrd (encoder);
+}
+
+/* Constructs profile and level information based on user-defined limits */
+static GstVaapiEncoderStatus
+ensure_profile_and_level (GstVaapiEncoderH264 * encoder)
+{
+  const GstVaapiProfile profile = encoder->profile;
+  const GstVaapiLevelH264 level = encoder->level;
+
+  if (!ensure_tuning (encoder))
+    GST_WARNING ("Failed to set some of the tuning option as expected! ");
+
+  if (!ensure_profile (encoder) || !ensure_profile_limits (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  /* If set low-power encode entry point and hardware doesn't have
+   * support, it will fail in ensure_hw_profile() in later stage. */
+  encoder->entrypoint =
+      gst_vaapi_encoder_get_entrypoint (GST_VAAPI_ENCODER_CAST (encoder),
+      encoder->profile);
+  if (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID) {
+    GST_WARNING ("Cannot find valid entrypoint");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  /* Check HW constraints */
+  if (!ensure_hw_profile_limits (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  if (encoder->profile_idc > encoder->hw_max_profile_idc)
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  /* Ensure bitrate if not set already and derive the right level to use */
+  ensure_bitrate (encoder);
+  if (!ensure_level (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+
+  if (encoder->profile != profile || encoder->level != level) {
+    GST_DEBUG ("selected %s profile at level %s",
+        gst_vaapi_utils_h264_get_profile_string (encoder->profile),
+        gst_vaapi_utils_h264_get_level_string (encoder->level));
+    encoder->config_changed = TRUE;
+  }
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static void
+reset_properties (GstVaapiEncoderH264 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  guint mb_size, i;
+  gboolean ret;
+
+  if (encoder->idr_period < base_encoder->keyframe_period)
+    encoder->idr_period = base_encoder->keyframe_period;
+
+  g_assert (encoder->min_qp <= encoder->max_qp);
+  if (encoder->min_qp > encoder->init_qp)
+    encoder->min_qp = encoder->init_qp;
+  if (encoder->max_qp < encoder->init_qp)
+    encoder->max_qp = encoder->init_qp;
+
+  encoder->qp_i = encoder->init_qp;
+
+  mb_size = encoder->mb_width * encoder->mb_height;
+  ret = gst_vaapi_encoder_ensure_num_slices (base_encoder, encoder->profile,
+      encoder->entrypoint, (mb_size + 1) / 2, &encoder->num_slices);
+  g_assert (ret);
+
+  if (encoder->num_bframes > (base_encoder->keyframe_period + 1) / 2)
+    encoder->num_bframes = (base_encoder->keyframe_period + 1) / 2;
+
+  gst_vaapi_encoder_ensure_max_num_ref_frames (base_encoder, encoder->profile,
+      encoder->entrypoint);
+
+  if (base_encoder->max_num_ref_frames_1 < 1 && encoder->num_bframes > 0) {
+    GST_WARNING ("Disabling b-frame since the driver doesn't support it");
+    encoder->num_bframes = 0;
+
+    if (encoder->prediction_type ==
+        GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B)
+      encoder->prediction_type = GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT;
+  }
+
+  if (encoder->num_ref_frames > base_encoder->max_num_ref_frames_0) {
+    GST_INFO ("Lowering the number of reference frames to %d",
+        base_encoder->max_num_ref_frames_0);
+    encoder->num_ref_frames = base_encoder->max_num_ref_frames_0;
+  }
+
+  if (encoder->num_bframes > 0 && GST_VAAPI_ENCODER_FPS_N (encoder) > 0)
+    encoder->cts_offset = gst_util_uint64_scale (GST_SECOND,
+        GST_VAAPI_ENCODER_FPS_D (encoder), GST_VAAPI_ENCODER_FPS_N (encoder));
+  else
+    encoder->cts_offset = 0;
+
+  /* init max_frame_num, max_poc */
+  encoder->log2_max_frame_num =
+      h264_get_log2_max_frame_num (encoder->idr_period);
+  g_assert (encoder->log2_max_frame_num >= 4);
+  encoder->max_frame_num = (1 << encoder->log2_max_frame_num);
+  encoder->log2_max_pic_order_cnt = encoder->log2_max_frame_num + 1;
+  encoder->max_pic_order_cnt = (1 << encoder->log2_max_pic_order_cnt);
+  encoder->idr_num = 0;
+
+  /* If temporal scalability enabled then use hierarchical-p/b
+   * according to num_bframes as default prediction */
+  if (encoder->temporal_levels > 1
+      && encoder->prediction_type ==
+      GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT) {
+    if (encoder->num_bframes > 0)
+      encoder->prediction_type =
+          GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B;
+    else
+      encoder->prediction_type =
+          GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_P;
+  }
+
+  if (encoder->prediction_type != GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT) {
+
+    /* Hierarchical prediction should have a temporal level count
+     * greater than one and we use 4 temporal levels as default */
+    if (encoder->temporal_levels <= 1)
+      encoder->temporal_levels = 4;
+
+    /* this ip_period calculation is for supporting hierarchical-p
+     * and hierarchical-b encode */
+    encoder->ip_period = 1 << (encoder->temporal_levels - 1);
+
+    /* align the idr_period to ip_peroid to simplify encode process */
+    encoder->idr_period =
+        GST_ROUND_UP_N (encoder->idr_period, encoder->ip_period);
+
+    GST_VAAPI_ENCODER_KEYFRAME_PERIOD (base_encoder) = encoder->idr_period;
+
+    /* Disable mvc-encode in hierarchical mode */
+    if (encoder->num_views > 1) {
+      encoder->num_views = 1;
+      encoder->is_mvc = FALSE;
+    }
+
+    /* no b-frames in Hierarchical-P */
+    if (encoder->prediction_type ==
+        GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_P)
+      encoder->num_bframes = 0;
+
+    /* reset number of b-frames in Hierarchical-B */
+    if (encoder->prediction_type ==
+        GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B)
+      encoder->num_bframes = (1 << (encoder->temporal_levels - 1)) - 1;
+  } else {
+    encoder->ip_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder) > 1 ?
+        (1 + encoder->num_bframes) : 0;
+  }
+
+  for (i = 0; i < encoder->num_views; i++) {
+    GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
+    GstVaapiH264ViewReorderPool *const reorder_pool =
+        &encoder->reorder_pools[i];
+
+    if (encoder->prediction_type == GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT) {
+      ref_pool->max_reflist0_count = encoder->num_ref_frames;
+      ref_pool->max_reflist1_count = encoder->num_bframes > 0;
+      ref_pool->max_ref_frames = ref_pool->max_reflist0_count
+          + ref_pool->max_reflist1_count;
+    } else {
+      guint d;
+
+      /* This shouldn't be executed on MVC encoding */
+      g_assert (i < 1);
+
+      ref_pool->max_ref_frames =
+          encoder->temporal_levels * (encoder->temporal_levels) / 2 +
+          (encoder->num_bframes > 0);
+      ref_pool->max_reflist0_count = 1;
+      ref_pool->max_reflist1_count = encoder->num_bframes > 0;
+      encoder->num_ref_frames = ref_pool->max_ref_frames;
+
+      d = encoder->ip_period;
+      /* temporal_level_div[] is helpful to find out the temporal level
+       * where each frame should belongs */
+      for (i = 0; i < encoder->temporal_levels; i++) {
+        encoder->temporal_level_div[i] = d;
+        d >>= 1;
+      }
+    }
+
+    reorder_pool->frame_index = 0;
+  }
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h264_encode (GstVaapiEncoder * base_encoder,
+    GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
+{
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder);
+  GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  GstVaapiSurfaceProxy *reconstruct = NULL;
+
+  reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
+
+  g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
+
+  if (!ensure_sequence (encoder, picture))
+    goto error;
+  if (!ensure_misc_params (encoder, picture))
+    goto error;
+  if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
+    goto error;
+  if (!ensure_slices (encoder, picture))
+    goto error;
+  if (!gst_vaapi_enc_picture_encode (picture))
+    goto error;
+
+  if (!reference_list_update (encoder, picture, reconstruct))
+    goto error;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    if (reconstruct)
+      gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
+          reconstruct);
+    return ret;
+  }
+}
+
+/* reorder_list sorting for hierarchical-b encode */
+static gint
+sort_hierarchical_b (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+  GstVaapiEncPicture *pic1 = (GstVaapiEncPicture *) a;
+  GstVaapiEncPicture *pic2 = (GstVaapiEncPicture *) b;
+
+  if (pic1->type != GST_VAAPI_PICTURE_TYPE_B)
+    return 1;
+  if (pic2->type != GST_VAAPI_PICTURE_TYPE_B)
+    return -1;
+  if (pic1->temporal_id == pic2->temporal_id)
+    return pic1->poc - pic2->poc;
+  else
+    return pic1->temporal_id - pic2->temporal_id;
+}
+
+struct _PendingIterState
+{
+  guint cur_view;
+  GstVaapiPictureType pic_type;
+};
+
+static gboolean
+gst_vaapi_encoder_h264_get_pending_reordered (GstVaapiEncoder * base_encoder,
+    GstVaapiEncPicture ** picture, gpointer * state)
+{
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder);
+  GstVaapiH264ViewReorderPool *reorder_pool;
+  GstVaapiEncPicture *pic = NULL;
+  struct _PendingIterState *iter;
+
+  g_return_val_if_fail (state, FALSE);
+
+  if (!*state) {
+    iter = g_new0 (struct _PendingIterState, 1);
+    iter->pic_type = GST_VAAPI_PICTURE_TYPE_P;
+    *state = iter;
+  } else {
+    iter = *state;
+  }
+
+  *picture = NULL;
+
+  if (iter->cur_view >= encoder->num_views)
+    return FALSE;
+
+  reorder_pool = &encoder->reorder_pools[iter->cur_view];
+  if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
+    iter->cur_view++;
+    return TRUE;                /* perhaps other views has pictures? */
+  }
+
+  if (iter->pic_type == GST_VAAPI_PICTURE_TYPE_P) {
+    pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list);
+    g_assert (pic);
+    set_p_frame (pic, encoder);
+
+    g_queue_foreach (&reorder_pool->reorder_frame_list, (GFunc) set_b_frame,
+        encoder);
+    /* sort the queued list of frames for hierarchical-b based on
+     * temporal level where each frame belongs */
+    if (encoder->prediction_type ==
+        GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B) {
+      pic->temporal_id = 0;
+      GST_VAAPI_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE);
+
+      g_queue_sort (&reorder_pool->reorder_frame_list, sort_hierarchical_b,
+          NULL);
+    }
+
+    iter->pic_type = GST_VAAPI_PICTURE_TYPE_B;
+  } else if (iter->pic_type == GST_VAAPI_PICTURE_TYPE_B) {
+    pic = g_queue_pop_head (&reorder_pool->reorder_frame_list);
+    g_assert (pic);
+  } else {
+    GST_WARNING ("Unhandled pending picture type");
+  }
+
+  set_frame_num (encoder, pic);
+
+  if (GST_CLOCK_TIME_IS_VALID (pic->frame->pts))
+    pic->frame->pts += encoder->cts_offset;
+
+  *picture = pic;
+  return TRUE;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h264_flush (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder);
+  GstVaapiH264ViewReorderPool *reorder_pool;
+  GstVaapiEncPicture *pic;
+  guint i;
+
+  for (i = 0; i < encoder->num_views; i++) {
+    reorder_pool = &encoder->reorder_pools[i];
+    reorder_pool->frame_index = 0;
+    reorder_pool->cur_frame_num = 0;
+    reorder_pool->cur_present_index = 0;
+    reorder_pool->prev_frame_is_ref = FALSE;
+
+    while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
+      pic = (GstVaapiEncPicture *)
+          g_queue_pop_head (&reorder_pool->reorder_frame_list);
+      gst_vaapi_enc_picture_unref (pic);
+    }
+    g_queue_clear (&reorder_pool->reorder_frame_list);
+  }
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+/* Generate "codec-data" buffer */
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h264_get_codec_data (GstVaapiEncoder * base_encoder,
+    GstBuffer ** out_buffer_ptr)
+{
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder);
+  const guint32 configuration_version = 0x01;
+  const guint32 nal_length_size = 4;
+  guint8 profile_idc, profile_comp, level_idc;
+  GstMapInfo sps_info, pps_info;
+  GstBitWriter bs;
+  GstBuffer *buffer;
+
+  if (!encoder->sps_data || !encoder->pps_data)
+    return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER;
+  if (gst_buffer_get_size (encoder->sps_data) < 4)
+    return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER;
+
+  if (!gst_buffer_map (encoder->sps_data, &sps_info, GST_MAP_READ))
+    goto error_map_sps_buffer;
+
+  if (!gst_buffer_map (encoder->pps_data, &pps_info, GST_MAP_READ))
+    goto error_map_pps_buffer;
+
+  /* skip sps_data[0], which is the nal_unit_type */
+  profile_idc = sps_info.data[1];
+  profile_comp = sps_info.data[2];
+  level_idc = sps_info.data[3];
+
+  /* Header */
+  gst_bit_writer_init_with_size (&bs, (sps_info.size + pps_info.size + 64),
+      FALSE);
+  WRITE_UINT32 (&bs, configuration_version, 8);
+  WRITE_UINT32 (&bs, profile_idc, 8);
+  WRITE_UINT32 (&bs, profile_comp, 8);
+  WRITE_UINT32 (&bs, level_idc, 8);
+  WRITE_UINT32 (&bs, 0x3f, 6);  /* 111111 */
+  WRITE_UINT32 (&bs, nal_length_size - 1, 2);
+  WRITE_UINT32 (&bs, 0x07, 3);  /* 111 */
+
+  /* Write SPS */
+  WRITE_UINT32 (&bs, 1, 5);     /* SPS count = 1 */
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  /* Write Nal unit length and data of SPS */
+  if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, sps_info.data, sps_info.size))
+    goto nal_to_byte_stream_error;
+
+  /* Write PPS */
+  WRITE_UINT32 (&bs, 1, 8);     /* PPS count = 1 */
+  /* Write Nal unit length and data of PPS */
+  if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, pps_info.data, pps_info.size))
+    goto nal_to_byte_stream_error;
+
+  gst_buffer_unmap (encoder->pps_data, &pps_info);
+  gst_buffer_unmap (encoder->sps_data, &sps_info);
+
+  buffer = gst_bit_writer_reset_and_get_buffer (&bs);
+  if (!buffer)
+    goto error_alloc_buffer;
+  if (gst_buffer_n_memory (buffer) == 0) {
+    gst_buffer_unref (buffer);
+    goto error_alloc_buffer;
+  }
+  *out_buffer_ptr = buffer;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_ERROR ("failed to write codec-data");
+    gst_buffer_unmap (encoder->sps_data, &sps_info);
+    gst_buffer_unmap (encoder->pps_data, &pps_info);
+    gst_bit_writer_reset (&bs);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+nal_to_byte_stream_error:
+  {
+    GST_ERROR ("failed to write nal unit");
+    gst_buffer_unmap (encoder->sps_data, &sps_info);
+    gst_buffer_unmap (encoder->pps_data, &pps_info);
+    gst_bit_writer_reset (&bs);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+error_map_sps_buffer:
+  {
+    GST_ERROR ("failed to map SPS packed header");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+error_map_pps_buffer:
+  {
+    GST_ERROR ("failed to map PPS packed header");
+    gst_buffer_unmap (encoder->sps_data, &sps_info);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+error_alloc_buffer:
+  {
+    GST_ERROR ("failed to allocate codec-data buffer");
+    gst_bit_writer_reset (&bs);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+}
+
+static guint32
+get_temporal_id (GstVaapiEncoderH264 * encoder, guint32 display_order)
+{
+  int l;
+  for (l = 0; l < encoder->temporal_levels; l++) {
+    if ((display_order % encoder->temporal_level_div[l]) == 0)
+      return l;
+  }
+
+  GST_WARNING ("Couldn't find valid temporal id");
+  return 0;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h264_reordering (GstVaapiEncoder * base_encoder,
+    GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
+{
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder);
+  GstVaapiH264ViewReorderPool *reorder_pool = NULL;
+  GstVaapiEncPicture *picture;
+  gboolean is_idr = FALSE;
+
+  *output = NULL;
+
+  /* encoding views alternatively for MVC */
+  if (encoder->is_mvc) {
+    /* FIXME: Use first-in-bundle flag on buffers to reset view idx? */
+    if (frame)
+      encoder->view_idx = frame->system_frame_number % encoder->num_views;
+    else
+      encoder->view_idx = (encoder->view_idx + 1) % encoder->num_views;
+  }
+  reorder_pool = &encoder->reorder_pools[encoder->view_idx];
+
+  if (!frame) {
+    if (reorder_pool->reorder_state != GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES)
+      return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
+
+    /* reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES
+       dump B frames from queue, sometime, there may also have P frame or I frame */
+    g_assert (encoder->num_bframes > 0);
+    g_return_val_if_fail (!g_queue_is_empty (&reorder_pool->reorder_frame_list),
+        GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN);
+
+    /* sort the queued list of frames for hierarchical-b based on
+     * temporal level where each frame belongs */
+    if (encoder->prediction_type ==
+        GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B)
+      g_queue_sort (&reorder_pool->reorder_frame_list, sort_hierarchical_b,
+          NULL);
+
+    picture = g_queue_pop_head (&reorder_pool->reorder_frame_list);
+    g_assert (picture);
+    if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
+      reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES;
+    }
+    goto end;
+  }
+
+  /* new frame coming */
+  picture = GST_VAAPI_ENC_PICTURE_NEW (H264, encoder, frame);
+  if (!picture) {
+    GST_WARNING ("create H264 picture failed, frame timestamp:%"
+        GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  ++reorder_pool->cur_present_index;
+  picture->poc = ((reorder_pool->cur_present_index * 2) %
+      encoder->max_pic_order_cnt);
+
+  picture->temporal_id = (encoder->temporal_levels == 1) ? 1 :
+      get_temporal_id (encoder, reorder_pool->frame_index);
+
+  is_idr = (reorder_pool->frame_index == 0 ||
+      reorder_pool->frame_index >= encoder->idr_period);
+
+  /* check key frames */
+  if (is_idr || GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame) ||
+      (reorder_pool->frame_index %
+          GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder)) == 0) {
+    ++reorder_pool->frame_index;
+
+    /* b frame enabled,  check queue of reorder_frame_list */
+    if (encoder->num_bframes
+        && !g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
+      GstVaapiEncPicture *p_pic;
+
+      p_pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list);
+      set_p_frame (p_pic, encoder);
+
+      /* for hierarchical-b, if idr-period reached , make sure the
+       * most recent queued frame get encoded as a reference
+       * p-frame in base-layer */
+      if (encoder->prediction_type ==
+          GST_VAAPI_ENCODER_H264_PREDICTION_HIERARCHICAL_B) {
+        p_pic->temporal_id = 0;
+        GST_VAAPI_PICTURE_FLAG_SET (p_pic,
+            GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE);
+      }
+      /* Fix : make sure the detached head is non-ref, currently it is ref */
+
+      g_queue_foreach (&reorder_pool->reorder_frame_list,
+          (GFunc) set_b_frame, encoder);
+      set_key_frame (picture, encoder,
+          is_idr | GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame));
+      g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
+      picture = p_pic;
+      reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES;
+    } else {                    /* no b frames in queue */
+      set_key_frame (picture, encoder,
+          is_idr | GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame));
+      g_assert (g_queue_is_empty (&reorder_pool->reorder_frame_list));
+      if (encoder->num_bframes)
+        reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES;
+    }
+    goto end;
+  }
+
+  /* new p/b frames coming */
+  ++reorder_pool->frame_index;
+  if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES &&
+      g_queue_get_length (&reorder_pool->reorder_frame_list) <
+      encoder->num_bframes) {
+    g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
+    return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
+  }
+
+  set_p_frame (picture, encoder);
+
+  if (reorder_pool->reorder_state == GST_VAAPI_ENC_H264_REORD_WAIT_FRAMES) {
+    g_queue_foreach (&reorder_pool->reorder_frame_list, (GFunc) set_b_frame,
+        encoder);
+    reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_DUMP_FRAMES;
+    g_assert (!g_queue_is_empty (&reorder_pool->reorder_frame_list));
+  }
+
+end:
+  g_assert (picture);
+  frame = picture->frame;
+  if (GST_CLOCK_TIME_IS_VALID (frame->pts))
+    frame->pts += encoder->cts_offset;
+
+  /* set frame_num based on previous frame reference type */
+  set_frame_num (encoder, picture);
+
+  *output = picture;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+set_context_info (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder);
+  GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+  const guint DEFAULT_SURFACES_COUNT = 3;
+
+  /* Maximum sizes for common headers (in bits) */
+  enum
+  {
+    MAX_SPS_HDR_SIZE = 16473,
+    MAX_VUI_PARAMS_SIZE = 210,
+    MAX_HRD_PARAMS_SIZE = 4103,
+    MAX_PPS_HDR_SIZE = 101,
+    MAX_SLICE_HDR_SIZE = 397 + 2572 + 6670 + 2402,
+  };
+
+  if (!ensure_hw_profile (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  base_encoder->num_ref_frames = (encoder->num_ref_frames
+      + (encoder->num_bframes > 0 ? 1 : 0) + DEFAULT_SURFACES_COUNT)
+      * encoder->num_views;
+
+  /* Only YUV 4:2:0 formats are supported for now. This means that we
+     have a limit of 3200 bits per macroblock. */
+  /* XXX: check profile and compute RawMbBits */
+  base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) *
+      GST_ROUND_UP_16 (vip->height) / 256) * 400;
+
+  /* Account for SPS header */
+  /* XXX: exclude scaling lists, MVC/SVC extensions */
+  base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE +
+      MAX_VUI_PARAMS_SIZE + 2 * MAX_HRD_PARAMS_SIZE) / 8;
+
+  /* Account for PPS header */
+  /* XXX: exclude slice groups, scaling lists, MVC/SVC extensions */
+  base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8;
+
+  /* Account for slice header */
+  base_encoder->codedbuf_size += encoder->num_slices * (4 +
+      GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE) / 8);
+  /* Some of the Intel Platforms(eg: APL) doesn't have LLC so
+   * the driver call cflush to ensure data consistency which is an
+   * expensive operation but we can still reduce the impact by
+   * limitting the pre-calculated coded_buffer size. This is not
+   * strictly following the h264 specification, but should be safe
+   * enough with intel-vaapi-driver. Our test cases showing significat
+   * performance improvement on APL platfrom with small coded-buffer size */
+  if (encoder->compliance_mode ==
+      GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_RESTRICT_CODED_BUFFER_ALLOC)
+    base_encoder->codedbuf_size /= encoder->min_cr;
+
+  base_encoder->context_info.profile = base_encoder->profile;
+  base_encoder->context_info.entrypoint = encoder->entrypoint;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h264_reconfigure (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (base_encoder);
+  GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+  GstVaapiEncoderStatus status;
+  guint mb_width, mb_height;
+
+  mb_width = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16;
+  mb_height = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16;
+  if (mb_width != encoder->mb_width || mb_height != encoder->mb_height) {
+    GST_DEBUG ("resolution: %dx%d", GST_VAAPI_ENCODER_WIDTH (encoder),
+        GST_VAAPI_ENCODER_HEIGHT (encoder));
+    encoder->mb_width = mb_width;
+    encoder->mb_height = mb_height;
+    encoder->config_changed = TRUE;
+  }
+
+  /* Take number of MVC views from input caps if provided */
+  if (GST_VIDEO_INFO_MULTIVIEW_MODE (vip) ==
+      GST_VIDEO_MULTIVIEW_MODE_FRAME_BY_FRAME
+      || GST_VIDEO_INFO_MULTIVIEW_MODE (vip) ==
+      GST_VIDEO_MULTIVIEW_MODE_MULTIVIEW_FRAME_BY_FRAME)
+    encoder->num_views = GST_VIDEO_INFO_VIEWS (vip);
+
+  encoder->is_mvc = encoder->num_views > 1;
+
+  status = ensure_profile_and_level (encoder);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return status;
+
+  reset_properties (encoder);
+  ensure_control_rate_params (encoder);
+  return set_context_info (base_encoder);
+}
+
+struct _GstVaapiEncoderH264Class
+{
+  GstVaapiEncoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiEncoderH264, gst_vaapi_encoder_h264,
+    GST_TYPE_VAAPI_ENCODER);
+
+static void
+gst_vaapi_encoder_h264_init (GstVaapiEncoderH264 * encoder)
+{
+  guint32 i;
+
+  /* Default encoding entrypoint */
+  encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
+
+  /* Multi-view coding information */
+  encoder->is_mvc = FALSE;
+  encoder->num_views = 1;
+  encoder->view_idx = 0;
+  encoder->temporal_levels = MIN_TEMPORAL_LEVELS;
+  encoder->abs_diff_pic_num_list0 = 1;
+  encoder->abs_diff_pic_num_list1 = 1;
+  memset (encoder->view_ids, 0, sizeof (encoder->view_ids));
+
+  /* re-ordering  list initialize */
+  for (i = 0; i < MAX_NUM_VIEWS; i++) {
+    GstVaapiH264ViewReorderPool *const reorder_pool =
+        &encoder->reorder_pools[i];
+    g_queue_init (&reorder_pool->reorder_frame_list);
+    reorder_pool->reorder_state = GST_VAAPI_ENC_H264_REORD_NONE;
+    reorder_pool->frame_index = 0;
+    reorder_pool->cur_frame_num = 0;
+    reorder_pool->cur_present_index = 0;
+  }
+
+  /* reference list info initialize */
+  for (i = 0; i < MAX_NUM_VIEWS; i++) {
+    GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
+    g_queue_init (&ref_pool->ref_list);
+    ref_pool->max_ref_frames = 0;
+    ref_pool->max_reflist0_count = 1;
+    ref_pool->max_reflist1_count = 1;
+  }
+
+  encoder->compliance_mode = GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_STRICT;
+  encoder->min_cr = 1;
+}
+
+static void
+gst_vaapi_encoder_h264_finalize (GObject * object)
+{
+  /*free private buffers */
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (object);
+  GstVaapiEncPicture *pic;
+  GstVaapiEncoderH264Ref *ref;
+  guint32 i;
+
+  gst_buffer_replace (&encoder->sps_data, NULL);
+  gst_buffer_replace (&encoder->subset_sps_data, NULL);
+  gst_buffer_replace (&encoder->pps_data, NULL);
+
+  /* reference list info de-init */
+  for (i = 0; i < MAX_NUM_VIEWS; i++) {
+    GstVaapiH264ViewRefPool *const ref_pool = &encoder->ref_pools[i];
+    while (!g_queue_is_empty (&ref_pool->ref_list)) {
+      ref = (GstVaapiEncoderH264Ref *) g_queue_pop_head (&ref_pool->ref_list);
+      reference_pic_free (encoder, ref);
+    }
+    g_queue_clear (&ref_pool->ref_list);
+  }
+
+  /* re-ordering  list initialize */
+  for (i = 0; i < MAX_NUM_VIEWS; i++) {
+    GstVaapiH264ViewReorderPool *const reorder_pool =
+        &encoder->reorder_pools[i];
+    while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
+      pic = (GstVaapiEncPicture *)
+          g_queue_pop_head (&reorder_pool->reorder_frame_list);
+      gst_vaapi_enc_picture_unref (pic);
+    }
+    g_queue_clear (&reorder_pool->reorder_frame_list);
+  }
+
+  G_OBJECT_CLASS (gst_vaapi_encoder_h264_parent_class)->finalize (object);
+}
+
+static void
+set_view_ids (GstVaapiEncoderH264 * const encoder, const GValue * value)
+{
+  guint i, j;
+  guint len = gst_value_array_get_size (value);
+
+  if (len == 0)
+    goto set_default_ids;
+
+  if (len != encoder->num_views) {
+    GST_WARNING ("The view number is %d, but %d view IDs are provided. Just "
+        "fallback to use default view IDs.", encoder->num_views, len);
+    goto set_default_ids;
+  }
+
+  for (i = 0; i < len; i++) {
+    const GValue *val = gst_value_array_get_value (value, i);
+    encoder->view_ids[i] = g_value_get_uint (val);
+  }
+
+  /* check whether duplicated ID */
+  for (i = 0; i < len; i++) {
+    for (j = i + 1; j < len; j++) {
+      if (encoder->view_ids[i] == encoder->view_ids[j]) {
+        GST_WARNING ("The view %d and view %d have same view ID %d. Just "
+            "fallback to use default view IDs.", i, j, encoder->view_ids[i]);
+        goto set_default_ids;
+      }
+    }
+  }
+
+  return;
+
+set_default_ids:
+  {
+    for (i = 0; i < encoder->num_views; i++)
+      encoder->view_ids[i] = i;
+  }
+}
+
+static void
+get_view_ids (GstVaapiEncoderH264 * const encoder, GValue * value)
+{
+  guint i;
+  GValue id = G_VALUE_INIT;
+
+  g_value_reset (value);
+  g_value_init (&id, G_TYPE_UINT);
+
+  for (i = 0; i < encoder->num_views; i++) {
+    g_value_set_uint (&id, encoder->view_ids[i]);
+    gst_value_array_append_value (value, &id);
+  }
+  g_value_unset (&id);
+}
+
+/**
+ * @ENCODER_H264_PROP_RATECONTROL: Rate control (#GstVaapiRateControl).
+ * @ENCODER_H264_PROP_TUNE: The tuning options (#GstVaapiEncoderTune).
+ * @ENCODER_H264_PROP_MAX_BFRAMES: Number of B-frames between I
+ *   and P (uint).
+ * @ENCODER_H264_PROP_INIT_QP: Initial quantizer value (uint).
+ * @ENCODER_H264_PROP_MIN_QP: Minimal quantizer value (uint).
+ * @ENCODER_H264_PROP_NUM_SLICES: Number of slices per frame (uint).
+ * @ENCODER_H264_PROP_CABAC: Enable CABAC entropy coding mode (bool).
+ * @ENCODER_H264_PROP_DCT8X8: Enable adaptive use of 8x8
+ *   transforms in I-frames (bool).
+ * @ENCODER_H264_PROP_CPB_LENGTH: Length of the CPB buffer
+ *   in milliseconds (uint).
+ * @ENCODER_H264_PROP_NUM_VIEWS: Number of views per frame.
+ * @ENCODER_H264_PROP_VIEW_IDS: View IDs
+ * @ENCODER_H264_PROP_AUD: Insert AUD as first NAL per frame.
+ * @ENCODER_H264_PROP_COMPLIANCE_MODE: Relax Compliance restrictions
+ * @ENCODER_H264_PROP_NUM_REF_FRAMES: Maximum number of reference frames.
+ * @ENCODER_H264_PROP_MBBRC: Macroblock level Bitrate Control.
+ * @ENCODER_H264_PROP_QP_IP: Difference of QP between I and P frame.
+ * @ENCODER_H264_PROP_QP_IB: Difference of QP between I and B frame.
+ * @ENCODER_H264_PROP_TEMPORAL_LEVELS: Number of temporal levels
+ * @ENCODER_H264_PROP_PREDICTION_TYPE: Reference picture selection modes
+ * @ENCODER_H264_PROP_MAX_QP: Maximal quantizer value (uint).
+ * @ENCODER_H264_PROP_QUALITY_FACTOR: Factor for ICQ/QVBR bitrate control mode.
+ *
+ * The set of H.264 encoder specific configurable properties.
+ */
+enum
+{
+  ENCODER_H264_PROP_RATECONTROL = 1,
+  ENCODER_H264_PROP_TUNE,
+  ENCODER_H264_PROP_MAX_BFRAMES,
+  ENCODER_H264_PROP_INIT_QP,
+  ENCODER_H264_PROP_MIN_QP,
+  ENCODER_H264_PROP_NUM_SLICES,
+  ENCODER_H264_PROP_CABAC,
+  ENCODER_H264_PROP_DCT8X8,
+  ENCODER_H264_PROP_CPB_LENGTH,
+  ENCODER_H264_PROP_NUM_VIEWS,
+  ENCODER_H264_PROP_VIEW_IDS,
+  ENCODER_H264_PROP_AUD,
+  ENCODER_H264_PROP_COMPLIANCE_MODE,
+  ENCODER_H264_PROP_NUM_REF_FRAMES,
+  ENCODER_H264_PROP_MBBRC,
+  ENCODER_H264_PROP_QP_IP,
+  ENCODER_H264_PROP_QP_IB,
+  ENCODER_H264_PROP_TEMPORAL_LEVELS,
+  ENCODER_H264_PROP_PREDICTION_TYPE,
+  ENCODER_H264_PROP_MAX_QP,
+  ENCODER_H264_PROP_QUALITY_FACTOR,
+  ENCODER_H264_N_PROPERTIES
+};
+
+static GParamSpec *properties[ENCODER_H264_N_PROPERTIES];
+
+static void
+gst_vaapi_encoder_h264_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (object);
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+
+  if (base_encoder->num_codedbuf_queued > 0) {
+    GST_ERROR_OBJECT (object,
+        "failed to set any property after encoding started");
+    return;
+  }
+
+  switch (prop_id) {
+    case ENCODER_H264_PROP_RATECONTROL:
+      gst_vaapi_encoder_set_rate_control (base_encoder,
+          g_value_get_enum (value));
+      break;
+    case ENCODER_H264_PROP_TUNE:
+      gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value));
+      break;
+    case ENCODER_H264_PROP_MAX_BFRAMES:
+      encoder->num_bframes = g_value_get_uint (value);
+      break;
+    case ENCODER_H264_PROP_INIT_QP:
+      encoder->init_qp = g_value_get_uint (value);
+      break;
+    case ENCODER_H264_PROP_MIN_QP:
+      encoder->min_qp = g_value_get_uint (value);
+      break;
+    case ENCODER_H264_PROP_QP_IP:
+      encoder->qp_ip = g_value_get_int (value);
+      break;
+    case ENCODER_H264_PROP_QP_IB:
+      encoder->qp_ib = g_value_get_int (value);
+      break;
+    case ENCODER_H264_PROP_NUM_SLICES:
+      encoder->num_slices = g_value_get_uint (value);
+      break;
+    case ENCODER_H264_PROP_CABAC:
+      encoder->use_cabac = g_value_get_boolean (value);
+      break;
+    case ENCODER_H264_PROP_DCT8X8:
+      encoder->use_dct8x8 = g_value_get_boolean (value);
+      break;
+    case ENCODER_H264_PROP_CPB_LENGTH:
+      encoder->cpb_length = g_value_get_uint (value);
+      break;
+    case ENCODER_H264_PROP_NUM_VIEWS:
+      encoder->num_views = g_value_get_uint (value);
+      break;
+    case ENCODER_H264_PROP_VIEW_IDS:
+      set_view_ids (encoder, value);
+      break;
+    case ENCODER_H264_PROP_AUD:
+      encoder->use_aud = g_value_get_boolean (value);
+      break;
+    case ENCODER_H264_PROP_COMPLIANCE_MODE:
+      encoder->compliance_mode = g_value_get_enum (value);
+      break;
+    case ENCODER_H264_PROP_NUM_REF_FRAMES:
+      encoder->num_ref_frames = g_value_get_uint (value);
+      break;
+    case ENCODER_H264_PROP_MBBRC:
+      encoder->mbbrc = g_value_get_enum (value);
+      break;
+    case ENCODER_H264_PROP_TEMPORAL_LEVELS:
+      encoder->temporal_levels = g_value_get_uint (value);
+      break;
+    case ENCODER_H264_PROP_PREDICTION_TYPE:
+      encoder->prediction_type = g_value_get_enum (value);
+      break;
+    case ENCODER_H264_PROP_MAX_QP:
+      encoder->max_qp = g_value_get_uint (value);
+      break;
+    case ENCODER_H264_PROP_QUALITY_FACTOR:
+      encoder->quality_factor = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_encoder_h264_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoderH264 *const encoder = GST_VAAPI_ENCODER_H264 (object);
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+
+  switch (prop_id) {
+    case ENCODER_H264_PROP_RATECONTROL:
+      g_value_set_enum (value, base_encoder->rate_control);
+      break;
+    case ENCODER_H264_PROP_TUNE:
+      g_value_set_enum (value, base_encoder->tune);
+      break;
+    case ENCODER_H264_PROP_MAX_BFRAMES:
+      g_value_set_uint (value, encoder->num_bframes);
+      break;
+    case ENCODER_H264_PROP_INIT_QP:
+      g_value_set_uint (value, encoder->init_qp);
+      break;
+    case ENCODER_H264_PROP_MIN_QP:
+      g_value_set_uint (value, encoder->min_qp);
+      break;
+    case ENCODER_H264_PROP_QP_IP:
+      g_value_set_int (value, encoder->qp_ip);
+      break;
+    case ENCODER_H264_PROP_QP_IB:
+      g_value_set_int (value, encoder->qp_ib);
+      break;
+    case ENCODER_H264_PROP_NUM_SLICES:
+      g_value_set_uint (value, encoder->num_slices);
+      break;
+    case ENCODER_H264_PROP_CABAC:
+      g_value_set_boolean (value, encoder->use_cabac);
+      break;
+    case ENCODER_H264_PROP_DCT8X8:
+      g_value_set_boolean (value, encoder->use_dct8x8);
+      break;
+    case ENCODER_H264_PROP_CPB_LENGTH:
+      g_value_set_uint (value, encoder->cpb_length);
+      break;
+    case ENCODER_H264_PROP_NUM_VIEWS:
+      g_value_set_uint (value, encoder->num_views);
+      break;
+    case ENCODER_H264_PROP_VIEW_IDS:
+      get_view_ids (encoder, value);
+      break;
+    case ENCODER_H264_PROP_AUD:
+      g_value_set_boolean (value, encoder->use_aud);
+      break;
+    case ENCODER_H264_PROP_COMPLIANCE_MODE:
+      g_value_set_enum (value, encoder->compliance_mode);
+      break;
+    case ENCODER_H264_PROP_NUM_REF_FRAMES:
+      g_value_set_uint (value, encoder->num_ref_frames);
+      break;
+    case ENCODER_H264_PROP_MBBRC:
+      g_value_set_enum (value, encoder->mbbrc);
+      break;
+    case ENCODER_H264_PROP_TEMPORAL_LEVELS:
+      g_value_set_uint (value, encoder->temporal_levels);
+      break;
+    case ENCODER_H264_PROP_PREDICTION_TYPE:
+      g_value_set_enum (value, encoder->prediction_type);
+      break;
+    case ENCODER_H264_PROP_MAX_QP:
+      g_value_set_uint (value, encoder->max_qp);
+      break;
+    case ENCODER_H264_PROP_QUALITY_FACTOR:
+      g_value_set_uint (value, encoder->quality_factor);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (H264);
+
+static void
+gst_vaapi_encoder_h264_class_init (GstVaapiEncoderH264Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass);
+
+  encoder_class->class_data = &g_class_data;
+  encoder_class->reconfigure = gst_vaapi_encoder_h264_reconfigure;
+  encoder_class->reordering = gst_vaapi_encoder_h264_reordering;
+  encoder_class->encode = gst_vaapi_encoder_h264_encode;
+  encoder_class->flush = gst_vaapi_encoder_h264_flush;
+  encoder_class->get_codec_data = gst_vaapi_encoder_h264_get_codec_data;
+  encoder_class->get_pending_reordered =
+      gst_vaapi_encoder_h264_get_pending_reordered;
+
+  object_class->set_property = gst_vaapi_encoder_h264_set_property;
+  object_class->get_property = gst_vaapi_encoder_h264_get_property;
+  object_class->finalize = gst_vaapi_encoder_h264_finalize;
+
+  /**
+   * GstVaapiEncoderH264:rate-control:
+   *
+   * The desired rate control mode, expressed as a #GstVaapiRateControl.
+   */
+  properties[ENCODER_H264_PROP_RATECONTROL] =
+      g_param_spec_enum ("rate-control",
+      "Rate Control", "Rate control mode",
+      g_class_data.rate_control_get_type (),
+      g_class_data.default_rate_control,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:tune:
+   *
+   * The desired encoder tuning option.
+   */
+  properties[ENCODER_H264_PROP_TUNE] =
+      g_param_spec_enum ("tune",
+      "Encoder Tuning",
+      "Encoder tuning option",
+      g_class_data.encoder_tune_get_type (),
+      g_class_data.default_encoder_tune,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:max-bframes:
+   *
+   * The number of B-frames between I and P.
+   */
+  properties[ENCODER_H264_PROP_MAX_BFRAMES] =
+      g_param_spec_uint ("max-bframes",
+      "Max B-Frames", "Number of B-frames between I and P", 0, 10, 0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:refs:
+   *
+   * The number of reference frames.
+   * If B frame is encoded, it will add 1 reference frame more.
+   */
+  properties[ENCODER_H264_PROP_NUM_REF_FRAMES] =
+      g_param_spec_uint ("refs", "Number of Reference Frames",
+      "Number of reference frames", 1, 8, 1,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:init-qp:
+   *
+   * The initial quantizer value.
+   */
+  properties[ENCODER_H264_PROP_INIT_QP] =
+      g_param_spec_uint ("init-qp",
+      "Initial QP", "Initial quantizer value", 0, 51, 26,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:min-qp:
+   *
+   * The minimum quantizer value.
+   */
+  properties[ENCODER_H264_PROP_MIN_QP] =
+      g_param_spec_uint ("min-qp",
+      "Minimum QP", "Minimum quantizer value", 0, 51, 1,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:max-qp:
+   *
+   * The maximum quantizer value.
+   *
+   * Since: 1.18
+   */
+  properties[ENCODER_H264_PROP_MAX_QP] =
+      g_param_spec_uint ("max-qp",
+      "Maximum QP", "Maximum quantizer value", 0, 51, 51,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:qp-ip:
+   *
+   * The difference of QP between I and P Frame.
+   * This is available only on CQP mode.
+   */
+  properties[ENCODER_H264_PROP_QP_IP] =
+      g_param_spec_int ("qp-ip",
+      "Difference of QP between I and P frame",
+      "Difference of QP between I and P frame (available only on CQP)",
+      -51, 51, 0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:qp-ib:
+   *
+   * The difference of QP between I and B Frame.
+   * This is available only on CQP mode.
+   */
+  properties[ENCODER_H264_PROP_QP_IB] =
+      g_param_spec_int ("qp-ib",
+      "Difference of QP between I and B frame",
+      "Difference of QP between I and B frame (available only on CQP)",
+      -51, 51, 0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:num-slices:
+   *
+   * The number of slices per frame.
+   */
+  properties[ENCODER_H264_PROP_NUM_SLICES] =
+      g_param_spec_uint ("num-slices",
+      "Number of Slices",
+      "Number of slices per frame",
+      1, 200, 1,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:cabac:
+   *
+   * Enable CABAC entropy coding mode for improved compression ratio,
+   * at the expense that the minimum target profile is Main. Default
+   * is CAVLC entropy coding mode.
+   */
+  properties[ENCODER_H264_PROP_CABAC] =
+      g_param_spec_boolean ("cabac",
+      "Enable CABAC",
+      "Enable CABAC entropy coding mode",
+      FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:dct8x8:
+   *
+   * Enable adaptive use of 8x8 transforms in I-frames. This improves
+   * the compression ratio by the minimum target profile is High.
+   * Default is to use 4x4 DCT only.
+   */
+  properties[ENCODER_H264_PROP_DCT8X8] =
+      g_param_spec_boolean ("dct8x8",
+      "Enable 8x8 DCT",
+      "Enable adaptive use of 8x8 transforms in I-frames",
+      FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:mbbrc:
+   *
+   * Macroblock level bitrate control.
+   * This is not compatible with Constant QP rate control.
+   */
+  properties[ENCODER_H264_PROP_MBBRC] =
+      g_param_spec_enum ("mbbrc",
+      "Macroblock level Bitrate Control",
+      "Macroblock level Bitrate Control",
+      GST_VAAPI_TYPE_ENCODER_MBBRC, GST_VAAPI_ENCODER_MBBRC_AUTO,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:temporal-levels:
+   *
+   * Number of temporal levels in the encoded stream.
+   */
+  properties[ENCODER_H264_PROP_TEMPORAL_LEVELS] =
+      g_param_spec_uint ("temporal-levels",
+      "temporal levels",
+      "Number of temporal levels in the encoded stream ",
+      MIN_TEMPORAL_LEVELS, MAX_TEMPORAL_LEVELS, MIN_TEMPORAL_LEVELS,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:prediction-type:
+   *
+   * Select the referece picture selection modes
+   */
+  properties[ENCODER_H264_PROP_PREDICTION_TYPE] =
+      g_param_spec_enum ("prediction-type",
+      "RefPic Selection",
+      "Reference Picture Selection Modes",
+      gst_vaapi_encoder_h264_prediction_type (),
+      GST_VAAPI_ENCODER_H264_PREDICTION_DEFAULT,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:cpb-length:
+   *
+   * The size of the CPB buffer in milliseconds.
+   */
+  properties[ENCODER_H264_PROP_CPB_LENGTH] =
+      g_param_spec_uint ("cpb-length",
+      "CPB Length", "Length of the CPB buffer in milliseconds",
+      1, 10000, DEFAULT_CPB_LENGTH,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:num-views:
+   *
+   * The number of views for MVC encoding .
+   */
+  properties[ENCODER_H264_PROP_NUM_VIEWS] =
+      g_param_spec_uint ("num-views",
+      "Number of Views",
+      "Number of Views for MVC encoding",
+      1, MAX_NUM_VIEWS, 1,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:view-ids:
+   *
+   * The view ids for MVC encoding .
+   */
+  properties[ENCODER_H264_PROP_VIEW_IDS] =
+      gst_param_spec_array ("view-ids",
+      "View IDs", "Set of View Ids used for MVC encoding",
+      g_param_spec_uint ("view-id-value", "View id value",
+          "view id values used for mvc encoding", 0, MAX_VIEW_ID, 0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:aud:
+   *
+   * Use AU (Access Unit) delimeter.
+   */
+  properties[ENCODER_H264_PROP_AUD] =
+      g_param_spec_boolean ("aud", "AU delimiter",
+      "Use AU (Access Unit) delimeter", FALSE,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:Compliance Mode:
+   *
+   * Encode Tuning(Tweaking) with different compliance modes .
+   *
+   *
+   */
+  properties[ENCODER_H264_PROP_COMPLIANCE_MODE] =
+      g_param_spec_enum ("compliance-mode",
+      "Spec Compliance Mode",
+      "Tune Encode quality/performance by relaxing specification"
+      " compliance restrictions",
+      gst_vaapi_encoder_h264_compliance_mode_type (),
+      GST_VAAPI_ENCODER_H264_COMPLIANCE_MODE_STRICT,
+      G_PARAM_READWRITE | G_PARAM_CONSTRUCT | GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH264:quality_factor:
+   *
+   * quality factor used under ICQ/QVBR bitrate control mode.
+   */
+  properties[ENCODER_H264_PROP_QUALITY_FACTOR] =
+      g_param_spec_uint ("quality-factor",
+      "Quality factor for ICQ/QVBR",
+      "quality factor for ICQ/QVBR bitrate control mode"
+      "(low value means higher-quality, higher value means lower-quality)",
+      1, 51, 26,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  g_object_class_install_properties (object_class, ENCODER_H264_N_PROPERTIES,
+      properties);
+
+  gst_type_mark_as_plugin_api (GST_VAAPI_TYPE_ENCODER_MBBRC, 0);
+  gst_type_mark_as_plugin_api (gst_vaapi_encoder_h264_prediction_type (), 0);
+  gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0);
+  gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0);
+  gst_type_mark_as_plugin_api (gst_vaapi_encoder_h264_compliance_mode_type (),
+      0);
+}
+
+/**
+ * gst_vaapi_encoder_h264_new:
+ * @display: a #GstVaapiDisplay
+ *
+ * Creates a new #GstVaapiEncoder for H.264 encoding. Note that the
+ * only supported output stream format is "byte-stream" format.
+ *
+ * Return value: the newly allocated #GstVaapiEncoder object
+ */
+GstVaapiEncoder *
+gst_vaapi_encoder_h264_new (GstVaapiDisplay * display)
+{
+  return g_object_new (GST_TYPE_VAAPI_ENCODER_H264, "display", display, NULL);
+}
+
+/**
+ * gst_vaapi_encoder_h264_set_max_profile:
+ * @encoder: a #GstVaapiEncoderH264
+ * @profile: an H.264 #GstVaapiProfile
+ *
+ * Notifies the @encoder to use coding tools from the supplied
+ * @profile at most.
+ *
+ * This means that if the minimal profile derived to
+ * support the specified coding tools is greater than this @profile,
+ * then an error is returned when the @encoder is configured.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_encoder_h264_set_max_profile (GstVaapiEncoderH264 * encoder,
+    GstVaapiProfile profile)
+{
+  guint8 profile_idc;
+
+  g_return_val_if_fail (encoder != NULL, FALSE);
+  g_return_val_if_fail (profile != GST_VAAPI_PROFILE_UNKNOWN, FALSE);
+
+  if (gst_vaapi_profile_get_codec (profile) != GST_VAAPI_CODEC_H264)
+    return FALSE;
+
+  profile_idc = gst_vaapi_utils_h264_get_profile_idc (profile);
+  if (!profile_idc)
+    return FALSE;
+
+  encoder->max_profile_idc = profile_idc;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_encoder_h264_get_profile_and_level:
+ * @encoder: a #GstVaapiEncoderH264
+ * @out_profile_ptr: return location for the #GstVaapiProfile
+ * @out_level_ptr: return location for the #GstVaapiLevelH264
+ *
+ * Queries the H.264 @encoder for the active profile and level. That
+ * information is only constructed and valid after the encoder is
+ * configured, i.e. after the gst_vaapi_encoder_set_codec_state()
+ * function is called.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_encoder_h264_get_profile_and_level (GstVaapiEncoderH264 * encoder,
+    GstVaapiProfile * out_profile_ptr, GstVaapiLevelH264 * out_level_ptr)
+{
+  g_return_val_if_fail (encoder != NULL, FALSE);
+
+  if (!encoder->profile || !encoder->level)
+    return FALSE;
+
+  if (out_profile_ptr)
+    *out_profile_ptr = encoder->profile;
+  if (out_level_ptr)
+    *out_level_ptr = encoder->level;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_encoder_h264_supports_avc:
+ * @encoder: a #GstVaapiEncoderH264
+ *
+ * Queries the H.264 @encoder if it supports the generation of avC
+ * stream format.
+ *
+ * Returns: %TRUE if @encoder supports avC; %FALSE otherwise
+ **/
+gboolean
+gst_vaapi_encoder_h264_supports_avc (GstVaapiEncoderH264 * encoder)
+{
+  return ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+          (VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE)) ==
+      (VA_ENC_PACKED_HEADER_SEQUENCE | VA_ENC_PACKED_HEADER_PICTURE));
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h264.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h264.h
new file mode 100644 (file)
index 0000000..fc5539f
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *  gstvaapiencoder_h264.h - H.264 encoder
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_H264_H
+#define GST_VAAPI_ENCODER_H264_H
+
+#include <gst/vaapi/gstvaapiencoder.h>
+#include <gst/vaapi/gstvaapiutils_h264.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_ENCODER_H264 \
+    (gst_vaapi_encoder_h264_get_type ())
+#define GST_VAAPI_ENCODER_H264(encoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_H264, GstVaapiEncoderH264))
+#define GST_IS_VAAPI_ENCODER_H264(encoder) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_H264))
+
+typedef struct _GstVaapiEncoderH264 GstVaapiEncoderH264;
+typedef struct _GstVaapiEncoderH264Class GstVaapiEncoderH264Class;
+
+GType
+gst_vaapi_encoder_h264_get_type (void) G_GNUC_CONST;
+
+GstVaapiEncoder *
+gst_vaapi_encoder_h264_new (GstVaapiDisplay * display);
+
+gboolean
+gst_vaapi_encoder_h264_set_max_profile (GstVaapiEncoderH264 * encoder,
+    GstVaapiProfile profile);
+
+gboolean
+gst_vaapi_encoder_h264_get_profile_and_level (GstVaapiEncoderH264 * encoder,
+    GstVaapiProfile * out_profile_ptr, GstVaapiLevelH264 * out_level_ptr);
+
+gboolean
+gst_vaapi_encoder_h264_supports_avc (GstVaapiEncoderH264 * encoder);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderH264, gst_object_unref)
+
+G_END_DECLS
+
+#endif /*GST_VAAPI_ENCODER_H264_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h265.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h265.c
new file mode 100644 (file)
index 0000000..caec85f
--- /dev/null
@@ -0,0 +1,4004 @@
+/*
+ *  gstvaapiencoder_h265.c - H.265 encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <math.h>
+#include <gst/base/gstbitwriter.h>
+#include <gst/codecparsers/gsth265parser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiencoder_priv.h"
+#include "gstvaapiencoder_h265.h"
+#include "gstvaapiutils_h265.h"
+#include "gstvaapiutils_h265_priv.h"
+#include "gstvaapiutils_h26x_priv.h"
+#include "gstvaapicodedbufferproxy_priv.h"
+#include "gstvaapisurface.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/* Supported set of VA rate controls, within this implementation */
+#define SUPPORTED_RATECONTROLS                          \
+  (GST_VAAPI_RATECONTROL_MASK (CQP) |                   \
+   GST_VAAPI_RATECONTROL_MASK (CBR) |                   \
+   GST_VAAPI_RATECONTROL_MASK (VBR) |                   \
+   GST_VAAPI_RATECONTROL_MASK (ICQ) |                   \
+   GST_VAAPI_RATECONTROL_MASK (QVBR))
+
+/* Supported set of tuning options, within this implementation */
+#define SUPPORTED_TUNE_OPTIONS                          \
+  (GST_VAAPI_ENCODER_TUNE_MASK (NONE) |                 \
+   GST_VAAPI_ENCODER_TUNE_MASK (LOW_POWER))
+
+/* Supported set of VA packed headers, within this implementation */
+#define SUPPORTED_PACKED_HEADERS                \
+  (VA_ENC_PACKED_HEADER_SEQUENCE |              \
+   VA_ENC_PACKED_HEADER_PICTURE  |              \
+   VA_ENC_PACKED_HEADER_SLICE)
+
+typedef struct
+{
+  GstVaapiSurfaceProxy *pic;
+  guint poc;
+} GstVaapiEncoderH265Ref;
+
+typedef enum
+{
+  GST_VAAPI_ENC_H265_REORD_NONE = 0,
+  GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES = 1,
+  GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES = 2
+} GstVaapiEncH265ReorderState;
+
+typedef struct _GstVaapiH265RefPool
+{
+  GQueue ref_list;
+  guint max_ref_frames;
+  guint max_reflist0_count;
+  guint max_reflist1_count;
+} GstVaapiH265RefPool;
+
+typedef struct _GstVaapiH265ReorderPool
+{
+  GQueue reorder_frame_list;
+  guint reorder_state;
+  guint frame_index;
+  guint cur_present_index;
+} GstVaapiH265ReorderPool;
+
+/* ------------------------------------------------------------------------- */
+/* --- H.265 Encoder                                                     --- */
+/* ------------------------------------------------------------------------- */
+
+struct _GstVaapiEncoderH265
+{
+  GstVaapiEncoder parent_instance;
+
+  GstVaapiProfile profile;
+  GstVaapiTierH265 tier;
+  GstVaapiLevelH265 level;
+  GstVaapiEntrypoint entrypoint;
+  guint8 profile_idc;
+  GArray *allowed_profiles;
+  guint8 level_idc;
+  guint32 idr_period;
+  guint32 init_qp;
+  guint32 min_qp;
+  guint32 max_qp;
+  guint32 qp_i;
+  guint32 qp_ip;
+  guint32 qp_ib;
+  guint32 num_slices;
+  guint32 num_bframes;
+  guint32 ctu_width;            /* CTU == Coding Tree Unit */
+  guint32 ctu_height;
+  guint32 luma_width;
+  guint32 luma_height;
+  guint32 quality_factor;
+  GstClockTime cts_offset;
+  gboolean config_changed;
+  /* Always need two reference lists for inter frame */
+  gboolean no_p_frame;
+  guint32 num_tile_cols;
+  guint32 num_tile_rows;
+  /* CTUs start address used in stream pack */
+  guint32 *tile_slice_address;
+  /* CTUs in this slice */
+  guint32 *tile_slice_ctu_num;
+  /* map the tile_slice_address to CTU start address in picture,
+     which is used by VA API. */
+  guint32 *tile_slice_address_map;
+
+  /* maximum required size of the decoded picture buffer */
+  guint32 max_dec_pic_buffering;
+  /* maximum allowed number of pictures that can precede any picture in
+   * the CVS in decoding order and follow that picture in output order */
+  guint32 max_num_reorder_pics;
+
+  /* frame, poc */
+  guint32 max_pic_order_cnt;
+  guint32 log2_max_pic_order_cnt;
+  guint32 idr_num;
+  guint num_ref_frames;
+
+  GstBuffer *vps_data;
+  GstBuffer *sps_data;
+  GstBuffer *pps_data;
+
+  guint bitrate_bits;           // bitrate (bits)
+  guint cpb_length;             // length of CPB buffer (ms)
+  guint cpb_length_bits;        // length of CPB buffer (bits)
+  GstVaapiEncoderMbbrc mbbrc;   // macroblock bitrate control
+
+  /* Crop rectangle */
+  guint conformance_window_flag:1;
+  guint32 conf_win_left_offset;
+  guint32 conf_win_right_offset;
+  guint32 conf_win_top_offset;
+  guint32 conf_win_bottom_offset;
+
+  GstVaapiH265RefPool ref_pool;
+  GstVaapiH265ReorderPool reorder_pool;
+  guint first_slice_segment_in_pic_flag:1;
+  guint sps_temporal_mvp_enabled_flag:1;
+  guint sample_adaptive_offset_enabled_flag:1;
+};
+
+static inline gboolean
+_poc_greater_than (guint poc1, guint poc2, guint max_poc)
+{
+  return (((poc1 - poc2) & (max_poc - 1)) < max_poc / 2);
+}
+
+/* Get slice_type value for H.265 specification */
+static guint8
+h265_get_slice_type (GstVaapiPictureType type)
+{
+  switch (type) {
+    case GST_VAAPI_PICTURE_TYPE_I:
+      return GST_H265_I_SLICE;
+    case GST_VAAPI_PICTURE_TYPE_P:
+      return GST_H265_P_SLICE;
+    case GST_VAAPI_PICTURE_TYPE_B:
+      return GST_H265_B_SLICE;
+    default:
+      break;
+  }
+  return -1;
+}
+
+static gboolean
+h265_is_scc (GstVaapiEncoderH265 * encoder)
+{
+  if (encoder->profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN ||
+      encoder->profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10 ||
+      encoder->profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444 ||
+      encoder->profile == GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10)
+    return TRUE;
+
+  return FALSE;
+}
+
+static gboolean
+h265_is_tile_enabled (GstVaapiEncoderH265 * encoder)
+{
+  return encoder->num_tile_cols * encoder->num_tile_rows > 1;
+}
+
+/* Get log2_max_pic_order_cnt value for H.265 specification */
+static guint
+h265_get_log2_max_pic_order_cnt (guint num)
+{
+  guint ret = 0;
+
+  while (num) {
+    ++ret;
+    num >>= 1;
+  }
+  if (ret <= 4)
+    ret = 4;
+  else if (ret > 16)
+    ret = 16;
+  /* must be greater than 4 */
+  return ret;
+}
+
+/* Write the NAL unit header */
+static gboolean
+bs_write_nal_header (GstBitWriter * bs, guint32 nal_unit_type)
+{
+  guint8 nuh_layer_id = 0;
+  guint8 nuh_temporal_id_plus1 = 1;
+
+  WRITE_UINT32 (bs, 0, 1);
+  WRITE_UINT32 (bs, nal_unit_type, 6);
+  WRITE_UINT32 (bs, nuh_layer_id, 6);
+  WRITE_UINT32 (bs, nuh_temporal_id_plus1, 3);
+
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write NAL unit header");
+    return FALSE;
+  }
+}
+
+/* Write the NAL unit trailing bits */
+static gboolean
+bs_write_trailing_bits (GstBitWriter * bs)
+{
+  if (!gst_bit_writer_put_bits_uint32 (bs, 1, 1))
+    goto bs_error;
+  gst_bit_writer_align_bytes_unchecked (bs, 0);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write NAL unit trailing bits");
+    return FALSE;
+  }
+}
+
+/* Write profile_tier_level()  */
+static gboolean
+bs_write_profile_tier_level (GstBitWriter * bs,
+    const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile)
+{
+  guint i;
+
+  /* general_profile_space */
+  WRITE_UINT32 (bs, 0, 2);
+  /* general_tier_flag */
+  WRITE_UINT32 (bs, seq_param->general_tier_flag, 1);
+  /* general_profile_idc */
+  WRITE_UINT32 (bs, seq_param->general_profile_idc, 5);
+
+  /* general_profile_compatibility_flag[0] */
+  WRITE_UINT32 (bs, 0, 1);
+  /* general_profile_compatibility_flag[1] */
+  if (seq_param->general_profile_idc == 1       /* Main profile */
+      /* In A.3.4, NOTE: When general_profile_compatibility_flag[ 3 ] is equal
+         to 1, general_profile_compatibility_flag[ 1 ] and
+         general_profile_compatibility_flag[ 2 ] should also be equal to 1. */
+      || seq_param->general_profile_idc == 3    /* Main Still Picture profile */
+      ) {
+    WRITE_UINT32 (bs, 1, 1);
+  } else {
+    WRITE_UINT32 (bs, 0, 1);
+  }
+  /* general_profile_compatibility_flag[2] */
+  if (
+      /* In A.3.2, NOTE: When general_profile_compatibility_flag[ 1 ] is equal
+         to 1, general_profile_compatibility_flag[ 2 ] should also be equal to
+         1. */
+      seq_param->general_profile_idc == 1       /* Main profile */
+      || seq_param->general_profile_idc == 2    /* Main 10 profile */
+      /* In A.3.4, NOTE: When general_profile_compatibility_flag[ 3 ] is equal
+         to 1, general_profile_compatibility_flag[ 1 ] and
+         general_profile_compatibility_flag[ 2 ] should also be equal to 1. */
+      || seq_param->general_profile_idc == 3    /* Main Still Picture profile */
+      ) {
+    WRITE_UINT32 (bs, 1, 1);
+  } else {
+    WRITE_UINT32 (bs, 0, 1);
+  }
+  /* general_profile_compatibility_flag[3] */
+  if (seq_param->general_profile_idc == 3) {
+    WRITE_UINT32 (bs, 1, 1);
+  } else {
+    WRITE_UINT32 (bs, 0, 1);
+  }
+
+  /* general_profile_compatibility_flag[4] */
+  if (seq_param->general_profile_idc == 4) {    /* format range extensions profiles */
+    WRITE_UINT32 (bs, 1, 1);
+  } else {
+    WRITE_UINT32 (bs, 0, 1);
+  }
+
+  /* general_profile_compatibility_flag[5~8] */
+  WRITE_UINT32 (bs, 0, 4);
+
+  /* general_profile_compatibility_flag[9] */
+  if (seq_param->general_profile_idc == 9) {    /* screen content coding profiles */
+    WRITE_UINT32 (bs, 1, 1);
+  } else {
+    WRITE_UINT32 (bs, 0, 1);
+  }
+
+  /* general_profile_compatibility_flag[10~32] */
+  WRITE_UINT32 (bs, 0, 22);
+
+  /* general_progressive_source_flag */
+  WRITE_UINT32 (bs, 1, 1);
+  /* general_interlaced_source_flag */
+  WRITE_UINT32 (bs, 0, 1);
+  /* general_non_packed_constraint_flag */
+  WRITE_UINT32 (bs, 0, 1);
+  /* general_frame_only_constraint_flag */
+  WRITE_UINT32 (bs, 1, 1);
+
+  /* additional indications specified for general_profile_idc from 4~10 */
+  if (seq_param->general_profile_idc == 4) {
+    /* In A.3.5, Format range extensions profiles.
+       Just support main444, main444-10 and main422-10 profile now, may add
+       more profiles when needed. */
+    switch (profile) {
+      case GST_VAAPI_PROFILE_H265_MAIN_444:
+        /* max_12bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_10bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_8bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_422chroma_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_420chroma_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_monochrome_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* intra_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* one_picture_only_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* lower_bit_rate_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        break;
+      case GST_VAAPI_PROFILE_H265_MAIN_444_10:
+        /* max_12bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_10bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_8bit_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_422chroma_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_420chroma_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_monochrome_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* intra_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* one_picture_only_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* lower_bit_rate_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        break;
+      case GST_VAAPI_PROFILE_H265_MAIN_422_10:
+        /* max_12bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_10bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_8bit_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_422chroma_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_420chroma_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_monochrome_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* intra_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* one_picture_only_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* lower_bit_rate_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        break;
+      case GST_VAAPI_PROFILE_H265_MAIN12:
+        /* max_12bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_10bit_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_8bit_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_422chroma_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_420chroma_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_monochrome_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* intra_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* one_picture_only_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* lower_bit_rate_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        break;
+      default:
+        GST_WARNING ("do not support the profile: %s of range extensions",
+            gst_vaapi_profile_get_va_name (profile));
+        goto bs_error;
+    }
+
+    /* general_reserved_zero_34bits */
+    for (i = 0; i < 34; i++)
+      WRITE_UINT32 (bs, 0, 1);
+  } else if (seq_param->general_profile_idc == 9) {
+    /*  In A.3.7, Screen content coding extensions profiles. */
+    switch (profile) {
+      case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN:
+        /* max_12bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_10bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_8bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_422chroma_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_420chroma_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_monochrome_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* intra_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* one_picture_only_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* lower_bit_rate_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* general_max_14bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        break;
+      case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10:
+        /* max_12bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_10bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_8bit_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_422chroma_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_420chroma_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_monochrome_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* intra_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* one_picture_only_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* lower_bit_rate_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* general_max_14bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        break;
+      case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444:
+        /* max_12bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_10bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_8bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_422chroma_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_420chroma_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_monochrome_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* intra_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* one_picture_only_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* lower_bit_rate_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* general_max_14bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        break;
+      case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10:
+        /* max_12bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_10bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* max_8bit_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_422chroma_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_420chroma_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* max_monochrome_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* intra_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* one_picture_only_constraint_flag */
+        WRITE_UINT32 (bs, 0, 1);
+        /* lower_bit_rate_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        /* general_max_14bit_constraint_flag */
+        WRITE_UINT32 (bs, 1, 1);
+        break;
+      default:
+        GST_WARNING ("do not support the profile: %s of screen"
+            " content coding extensions",
+            gst_vaapi_profile_get_va_name (profile));
+        goto bs_error;
+    }
+
+    /* general_reserved_zero_33bits */
+    for (i = 0; i < 33; i++)
+      WRITE_UINT32 (bs, 0, 1);
+  } else {
+    /* general_reserved_zero_43bits */
+    for (i = 0; i < 43; i++)
+      WRITE_UINT32 (bs, 0, 1);
+  }
+
+  /* general_inbld_flag */
+  WRITE_UINT32 (bs, 0, 1);
+  /* general_level_idc */
+  WRITE_UINT32 (bs, seq_param->general_level_idc, 8);
+
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write Profile Tier Level");
+    return FALSE;
+  }
+}
+
+/* Write an VPS NAL unit */
+static gboolean
+bs_write_vps_data (GstBitWriter * bs, GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture,
+    const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile)
+{
+  guint32 video_parameter_set_id = 0;
+  guint32 vps_max_layers_minus1 = 0;
+  guint32 vps_max_sub_layers_minus1 = 0;
+  guint32 vps_temporal_id_nesting_flag = 1;
+  guint32 vps_sub_layer_ordering_info_present_flag = 0;
+  guint32 vps_max_latency_increase_plus1 = 0;
+  guint32 vps_max_layer_id = 0;
+  guint32 vps_num_layer_sets_minus1 = 0;
+  guint32 vps_timing_info_present_flag = 0;
+  guint32 vps_extension_flag = 0;
+  guint32 vps_base_layer_internal_flag = 1;
+  guint32 vps_base_layer_available_flag = 1;
+
+  /* video_parameter_set_id */
+  WRITE_UINT32 (bs, video_parameter_set_id, 4);
+  /* vps_base_layer_internal_flag */
+  WRITE_UINT32 (bs, vps_base_layer_internal_flag, 1);
+  /* vps_base_layer_available_flag */
+  WRITE_UINT32 (bs, vps_base_layer_available_flag, 1);
+  /* vps_max_layers_minus1 */
+  WRITE_UINT32 (bs, vps_max_layers_minus1, 6);
+  /* vps_max_sub_layers_minus1 */
+  WRITE_UINT32 (bs, vps_max_sub_layers_minus1, 3);
+  /* vps_temporal_id_nesting_flag */
+  WRITE_UINT32 (bs, vps_temporal_id_nesting_flag, 1);
+  /* vps_reserved_0xffff_16bits */
+  WRITE_UINT32 (bs, 0xffff, 16);
+
+  /* profile_tier_level */
+  bs_write_profile_tier_level (bs, seq_param, profile);
+
+  /* vps_sub_layer_ordering_info_present_flag */
+  WRITE_UINT32 (bs, vps_sub_layer_ordering_info_present_flag, 1);
+  /* vps_max_dec_pic_buffering_minus1 */
+  WRITE_UE (bs, encoder->max_dec_pic_buffering - 1);
+  /* vps_max_num_reorder_pics */
+  WRITE_UE (bs, encoder->max_num_reorder_pics);
+  /* vps_max_latency_increase_plus1 */
+  WRITE_UE (bs, vps_max_latency_increase_plus1);
+  /* vps_max_layer_id */
+  WRITE_UINT32 (bs, vps_max_layer_id, 6);
+  /* vps_num_layer_sets_minus1 */
+  WRITE_UE (bs, vps_num_layer_sets_minus1);
+  /* vps_timing_info_present_flag */
+  WRITE_UINT32 (bs, vps_timing_info_present_flag, 1);
+  /* vps_extension_flag */
+  WRITE_UINT32 (bs, vps_extension_flag, 1);
+
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write VPS NAL unit");
+    return FALSE;
+  }
+}
+
+static gboolean
+bs_write_vps (GstBitWriter * bs, GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture,
+    const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile)
+{
+  if (!bs_write_vps_data (bs, encoder, picture, seq_param, profile))
+    return FALSE;
+
+  /* rbsp_trailing_bits */
+  bs_write_trailing_bits (bs);
+
+  return FALSE;
+}
+
+/* Write an SPS NAL unit */
+static gboolean
+bs_write_sps_data (GstBitWriter * bs, GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture,
+    const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile,
+    GstVaapiRateControl rate_control, const VAEncMiscParameterHRD * hrd_params)
+{
+  guint32 video_parameter_set_id = 0;
+  guint32 max_sub_layers_minus1 = 0;
+  guint32 temporal_id_nesting_flag = 1;
+  guint32 separate_colour_plane_flag = 0;
+  guint32 seq_parameter_set_id = 0;
+  guint32 sps_sub_layer_ordering_info_present_flag = 0;
+  guint32 sps_max_latency_increase_plus1 = 0;
+  guint32 num_short_term_ref_pic_sets = 0;
+  guint32 long_term_ref_pics_present_flag = 0;
+  guint32 sps_extension_flag = 0;
+  guint32 nal_hrd_parameters_present_flag = 0;
+  guint maxNumSubLayers = 1, i;
+  guint32 cbr_flag = rate_control == GST_VAAPI_RATECONTROL_CBR ? 1 : 0;
+
+  /* video_parameter_set_id */
+  WRITE_UINT32 (bs, video_parameter_set_id, 4);
+  /* max_sub_layers_minus1 */
+  WRITE_UINT32 (bs, max_sub_layers_minus1, 3);
+  /* temporal_id_nesting_flag */
+  WRITE_UINT32 (bs, temporal_id_nesting_flag, 1);
+
+  /* profile_tier_level */
+  bs_write_profile_tier_level (bs, seq_param, profile);
+
+  /* seq_parameter_set_id */
+  WRITE_UE (bs, seq_parameter_set_id);
+  /* chroma_format_idc  = 1, 4:2:0 */
+  WRITE_UE (bs, seq_param->seq_fields.bits.chroma_format_idc);
+  if (seq_param->seq_fields.bits.chroma_format_idc == 3)
+    /* if( chroma_format_idc == 3 )  separate_colour_plane_flag */
+    WRITE_UINT32 (bs, separate_colour_plane_flag, 1);
+  /* pic_width_in_luma_samples */
+  WRITE_UE (bs, seq_param->pic_width_in_luma_samples);
+  /* pic_height_in_luma_samples */
+  WRITE_UE (bs, seq_param->pic_height_in_luma_samples);
+
+  /* conformance_window_flag */
+  WRITE_UINT32 (bs, encoder->conformance_window_flag, 1);
+  if (encoder->conformance_window_flag) {
+    WRITE_UE (bs, encoder->conf_win_left_offset);
+    WRITE_UE (bs, encoder->conf_win_right_offset);
+    WRITE_UE (bs, encoder->conf_win_top_offset);
+    WRITE_UE (bs, encoder->conf_win_bottom_offset);
+  }
+
+  /* bit_depth_luma_minus8 */
+  WRITE_UE (bs, seq_param->seq_fields.bits.bit_depth_luma_minus8);
+  /* bit_depth_chroma_minus8 */
+  WRITE_UE (bs, seq_param->seq_fields.bits.bit_depth_chroma_minus8);
+  /* log2_max_pic_order_cnt_lsb_minus4  */
+  WRITE_UE (bs, encoder->log2_max_pic_order_cnt - 4);
+
+  /* sps_sub_layer_ordering_info_present_flag */
+  WRITE_UINT32 (bs, sps_sub_layer_ordering_info_present_flag, 1);
+  /* sps_max_dec_pic_buffering_minus1 */
+  WRITE_UE (bs, encoder->max_dec_pic_buffering - 1);
+  /* sps_max_num_reorder_pics */
+  WRITE_UE (bs, encoder->max_num_reorder_pics);
+  /* sps_max_latency_increase_plus1 */
+  WRITE_UE (bs, sps_max_latency_increase_plus1);
+
+  /* log2_min_luma_coding_block_size_minus3 */
+  WRITE_UE (bs, seq_param->log2_min_luma_coding_block_size_minus3);
+  /* log2_diff_max_min_luma_coding_block_size */
+  WRITE_UE (bs, seq_param->log2_diff_max_min_luma_coding_block_size);
+  /* log2_min_transform_block_size_minus2 */
+  WRITE_UE (bs, seq_param->log2_min_transform_block_size_minus2);
+  /* log2_diff_max_min_transform_block_size */
+  WRITE_UE (bs, seq_param->log2_diff_max_min_transform_block_size);
+  /* max_transform_hierarchy_depth_inter */
+  WRITE_UE (bs, seq_param->max_transform_hierarchy_depth_inter);
+  /*max_transform_hierarchy_depth_intra */
+  WRITE_UE (bs, seq_param->max_transform_hierarchy_depth_intra);
+
+  /* scaling_list_enabled_flag */
+  WRITE_UINT32 (bs, seq_param->seq_fields.bits.scaling_list_enabled_flag, 1);
+  /* amp_enabled_flag */
+  WRITE_UINT32 (bs, seq_param->seq_fields.bits.amp_enabled_flag, 1);
+  /* sample_adaptive_offset_enabled_flag */
+  WRITE_UINT32 (bs,
+      seq_param->seq_fields.bits.sample_adaptive_offset_enabled_flag, 1);
+  /* pcm_enabled_flag */
+  WRITE_UINT32 (bs, seq_param->seq_fields.bits.pcm_enabled_flag, 1);
+
+  /* num_short_term_ref_pic_sets  */
+  WRITE_UE (bs, num_short_term_ref_pic_sets);
+
+  /* long_term_ref_pics_present_flag */
+  WRITE_UINT32 (bs, long_term_ref_pics_present_flag, 1);
+
+  /* sps_temporal_mvp_enabled_flag */
+  WRITE_UINT32 (bs, seq_param->seq_fields.bits.sps_temporal_mvp_enabled_flag,
+      1);
+  /* strong_intra_smoothing_enabled_flag */
+  WRITE_UINT32 (bs,
+      seq_param->seq_fields.bits.strong_intra_smoothing_enabled_flag, 1);
+
+  /* vui_parameters_present_flag */
+  WRITE_UINT32 (bs, seq_param->vui_parameters_present_flag, 1);
+
+  /*--------------- Write VUI Parameters--------------- */
+  if (seq_param->vui_parameters_present_flag) {
+    gboolean vui_hrd_parameters_present_flag;
+    /* aspect_ratio_info_present_flag */
+    WRITE_UINT32 (bs,
+        seq_param->vui_fields.bits.aspect_ratio_info_present_flag, 1);
+    if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) {
+      WRITE_UINT32 (bs, seq_param->aspect_ratio_idc, 8);
+      if (seq_param->aspect_ratio_idc == 0xFF) {
+        WRITE_UINT32 (bs, seq_param->sar_width, 16);
+        WRITE_UINT32 (bs, seq_param->sar_height, 16);
+      }
+    }
+    /* overscan_info_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* video_signal_type_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* chroma_loc_info_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* neutral_chroma_indication_flag */
+    WRITE_UINT32 (bs, seq_param->vui_fields.bits.neutral_chroma_indication_flag,
+        1);
+    /* field_seq_flag */
+    WRITE_UINT32 (bs, seq_param->vui_fields.bits.field_seq_flag, 1);
+    /* frame_field_info_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* default_display_window_flag */
+    WRITE_UINT32 (bs, 0, 1);
+
+    /* timing_info_present_flag */
+    WRITE_UINT32 (bs, seq_param->vui_fields.bits.vui_timing_info_present_flag,
+        1);
+    if (seq_param->vui_fields.bits.vui_timing_info_present_flag) {
+      /* vui_num_units_in_tick */
+      WRITE_UINT32 (bs, seq_param->vui_num_units_in_tick, 32);
+      /* vui_time_scale */
+      WRITE_UINT32 (bs, seq_param->vui_time_scale, 32);
+      /* vui_poc_proportional_to_timing_flag */
+      WRITE_UINT32 (bs, 0, 1);
+
+      /* vui_hrd_parameters_present_flag */
+      vui_hrd_parameters_present_flag = seq_param->bits_per_second > 0;
+      WRITE_UINT32 (bs, vui_hrd_parameters_present_flag, 1);
+
+      if (vui_hrd_parameters_present_flag) {
+        nal_hrd_parameters_present_flag = 1;
+        /* nal_hrd_parameters_present_flag */
+        WRITE_UINT32 (bs, nal_hrd_parameters_present_flag, 1);
+        /* vcl_hrd_parameters_present_flag */
+        WRITE_UINT32 (bs, 0, 1);
+
+        if (nal_hrd_parameters_present_flag) {
+          /* sub_pic_hrd_params_present_flag */
+          WRITE_UINT32 (bs, 0, 1);
+          /* bit_rate_scale */
+          WRITE_UINT32 (bs, SX_BITRATE - 6, 4);
+          /* cpb_size_scale */
+          WRITE_UINT32 (bs, SX_CPB_SIZE - 4, 4);
+          /* initial_cpb_removal_delay_length_minus1 */
+          WRITE_UINT32 (bs, 23, 5);
+          /* au_cpb_removal_delay_length_minus1 */
+          WRITE_UINT32 (bs, 23, 5);
+          /* dpb_output_delay_length_minus1 */
+          WRITE_UINT32 (bs, 23, 5);
+
+          for (i = 0; i < maxNumSubLayers; i++) {
+            /* fixed_pic_rate_general_flag */
+            WRITE_UINT32 (bs, 0, 1);
+            /* fixed_pic_rate_within_cvs_flag */
+            WRITE_UINT32 (bs, 0, 1);
+            /* low_delay_hrd_flag */
+            WRITE_UINT32 (bs, 1, 1);
+            /* bit_rate_value_minus1 */
+            WRITE_UE (bs, (seq_param->bits_per_second >> SX_BITRATE) - 1);
+            /* cpb_size_value_minus1 */
+            WRITE_UE (bs, (hrd_params->buffer_size >> SX_CPB_SIZE) - 1);
+            /* cbr_flag */
+            WRITE_UINT32 (bs, cbr_flag, 1);
+          }
+        }
+      }
+    }
+    /* bitstream_restriction_flag */
+    WRITE_UINT32 (bs, seq_param->vui_fields.bits.bitstream_restriction_flag, 1);
+  }
+
+  if (h265_is_scc (encoder)) {
+    /* sps_extension_flag */
+    WRITE_UINT32 (bs, 1, 1);
+    /* sps_range_extension_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* sps_multilayer_extension_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* sps_3d_extension_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* sps_scc_extension_flag */
+    WRITE_UINT32 (bs, 1, 1);
+    /* sps_extension_4bits */
+    WRITE_UINT32 (bs, 0, 4);
+
+    /* sps_scc_extension() */
+    /* sps_curr_pic_ref_enabled_flag */
+    WRITE_UINT32 (bs, 1, 1);
+    /* palette_mode_enabled_flag */
+    WRITE_UINT32 (bs, 1, 1);
+    /* palette_max_size */
+    WRITE_UE (bs, 64);
+    /* delta_palette_max_predictor_size */
+    WRITE_UE (bs, 32);
+    /* sps_palette_predictor_initializers_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* motion_vector_resolution_control_idc */
+    WRITE_UINT32 (bs, 0, 2);
+    /* intra_boundary_filtering_disabled_flag */
+    WRITE_UINT32 (bs, 0, 1);
+  } else {
+    /* sps_extension_flag */
+    WRITE_UINT32 (bs, sps_extension_flag, 1);
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write SPS NAL unit");
+    return FALSE;
+  }
+}
+
+static gboolean
+bs_write_sps (GstBitWriter * bs, GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture,
+    const VAEncSequenceParameterBufferHEVC * seq_param, GstVaapiProfile profile,
+    GstVaapiRateControl rate_control, const VAEncMiscParameterHRD * hrd_params)
+{
+  if (!bs_write_sps_data (bs, encoder, picture, seq_param, profile,
+          rate_control, hrd_params))
+    return FALSE;
+
+  /* rbsp_trailing_bits */
+  bs_write_trailing_bits (bs);
+
+  return FALSE;
+}
+
+/* Write a PPS NAL unit */
+static gboolean
+bs_write_pps (GstBitWriter * bs, gboolean is_scc,
+    const VAEncPictureParameterBufferHEVC * pic_param)
+{
+  guint32 pic_parameter_set_id = 0;
+  guint32 seq_parameter_set_id = 0;
+  guint32 output_flag_present_flag = 0;
+  guint32 num_extra_slice_header_bits = 0;
+  guint32 cabac_init_present_flag = 0;
+  guint32 pps_slice_chroma_qp_offsets_present_flag = 0;
+  guint32 deblocking_filter_control_present_flag = 0;
+  guint32 lists_modification_present_flag = 0;
+  guint32 slice_segment_header_extension_present_flag = 0;
+  guint32 pps_extension_flag = 0;
+
+  /* pic_parameter_set_id */
+  WRITE_UE (bs, pic_parameter_set_id);
+  /* seq_parameter_set_id */
+  WRITE_UE (bs, seq_parameter_set_id);
+  /* dependent_slice_segments_enabled_flag */
+  WRITE_UINT32 (bs,
+      pic_param->pic_fields.bits.dependent_slice_segments_enabled_flag, 1);
+  /* output_flag_present_flag */
+  WRITE_UINT32 (bs, output_flag_present_flag, 1);
+  /* num_extra_slice_header_bits */
+  WRITE_UINT32 (bs, num_extra_slice_header_bits, 3);
+  /* sign_data_hiding_enabled_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.sign_data_hiding_enabled_flag,
+      1);
+  /* cabac_init_present_flag */
+  WRITE_UINT32 (bs, cabac_init_present_flag, 1);
+  /* num_ref_idx_l0_default_active_minus1 */
+  WRITE_UE (bs, pic_param->num_ref_idx_l0_default_active_minus1);
+  /* num_ref_idx_l1_default_active_minus1 */
+  WRITE_UE (bs, pic_param->num_ref_idx_l1_default_active_minus1);
+  /* pic_init_qp_minus26 */
+  WRITE_SE (bs, pic_param->pic_init_qp - 26);
+  /* constrained_intra_pred_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.constrained_intra_pred_flag, 1);
+  /* transform_skip_enabled_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.transform_skip_enabled_flag, 1);
+  /* cu_qp_delta_enabled_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.cu_qp_delta_enabled_flag, 1);
+  /* diff_cu_qp_delta_depth */
+  if (pic_param->pic_fields.bits.cu_qp_delta_enabled_flag)
+    WRITE_UE (bs, pic_param->diff_cu_qp_delta_depth);
+
+  /* pps_cb_qp_offset */
+  WRITE_SE (bs, pic_param->pps_cb_qp_offset);
+  /* pps_cr_qp_offset */
+  WRITE_SE (bs, pic_param->pps_cr_qp_offset);
+  /* pps_slice_chroma_qp_offsets_present_flag */
+  WRITE_UINT32 (bs, pps_slice_chroma_qp_offsets_present_flag, 1);
+  /* weighted_pred_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_pred_flag, 1);
+  /* weighted_bipred_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.weighted_bipred_flag, 1);
+  /* transquant_bypass_enabled_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.transquant_bypass_enabled_flag,
+      1);
+  /* tiles_enabled_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.tiles_enabled_flag, 1);
+  /* entropy_coding_sync_enabled_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.entropy_coding_sync_enabled_flag,
+      1);
+
+  /* tiles info */
+  if (pic_param->pic_fields.bits.tiles_enabled_flag) {
+    WRITE_UE (bs, pic_param->num_tile_columns_minus1);
+    WRITE_UE (bs, pic_param->num_tile_rows_minus1);
+    /* uniform_spacing_flag is 1 now */
+    WRITE_UINT32 (bs, 1, 1);
+    /* if (!uniform_spacing_flag) {
+       for (i = 0; i < num_tile_columns_minus1; i++)
+       column_width_minus1[i]
+       ue (v)
+       for (i = 0; i < num_tile_rows_minus1; i++)
+       row_height_minus1[i]
+       ue (v)
+       } */
+    WRITE_UINT32 (bs,
+        pic_param->pic_fields.bits.loop_filter_across_tiles_enabled_flag, 1);
+  }
+
+  /* pps_loop_filter_across_slices_enabled_flag */
+  WRITE_UINT32 (bs,
+      pic_param->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag, 1);
+  /* deblocking_filter_control_present_flag */
+  WRITE_UINT32 (bs, deblocking_filter_control_present_flag, 1);
+  /* pps_scaling_list_data_present_flag */
+  WRITE_UINT32 (bs, pic_param->pic_fields.bits.scaling_list_data_present_flag,
+      1);
+  /* lists_modification_present_flag */
+  WRITE_UINT32 (bs, lists_modification_present_flag, 1);
+  /* log2_parallel_merge_level_minus2 */
+  WRITE_UE (bs, pic_param->log2_parallel_merge_level_minus2);
+  /* slice_segment_header_extension_present_flag */
+  WRITE_UINT32 (bs, slice_segment_header_extension_present_flag, 1);
+
+  if (is_scc) {
+#if VA_CHECK_VERSION(1,8,0)
+    /* pps_extension_flag */
+    WRITE_UINT32 (bs, 1, 1);
+    /* pps_range_extension_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* pps_multilayer_extension_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* pps_3d_extension_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* pps_scc_extension_flag */
+    WRITE_UINT32 (bs, 1, 1);
+    /* pps_extension_4bits */
+    WRITE_UINT32 (bs, 0, 4);
+
+    /* pps_scc_extension() */
+    /* pps_curr_pic_ref_enabled_flag */
+    WRITE_UINT32 (bs,
+        pic_param->scc_fields.bits.pps_curr_pic_ref_enabled_flag, 1);
+    /* residual_adaptive_colour_transform_enabled_flag */
+    WRITE_UINT32 (bs, 0, 1);
+    /* pps_palette_predictor_initializers_present_flag */
+    WRITE_UINT32 (bs, 0, 1);
+#else
+    /* SCC profile should not be selected. */
+    g_assert_not_reached ();
+    return FALSE;
+#endif
+  } else {
+    /* pps_extension_flag */
+    WRITE_UINT32 (bs, pps_extension_flag, 1);
+  }
+
+  /* rbsp_trailing_bits */
+  bs_write_trailing_bits (bs);
+
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write PPS NAL unit");
+    return FALSE;
+  }
+}
+
+/* Write a Slice NAL unit */
+static gboolean
+bs_write_slice (GstBitWriter * bs,
+    const VAEncSliceParameterBufferHEVC * slice_param,
+    GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture,
+    guint8 nal_unit_type)
+{
+  const VAEncPictureParameterBufferHEVC *const pic_param = picture->param;
+
+  guint8 no_output_of_prior_pics_flag = 0;
+  guint8 dependent_slice_segment_flag = 0;
+  guint8 short_term_ref_pic_set_sps_flag = 0;
+  guint8 slice_deblocking_filter_disabled_flag = 0;
+  guint8 num_ref_idx_active_override_flag =
+      slice_param->slice_fields.bits.num_ref_idx_active_override_flag;
+
+  if (h265_is_scc (encoder)) {
+    /* If scc, need to add the current picture itself. */
+    num_ref_idx_active_override_flag = 1;
+  }
+
+  /* first_slice_segment_in_pic_flag */
+  WRITE_UINT32 (bs, encoder->first_slice_segment_in_pic_flag, 1);
+
+  /* FIXME: For all IRAP pics */
+  /* no_output_of_prior_pics_flag */
+  if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
+    WRITE_UINT32 (bs, no_output_of_prior_pics_flag, 1);
+
+  /* slice_pic_parameter_set_id */
+  WRITE_UE (bs, slice_param->slice_pic_parameter_set_id);
+
+  /* slice_segment_address , bits_size = Ceil(Log2(PicSizeInCtbsY)) */
+  if (!encoder->first_slice_segment_in_pic_flag) {
+    guint pic_size_ctb = encoder->ctu_width * encoder->ctu_height;
+    guint bits_size = (guint) ceil ((log2 (pic_size_ctb)));
+    WRITE_UINT32 (bs, slice_param->slice_segment_address, bits_size);
+  }
+
+  if (!dependent_slice_segment_flag) {
+    /* slice_type */
+    WRITE_UE (bs, slice_param->slice_type);
+
+    if (!pic_param->pic_fields.bits.idr_pic_flag) {
+      /* slice_pic_order_cnt_lsb */
+      WRITE_UINT32 (bs, picture->poc, encoder->log2_max_pic_order_cnt);
+      /* short_term_ref_pic_set_sps_flag */
+      WRITE_UINT32 (bs, short_term_ref_pic_set_sps_flag, 1);
+
+    /*---------- Write short_term_ref_pic_set(0) ----------- */
+      {
+        guint num_positive_pics = 0, num_negative_pics = 0;
+        guint delta_poc_s0_minus1 = 0, delta_poc_s1_minus1 = 0;
+        guint used_by_curr_pic_s0_flag = 0, used_by_curr_pic_s1_flag = 0;
+        guint reflist_0_count = 0, reflist_1_count = 0;
+        gint i;
+
+        /* Get count of ref_pic_list */
+        if (picture->type == GST_VAAPI_PICTURE_TYPE_P
+            || picture->type == GST_VAAPI_PICTURE_TYPE_B) {
+          for (i = 0; i < G_N_ELEMENTS (slice_param->ref_pic_list0); ++i) {
+            if (slice_param->ref_pic_list0[i].picture_id == VA_INVALID_SURFACE)
+              break;
+          }
+          reflist_0_count = i;
+
+          if (picture->type == GST_VAAPI_PICTURE_TYPE_B) {
+            for (i = 0; i < G_N_ELEMENTS (slice_param->ref_pic_list1); ++i) {
+              if (slice_param->ref_pic_list1[i].picture_id ==
+                  VA_INVALID_SURFACE)
+                break;
+            }
+            reflist_1_count = i;
+          }
+        }
+
+        if (picture->type == GST_VAAPI_PICTURE_TYPE_P) {
+          delta_poc_s0_minus1 =
+              picture->poc - slice_param->ref_pic_list0[0].pic_order_cnt - 1;
+          used_by_curr_pic_s0_flag = 1;
+          delta_poc_s1_minus1 = 0;
+          used_by_curr_pic_s1_flag = 0;
+        }
+        if (picture->type == GST_VAAPI_PICTURE_TYPE_B) {
+          delta_poc_s0_minus1 =
+              picture->poc - slice_param->ref_pic_list0[0].pic_order_cnt - 1;
+          used_by_curr_pic_s0_flag = 1;
+          delta_poc_s1_minus1 =
+              slice_param->ref_pic_list1[0].pic_order_cnt - picture->poc - 1;
+          used_by_curr_pic_s1_flag = 1;
+        }
+
+        num_negative_pics = reflist_0_count;
+        num_positive_pics = reflist_1_count;
+
+        /* num_negative_pics */
+        WRITE_UE (bs, num_negative_pics);
+        /* num_positive_pics */
+        WRITE_UE (bs, num_positive_pics);
+
+        for (i = 0; i < num_negative_pics; i++) {
+          /* delta_poc_s0_minus1 */
+          if (i == 0) {
+            WRITE_UE (bs, delta_poc_s0_minus1);
+          } else {
+            WRITE_UE (bs,
+                slice_param->ref_pic_list0[i - 1].pic_order_cnt -
+                slice_param->ref_pic_list0[i].pic_order_cnt - 1);
+          }
+          /* used_by_curr_pic_s0_flag */
+          WRITE_UINT32 (bs, used_by_curr_pic_s0_flag, 1);
+        }
+        for (i = 0; i < num_positive_pics; i++) {
+          /* delta_poc_s1_minus1 */
+          if (i == 0) {
+            WRITE_UE (bs, delta_poc_s1_minus1);
+          } else {
+            WRITE_UE (bs,
+                slice_param->ref_pic_list1[i - 1].pic_order_cnt -
+                slice_param->ref_pic_list1[i].pic_order_cnt - 1);
+          }
+          /* used_by_curr_pic_s1_flag */
+          WRITE_UINT32 (bs, used_by_curr_pic_s1_flag, 1);
+        }
+      }
+
+      /* slice_temporal_mvp_enabled_flag */
+      if (encoder->sps_temporal_mvp_enabled_flag)
+        WRITE_UINT32 (bs,
+            slice_param->slice_fields.bits.slice_temporal_mvp_enabled_flag, 1);
+    }
+
+    if (encoder->sample_adaptive_offset_enabled_flag) {
+      WRITE_UINT32 (bs, slice_param->slice_fields.bits.slice_sao_luma_flag, 1);
+      WRITE_UINT32 (bs, slice_param->slice_fields.bits.slice_sao_chroma_flag,
+          1);
+    }
+
+    if (slice_param->slice_type == GST_H265_P_SLICE ||
+        slice_param->slice_type == GST_H265_B_SLICE) {
+      /* num_ref_idx_active_override_flag */
+      WRITE_UINT32 (bs, num_ref_idx_active_override_flag, 1);
+      if (num_ref_idx_active_override_flag) {
+        if (h265_is_scc (encoder)) {
+          if (picture->type == GST_VAAPI_PICTURE_TYPE_I) {
+            g_assert (slice_param->num_ref_idx_l0_active_minus1 == 0);
+            /* Let num_ref_idx_l0_active_minus1 = 0 and
+               NumRpsCurrTempList0 = 1 to include current picture itself */
+            WRITE_UE (bs, 0);
+          } else {
+            /* For scc, need to add 1 for current picture itself when
+               calculating NumRpsCurrTempList0. */
+            WRITE_UE (bs, slice_param->num_ref_idx_l0_active_minus1 + 1);
+          }
+        } else {
+          WRITE_UE (bs, slice_param->num_ref_idx_l0_active_minus1);
+        }
+        if (slice_param->slice_type == GST_H265_B_SLICE)
+          WRITE_UE (bs, slice_param->num_ref_idx_l1_active_minus1);
+      }
+
+      /* mvd_l1_zero_flag */
+      if (slice_param->slice_type == GST_H265_B_SLICE)
+        WRITE_UINT32 (bs, slice_param->slice_fields.bits.mvd_l1_zero_flag, 1);
+
+      /* cabac_init_present_flag == FALSE */
+      /* cabac_init_flag  = FALSE */
+
+      /* collocated_from_l0_flag */
+      if (slice_param->slice_fields.bits.slice_temporal_mvp_enabled_flag) {
+        if (slice_param->slice_type == GST_H265_B_SLICE)
+          WRITE_UINT32 (bs,
+              slice_param->slice_fields.bits.collocated_from_l0_flag, 1);
+      }
+      /* five_minus_max_num_merge_cand */
+      WRITE_UE (bs, 5 - slice_param->max_num_merge_cand);
+    }
+
+    /* slice_qp_delta */
+    WRITE_SE (bs, slice_param->slice_qp_delta);
+    if (pic_param->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag &&
+        (slice_param->slice_fields.bits.slice_sao_luma_flag
+            || slice_param->slice_fields.bits.slice_sao_chroma_flag
+            || !slice_deblocking_filter_disabled_flag))
+      WRITE_UINT32 (bs,
+          slice_param->slice_fields.bits.
+          slice_loop_filter_across_slices_enabled_flag, 1);
+  }
+
+  if (pic_param->pic_fields.bits.tiles_enabled_flag
+      || pic_param->pic_fields.bits.entropy_coding_sync_enabled_flag) {
+    /* output a num_entry_point_offsets, which should be 0 here */
+    WRITE_UE (bs, 0);
+  }
+
+  /* byte_alignment() */
+  {
+    /* alignment_bit_equal_to_one */
+    WRITE_UINT32 (bs, 1, 1);
+    while (GST_BIT_WRITER_BIT_SIZE (bs) % 8 != 0) {
+      /* alignment_bit_equal_to_zero */
+      WRITE_UINT32 (bs, 0, 1);
+    }
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write Slice NAL unit");
+    return FALSE;
+  }
+}
+
+static inline void
+_check_vps_sps_pps_status (GstVaapiEncoderH265 * encoder,
+    const guint8 * nal, guint32 size)
+{
+  guint8 nal_type;
+  G_GNUC_UNUSED gsize ret;      /* FIXME */
+  g_assert (size);
+
+  if (encoder->vps_data && encoder->sps_data && encoder->pps_data)
+    return;
+
+  nal_type = (nal[0] & 0x7E) >> 1;
+  switch (nal_type) {
+    case GST_H265_NAL_VPS:
+      encoder->vps_data = gst_buffer_new_allocate (NULL, size, NULL);
+      ret = gst_buffer_fill (encoder->vps_data, 0, nal, size);
+      g_assert (ret == size);
+      break;
+    case GST_H265_NAL_SPS:
+      encoder->sps_data = gst_buffer_new_allocate (NULL, size, NULL);
+      ret = gst_buffer_fill (encoder->sps_data, 0, nal, size);
+      g_assert (ret == size);
+      break;
+    case GST_H265_NAL_PPS:
+      encoder->pps_data = gst_buffer_new_allocate (NULL, size, NULL);
+      ret = gst_buffer_fill (encoder->pps_data, 0, nal, size);
+      g_assert (ret == size);
+      break;
+    default:
+      break;
+  }
+}
+
+static gboolean
+is_profile_allowed (GstVaapiEncoderH265 * encoder, GstVaapiProfile profile)
+{
+  guint i;
+
+  if (encoder->allowed_profiles == NULL)
+    return TRUE;
+
+  for (i = 0; i < encoder->allowed_profiles->len; i++)
+    if (profile ==
+        g_array_index (encoder->allowed_profiles, GstVaapiProfile, i))
+      return TRUE;
+
+  return FALSE;
+}
+
+/* Derives the profile from the active coding tools. */
+static gboolean
+ensure_profile (GstVaapiEncoderH265 * encoder)
+{
+  GstVaapiProfile profile;
+  const GstVideoFormat format =
+      GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder));
+  guint depth, chrome;
+  GstVaapiProfile profile_candidates[6];
+  guint num, i;
+
+  g_assert (GST_VIDEO_FORMAT_INFO_IS_YUV (gst_video_format_get_info (format)));
+  depth = GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info (format), 0);
+  chrome = gst_vaapi_utils_h265_get_chroma_format_idc
+      (gst_vaapi_video_format_get_chroma_type (format));
+
+  num = 0;
+
+  if (chrome == 3) {
+    /* 4:4:4 */
+    if (depth == 8)
+      profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN_444;
+    if (depth <= 10)
+      profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN_444_10;
+#if VA_CHECK_VERSION(1,8,0)
+    /* Consider SCREEN_EXTENDED_MAIN_444 and SCREEN_EXTENDED_MAIN_444_10 */
+    if (depth == 8)
+      profile_candidates[num++] =
+          GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444;
+    if (depth <= 10)
+      profile_candidates[num++] =
+          GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10;
+#endif
+  } else if (chrome == 2) {
+    /* 4:2:2 */
+    profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN_422_10;
+  } else if (chrome == 1 || chrome == 0) {
+    /* 4:2:0 or 4:0:0 */
+    if (depth == 8)
+      profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN;
+    if (depth <= 10)
+      profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN10;
+    if (depth <= 12)
+      profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN12;
+    /* Always add STILL_PICTURE as a candidate for Main and Main10. */
+    if (depth <= 10)
+      profile_candidates[num++] = GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE;
+#if VA_CHECK_VERSION(1,8,0)
+    /* Consider SCREEN_EXTENDED_MAIN and SCREEN_EXTENDED_MAIN_10 */
+    if (depth == 8)
+      profile_candidates[num++] = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN;
+    if (depth <= 10)
+      profile_candidates[num++] =
+          GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10;
+#endif
+  }
+
+  if (num == 0) {
+    GST_ERROR ("Fail to find a profile for format %s.",
+        gst_video_format_to_string (format));
+    return FALSE;
+  }
+
+  profile = GST_VAAPI_PROFILE_UNKNOWN;
+  for (i = 0; i < num; i++) {
+    if (!is_profile_allowed (encoder, profile_candidates[i]))
+      continue;
+    /* If we can get valid entrypoint, hw must support this profile. */
+    if (gst_vaapi_encoder_get_entrypoint (GST_VAAPI_ENCODER_CAST (encoder),
+            profile_candidates[i]) == GST_VAAPI_ENTRYPOINT_INVALID)
+      continue;
+
+    profile = profile_candidates[i];
+    break;
+  }
+
+  if (profile == GST_VAAPI_PROFILE_UNKNOWN) {
+    GST_ERROR ("Fail to find a supported profile %sfor format %s.",
+        GST_VAAPI_ENCODER_TUNE (encoder) == GST_VAAPI_ENCODER_TUNE_LOW_POWER ?
+        "in low power mode " : "", gst_video_format_to_string (format));
+    return FALSE;
+  }
+
+  encoder->profile = profile;
+  encoder->profile_idc = gst_vaapi_utils_h265_get_profile_idc (profile);
+  return TRUE;
+}
+
+/* Derives the level and tier from the currently set limits */
+static gboolean
+ensure_tier_level (GstVaapiEncoderH265 * encoder)
+{
+  guint bitrate = GST_VAAPI_ENCODER_CAST (encoder)->bitrate;
+  guint i, num_limits, PicSizeInSamplesY;
+  guint LumaSr;
+  const GstVaapiH265LevelLimits *limits_table;
+  const GstVaapiH265LevelLimits *limits;
+
+  PicSizeInSamplesY = encoder->luma_width * encoder->luma_height;
+  LumaSr =
+      gst_util_uint64_scale (PicSizeInSamplesY,
+      GST_VAAPI_ENCODER_FPS_N (encoder), GST_VAAPI_ENCODER_FPS_D (encoder));
+
+  limits_table = gst_vaapi_utils_h265_get_level_limits_table (&num_limits);
+  for (i = 0; i < num_limits; i++) {
+    limits = &limits_table[i];
+    /* Choose level by luma picture size and luma sample rate */
+    if (PicSizeInSamplesY <= limits->MaxLumaPs && LumaSr <= limits->MaxLumaSr)
+      break;
+  }
+
+  if (i == num_limits)
+    goto error_unsupported_level;
+
+  /* may need to promote the level by tile setting */
+  if (h265_is_tile_enabled (encoder)) {
+    for (; i < num_limits; i++) {
+      limits = &limits_table[i];
+      if (encoder->num_tile_cols <= limits->MaxTileColumns &&
+          encoder->num_tile_rows <= limits->MaxTileRows)
+        break;
+    }
+
+    if (i == num_limits)
+      goto error_promote_level;
+  }
+
+  if (bitrate <= limits_table[i].MaxBRTierMain) {
+    encoder->tier = GST_VAAPI_TIER_H265_MAIN;
+  } else {
+    encoder->tier = GST_VAAPI_TIER_H265_HIGH;
+    if (bitrate > limits_table[i].MaxBRTierHigh) {
+      GST_INFO ("The bitrate of the stream is %d kbps, larger than"
+          " %s profile %s level %s tier's max bit rate %d kbps",
+          bitrate,
+          gst_vaapi_utils_h265_get_profile_string (encoder->profile),
+          gst_vaapi_utils_h265_get_level_string (limits_table[i].level),
+          gst_vaapi_utils_h265_get_tier_string (GST_VAAPI_TIER_H265_HIGH),
+          limits_table[i].MaxBRTierHigh);
+    }
+  }
+
+  encoder->level = limits_table[i].level;
+  encoder->level_idc = limits_table[i].level_idc;
+  return TRUE;
+
+  /* ERRORS */
+error_promote_level:
+  {
+    GST_ERROR ("failed to promote level for num-tile-cols is %d,"
+        " num-tile-rows %d", encoder->num_tile_cols, encoder->num_tile_rows);
+    return FALSE;
+  }
+error_unsupported_level:
+  {
+    GST_ERROR ("failed to find a suitable level matching codec config");
+    return FALSE;
+  }
+}
+
+/* Handle new GOP starts */
+static void
+reset_gop_start (GstVaapiEncoderH265 * encoder)
+{
+  GstVaapiH265ReorderPool *const reorder_pool = &encoder->reorder_pool;
+
+  reorder_pool->frame_index = 1;
+  reorder_pool->cur_present_index = 0;
+  ++encoder->idr_num;
+}
+
+/* Marks the supplied picture as a B-frame */
+static void
+set_b_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH265 * encoder)
+{
+  g_assert (pic && encoder);
+  g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
+  pic->type = GST_VAAPI_PICTURE_TYPE_B;
+}
+
+/* Marks the supplied picture as a P-frame */
+static void
+set_p_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH265 * encoder)
+{
+  g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
+  pic->type = GST_VAAPI_PICTURE_TYPE_P;
+}
+
+/* Marks the supplied picture as an I-frame */
+static void
+set_i_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH265 * encoder)
+{
+  g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
+  pic->type = GST_VAAPI_PICTURE_TYPE_I;
+
+  g_assert (pic->frame);
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame);
+}
+
+/* Marks the supplied picture as an IDR frame */
+static void
+set_idr_frame (GstVaapiEncPicture * pic, GstVaapiEncoderH265 * encoder)
+{
+  g_return_if_fail (pic->type == GST_VAAPI_PICTURE_TYPE_NONE);
+  pic->type = GST_VAAPI_PICTURE_TYPE_I;
+  pic->poc = 0;
+  GST_VAAPI_ENC_PICTURE_FLAG_SET (pic, GST_VAAPI_ENC_PICTURE_FLAG_IDR);
+
+  g_assert (pic->frame);
+  GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (pic->frame);
+}
+
+/* Marks the supplied picture a a key-frame */
+static void
+set_key_frame (GstVaapiEncPicture * picture,
+    GstVaapiEncoderH265 * encoder, gboolean is_idr)
+{
+  if (is_idr) {
+    reset_gop_start (encoder);
+    set_idr_frame (picture, encoder);
+  } else
+    set_i_frame (picture, encoder);
+}
+
+/* Fills in VA HRD parameters */
+static void
+fill_hrd_params (GstVaapiEncoderH265 * encoder, VAEncMiscParameterHRD * hrd)
+{
+  if (encoder->bitrate_bits > 0) {
+    hrd->buffer_size = encoder->cpb_length_bits;
+    hrd->initial_buffer_fullness = hrd->buffer_size / 2;
+  } else {
+    hrd->buffer_size = 0;
+    hrd->initial_buffer_fullness = 0;
+  }
+}
+
+/* Adds the supplied video parameter set header (VPS) to the list of packed
+   headers to pass down as-is to the encoder */
+static gboolean
+add_packed_vps_header (GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence)
+{
+  GstVaapiEncPackedHeader *packed_vps;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_vps_param = { 0 };
+  const VAEncSequenceParameterBufferHEVC *const seq_param = sequence->param;
+  GstVaapiProfile profile = encoder->profile;
+
+  guint32 data_bit_size;
+  guint8 *data;
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+  bs_write_nal_header (&bs, GST_H265_NAL_VPS);
+
+  bs_write_vps (&bs, encoder, picture, seq_param, profile);
+
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_vps_param.type = VAEncPackedHeaderSequence;
+  packed_vps_param.bit_length = data_bit_size;
+  packed_vps_param.has_emulation_bytes = 0;
+
+  packed_vps = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_vps_param, sizeof (packed_vps_param),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_vps);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_vps);
+  gst_vaapi_codec_object_replace (&packed_vps, NULL);
+
+  /* store vps data */
+  _check_vps_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4);
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write VPS NAL unit");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+/* Adds the supplied sequence header (SPS) to the list of packed
+   headers to pass down as-is to the encoder */
+static gboolean
+add_packed_sequence_header (GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  GstVaapiEncPackedHeader *packed_seq;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_seq_param = { 0 };
+  const VAEncSequenceParameterBufferHEVC *const seq_param = sequence->param;
+  GstVaapiProfile profile = encoder->profile;
+
+  VAEncMiscParameterHRD hrd_params;
+  guint32 data_bit_size;
+  guint8 *data;
+
+  fill_hrd_params (encoder, &hrd_params);
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+  bs_write_nal_header (&bs, GST_H265_NAL_SPS);
+
+  bs_write_sps (&bs, encoder, picture, seq_param, profile,
+      base_encoder->rate_control, &hrd_params);
+
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_seq_param.type = VAEncPackedHeaderSequence;
+  packed_seq_param.bit_length = data_bit_size;
+  packed_seq_param.has_emulation_bytes = 0;
+
+  packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_seq_param, sizeof (packed_seq_param),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_seq);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_seq);
+  gst_vaapi_codec_object_replace (&packed_seq, NULL);
+
+  /* store sps data */
+  _check_vps_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4);
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write SPS NAL unit");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+/* Adds the supplied picture header (PPS) to the list of packed
+   headers to pass down as-is to the encoder */
+static gboolean
+add_packed_picture_header (GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture)
+{
+  GstVaapiEncPackedHeader *packed_pic;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_pic_param = { 0 };
+  const VAEncPictureParameterBufferHEVC *const pic_param = picture->param;
+  guint32 data_bit_size;
+  guint8 *data;
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+  bs_write_nal_header (&bs, GST_H265_NAL_PPS);
+  bs_write_pps (&bs, h265_is_scc (encoder), pic_param);
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_pic_param.type = VAEncPackedHeaderPicture;
+  packed_pic_param.bit_length = data_bit_size;
+  packed_pic_param.has_emulation_bytes = 0;
+
+  packed_pic = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_pic_param, sizeof (packed_pic_param),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_pic);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_pic);
+  gst_vaapi_codec_object_replace (&packed_pic, NULL);
+
+  /* store pps data */
+  _check_vps_sps_pps_status (encoder, data + 4, data_bit_size / 8 - 4);
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write PPS NAL unit");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+static gboolean
+get_nal_unit_type (GstVaapiEncPicture * picture, guint8 * nal_unit_type)
+{
+  switch (picture->type) {
+    case GST_VAAPI_PICTURE_TYPE_I:
+      if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
+        *nal_unit_type = GST_H265_NAL_SLICE_IDR_W_RADL;
+      else
+        *nal_unit_type = GST_H265_NAL_SLICE_TRAIL_R;
+      break;
+    case GST_VAAPI_PICTURE_TYPE_P:
+      *nal_unit_type = GST_H265_NAL_SLICE_TRAIL_R;
+      break;
+    case GST_VAAPI_PICTURE_TYPE_B:
+      *nal_unit_type = GST_H265_NAL_SLICE_TRAIL_N;
+      break;
+    default:
+      return FALSE;
+  }
+  return TRUE;
+}
+
+/* Adds the supplied slice header to the list of packed
+   headers to pass down as-is to the encoder */
+static gboolean
+add_packed_slice_header (GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiEncSlice * slice)
+{
+  GstVaapiEncPackedHeader *packed_slice;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_slice_param = { 0 };
+  const VAEncSliceParameterBufferHEVC *const slice_param = slice->param;
+  guint32 data_bit_size;
+  guint8 *data;
+  guint8 nal_unit_type;
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  WRITE_UINT32 (&bs, 0x00000001, 32);   /* start code */
+
+  if (!get_nal_unit_type (picture, &nal_unit_type))
+    goto bs_error;
+  bs_write_nal_header (&bs, nal_unit_type);
+
+  bs_write_slice (&bs, slice_param, encoder, picture, nal_unit_type);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_slice_param.type = VAEncPackedHeaderSlice;
+  packed_slice_param.bit_length = data_bit_size;
+  packed_slice_param.has_emulation_bytes = 0;
+
+  packed_slice = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_slice_param, sizeof (packed_slice_param),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_slice);
+
+  gst_vaapi_enc_slice_add_packed_header (slice, packed_slice);
+  gst_vaapi_codec_object_replace (&packed_slice, NULL);
+
+  gst_bit_writer_reset (&bs);
+  return TRUE;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_WARNING ("failed to write Slice NAL unit header");
+    gst_bit_writer_reset (&bs);
+    return FALSE;
+  }
+}
+
+/* Reference picture management */
+static void
+reference_pic_free (GstVaapiEncoderH265 * encoder, GstVaapiEncoderH265Ref * ref)
+{
+  if (!ref)
+    return;
+  if (ref->pic)
+    gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), ref->pic);
+  g_slice_free (GstVaapiEncoderH265Ref, ref);
+}
+
+static inline GstVaapiEncoderH265Ref *
+reference_pic_create (GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiEncoderH265Ref *const ref = g_slice_new0 (GstVaapiEncoderH265Ref);
+
+  ref->pic = surface;
+  ref->poc = picture->poc;
+  return ref;
+}
+
+static gboolean
+reference_list_update (GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiEncoderH265Ref *ref;
+  GstVaapiH265RefPool *const ref_pool = &encoder->ref_pool;
+
+  if (GST_VAAPI_PICTURE_TYPE_B == picture->type) {
+    gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), surface);
+    return TRUE;
+  }
+
+  if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture)) {
+    while (!g_queue_is_empty (&ref_pool->ref_list))
+      reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list));
+  } else if (g_queue_get_length (&ref_pool->ref_list) >=
+      ref_pool->max_ref_frames) {
+    reference_pic_free (encoder, g_queue_pop_head (&ref_pool->ref_list));
+  }
+  ref = reference_pic_create (encoder, picture, surface);
+  g_queue_push_tail (&ref_pool->ref_list, ref);
+  g_assert (g_queue_get_length (&ref_pool->ref_list) <=
+      ref_pool->max_ref_frames);
+  return TRUE;
+}
+
+static gboolean
+reference_list_init (GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture,
+    GstVaapiEncoderH265Ref ** reflist_0,
+    guint * reflist_0_count,
+    GstVaapiEncoderH265Ref ** reflist_1, guint * reflist_1_count)
+{
+  GstVaapiEncoderH265Ref *tmp;
+  GstVaapiH265RefPool *const ref_pool = &encoder->ref_pool;
+  GList *iter, *list_0_start = NULL, *list_1_start = NULL;
+  guint count;
+
+  *reflist_0_count = 0;
+  *reflist_1_count = 0;
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
+    return TRUE;
+
+  iter = g_queue_peek_tail_link (&ref_pool->ref_list);
+  for (; iter; iter = g_list_previous (iter)) {
+    tmp = (GstVaapiEncoderH265Ref *) iter->data;
+    g_assert (tmp && tmp->poc != picture->poc);
+    if (_poc_greater_than (picture->poc, tmp->poc, encoder->max_pic_order_cnt)) {
+      list_0_start = iter;
+      list_1_start = g_list_next (iter);
+      break;
+    }
+  }
+
+  /* order reflist_0 */
+  g_assert (list_0_start);
+  iter = list_0_start;
+  count = 0;
+  for (; iter; iter = g_list_previous (iter)) {
+    reflist_0[count] = (GstVaapiEncoderH265Ref *) iter->data;
+    ++count;
+  }
+  *reflist_0_count = count;
+
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_B)
+    return TRUE;
+
+  /* order reflist_1 */
+  count = 0;
+  iter = list_1_start;
+  for (; iter; iter = g_list_next (iter)) {
+    reflist_1[count] = (GstVaapiEncoderH265Ref *) iter->data;
+    ++count;
+  }
+  *reflist_1_count = count;
+  return TRUE;
+}
+
+/* Fills in VA sequence parameter buffer */
+static gboolean
+fill_sequence (GstVaapiEncoderH265 * encoder, GstVaapiEncSequence * sequence)
+{
+  VAEncSequenceParameterBufferHEVC *const seq_param = sequence->param;
+  const GstVideoFormat format =
+      GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder));
+  guint bits_depth_luma_minus8 =
+      GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info (format), 0);
+  if (bits_depth_luma_minus8 < 8)
+    return FALSE;
+  bits_depth_luma_minus8 -= 8;
+
+  memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferHEVC));
+
+  seq_param->general_profile_idc = encoder->profile_idc;
+  seq_param->general_level_idc = encoder->level_idc;
+  seq_param->general_tier_flag = encoder->tier;
+
+  seq_param->intra_period = GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder);
+  seq_param->intra_idr_period = encoder->idr_period;
+  seq_param->ip_period = seq_param->intra_period > 1 ?
+      (1 + encoder->num_bframes) : 0;
+  seq_param->bits_per_second = encoder->bitrate_bits;
+
+  seq_param->pic_width_in_luma_samples = encoder->luma_width;
+  seq_param->pic_height_in_luma_samples = encoder->luma_height;
+
+  /*sequence field values */
+  seq_param->seq_fields.value = 0;
+  seq_param->seq_fields.bits.chroma_format_idc =
+      gst_vaapi_utils_h265_get_chroma_format_idc
+      (gst_vaapi_video_format_get_chroma_type (GST_VIDEO_INFO_FORMAT
+          (GST_VAAPI_ENCODER_VIDEO_INFO (encoder))));
+  /* the 4:4:4 chrome format */
+  if (seq_param->seq_fields.bits.chroma_format_idc == 3)
+    seq_param->seq_fields.bits.separate_colour_plane_flag = 0;
+  seq_param->seq_fields.bits.separate_colour_plane_flag = 0;
+  seq_param->seq_fields.bits.bit_depth_luma_minus8 = bits_depth_luma_minus8;
+  seq_param->seq_fields.bits.bit_depth_chroma_minus8 = bits_depth_luma_minus8;
+  seq_param->seq_fields.bits.scaling_list_enabled_flag = FALSE;
+  seq_param->seq_fields.bits.strong_intra_smoothing_enabled_flag = TRUE;
+  seq_param->seq_fields.bits.amp_enabled_flag = TRUE;
+  seq_param->seq_fields.bits.sample_adaptive_offset_enabled_flag =
+      encoder->sample_adaptive_offset_enabled_flag = FALSE;
+  seq_param->seq_fields.bits.pcm_enabled_flag = FALSE;
+  seq_param->seq_fields.bits.pcm_loop_filter_disabled_flag = FALSE;
+  seq_param->seq_fields.bits.sps_temporal_mvp_enabled_flag =
+      encoder->sps_temporal_mvp_enabled_flag = TRUE;
+
+  /* Based on 32x32 CTU (64x64 when using lowpower mode for hardware limitation) */
+  seq_param->log2_min_luma_coding_block_size_minus3 = 0;
+  if (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP)
+    seq_param->log2_diff_max_min_luma_coding_block_size = 3;
+  else
+    seq_param->log2_diff_max_min_luma_coding_block_size = 2;
+  seq_param->log2_min_transform_block_size_minus2 = 0;
+  seq_param->log2_diff_max_min_transform_block_size = 3;
+  /*
+   * Intel HW supports up to 2, we can provide a quirk for other HWs in future
+   * if other HW may support other values
+   *
+   * Refer to https://01.org/sites/default/files/documentation/intel-gfx-prm-osrc-kbl-vol10-hevc.pdf
+   */
+  seq_param->max_transform_hierarchy_depth_inter = 2;
+  seq_param->max_transform_hierarchy_depth_intra = 2;
+
+  seq_param->pcm_sample_bit_depth_luma_minus1 = 0;
+  seq_param->pcm_sample_bit_depth_chroma_minus1 = 0;
+  seq_param->log2_min_pcm_luma_coding_block_size_minus3 = 0;
+  seq_param->log2_max_pcm_luma_coding_block_size_minus3 = 0;
+
+  /* VUI parameters are always set, at least for timing_info (framerate) */
+  seq_param->vui_parameters_present_flag = TRUE;
+  if (seq_param->vui_parameters_present_flag) {
+    seq_param->vui_fields.bits.aspect_ratio_info_present_flag = TRUE;
+    if (seq_param->vui_fields.bits.aspect_ratio_info_present_flag) {
+      const GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+      seq_param->aspect_ratio_idc = 0xff;
+      seq_param->sar_width = GST_VIDEO_INFO_PAR_N (vip);
+      seq_param->sar_height = GST_VIDEO_INFO_PAR_D (vip);
+    }
+    seq_param->vui_fields.bits.bitstream_restriction_flag = FALSE;
+    seq_param->vui_fields.bits.vui_timing_info_present_flag = TRUE;
+    if (seq_param->vui_fields.bits.vui_timing_info_present_flag) {
+      seq_param->vui_num_units_in_tick = GST_VAAPI_ENCODER_FPS_D (encoder);
+      seq_param->vui_time_scale = GST_VAAPI_ENCODER_FPS_N (encoder);
+    }
+  }
+
+  if (h265_is_scc (encoder)) {
+#if VA_CHECK_VERSION(1,8,0)
+    seq_param->scc_fields.bits.palette_mode_enabled_flag = 1;
+#else
+    /* SCC profile should not be selected. */
+    g_assert_not_reached ();
+    return FALSE;
+#endif
+  }
+
+  return TRUE;
+}
+
+/* CTUs in each tile column */
+static guint32 tile_ctu_cols[GST_VAAPI_H265_MAX_COL_TILES];
+/* CTUs in each tile row */
+static guint32 tile_ctu_rows[GST_VAAPI_H265_MAX_ROW_TILES];
+
+/* Fills in VA picture parameter buffer */
+static gboolean
+fill_picture (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
+{
+  VAEncPictureParameterBufferHEVC *const pic_param = picture->param;
+  GstVaapiH265RefPool *const ref_pool = &encoder->ref_pool;
+  GstVaapiEncoderH265Ref *ref_pic;
+  GList *reflist;
+  guint i;
+  guint8 nal_unit_type, no_output_of_prior_pics_flag = 0;
+
+  memset (pic_param, 0, sizeof (VAEncPictureParameterBufferHEVC));
+
+  pic_param->decoded_curr_pic.picture_id =
+      GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
+  pic_param->decoded_curr_pic.pic_order_cnt = picture->poc;
+  pic_param->decoded_curr_pic.flags = 0;
+
+  i = 0;
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_I) {
+    for (reflist = g_queue_peek_head_link (&ref_pool->ref_list);
+        reflist; reflist = g_list_next (reflist)) {
+      ref_pic = reflist->data;
+      g_assert (ref_pic && ref_pic->pic &&
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic) != VA_INVALID_ID);
+
+      pic_param->reference_frames[i].picture_id =
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (ref_pic->pic);
+      pic_param->reference_frames[i].pic_order_cnt = ref_pic->poc;
+      ++i;
+    }
+    g_assert (i <= 15 && i <= ref_pool->max_ref_frames);
+  }
+  for (; i < 15; ++i) {
+    pic_param->reference_frames[i].picture_id = VA_INVALID_SURFACE;
+    pic_param->reference_frames[i].flags = VA_PICTURE_HEVC_INVALID;
+  }
+  pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf);
+
+  /* slice_temporal_mvp_enable_flag == FALSE */
+  pic_param->collocated_ref_pic_index = 0xFF;
+
+  pic_param->last_picture = 0;
+  pic_param->pic_init_qp = encoder->qp_i;
+  pic_param->num_ref_idx_l0_default_active_minus1 =
+      (ref_pool->max_reflist0_count ? (ref_pool->max_reflist0_count - 1) : 0);
+  pic_param->num_ref_idx_l1_default_active_minus1 =
+      (ref_pool->max_reflist1_count ? (ref_pool->max_reflist1_count - 1) : 0);
+
+  if (!get_nal_unit_type (picture, &nal_unit_type))
+    return FALSE;
+  pic_param->nal_unit_type = nal_unit_type;
+
+  /* set picture fields */
+  pic_param->pic_fields.value = 0;
+  pic_param->pic_fields.bits.idr_pic_flag =
+      GST_VAAPI_ENC_PICTURE_IS_IDR (picture);
+  pic_param->pic_fields.bits.coding_type = picture->type;
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_B)
+    pic_param->pic_fields.bits.reference_pic_flag = TRUE;
+  pic_param->pic_fields.bits.sign_data_hiding_enabled_flag = FALSE;
+  pic_param->pic_fields.bits.transform_skip_enabled_flag = TRUE;
+  /* it seems driver requires enablement of cu_qp_delta_enabled_flag
+   * to modifiy QP values in CBR mode or low power encoding */
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) != GST_VAAPI_RATECONTROL_CQP
+      || picture->has_roi
+      || encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP)
+    pic_param->pic_fields.bits.cu_qp_delta_enabled_flag = 1;
+
+  /* XXX: Intel's media-driver, when using low-power mode, requires
+   * that diff_cu_qp_delta_depth has to be equal to
+   * log2_diff_max_min_luma_coding_block_size, meaning 3.
+   *
+   * For now we assume that on only Intel's media-drivers supports
+   * H265 low-power */
+  if ((encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP) &&
+      (pic_param->pic_fields.bits.cu_qp_delta_enabled_flag))
+    pic_param->diff_cu_qp_delta_depth = 3;
+
+  pic_param->pic_fields.bits.pps_loop_filter_across_slices_enabled_flag = TRUE;
+
+  if (GST_VAAPI_ENC_PICTURE_IS_IDR (picture))
+    no_output_of_prior_pics_flag = 1;
+  pic_param->pic_fields.bits.no_output_of_prior_pics_flag =
+      no_output_of_prior_pics_flag;
+
+  /* Setup tile info */
+  pic_param->pic_fields.bits.tiles_enabled_flag =
+      h265_is_tile_enabled (encoder);
+  if (pic_param->pic_fields.bits.tiles_enabled_flag) {
+    /* Always set loop filter across tiles enabled now */
+    pic_param->pic_fields.bits.loop_filter_across_tiles_enabled_flag = 1;
+
+    pic_param->num_tile_columns_minus1 = encoder->num_tile_cols - 1;
+    pic_param->num_tile_rows_minus1 = encoder->num_tile_rows - 1;
+
+    /* The VA row_height_minus1 and column_width_minus1 size is 1 smaller
+       than the MAX_COL_TILES and MAX_ROW_TILES, which means the driver
+       can deduce the last tile's size based on the picture info. We need
+       to take care of the array size here. */
+    for (i = 0; i < MIN (encoder->num_tile_cols, 19); ++i)
+      pic_param->column_width_minus1[i] = tile_ctu_cols[i] - 1;
+    for (i = 0; i < MIN (encoder->num_tile_rows, 21); ++i)
+      pic_param->row_height_minus1[i] = tile_ctu_rows[i] - 1;
+  }
+
+  if (h265_is_scc (encoder)) {
+#if VA_CHECK_VERSION(1,8,0)
+    pic_param->scc_fields.bits.pps_curr_pic_ref_enabled_flag = 1;
+#else
+    /* SCC profile should not be selected. */
+    g_assert_not_reached ();
+    return FALSE;
+#endif
+  }
+
+  return TRUE;
+}
+
+static GstVaapiEncSlice *
+create_and_fill_one_slice (GstVaapiEncoderH265 * encoder,
+    GstVaapiEncPicture * picture,
+    GstVaapiEncoderH265Ref ** reflist_0, guint reflist_0_count,
+    GstVaapiEncoderH265Ref ** reflist_1, guint reflist_1_count)
+{
+  VAEncSliceParameterBufferHEVC *slice_param;
+  GstVaapiEncSlice *slice;
+  guint i_ref;
+
+  slice = GST_VAAPI_ENC_SLICE_NEW (HEVC, encoder);
+  g_assert (slice && slice->param_id != VA_INVALID_ID);
+  slice_param = slice->param;
+  memset (slice_param, 0, sizeof (VAEncSliceParameterBufferHEVC));
+
+  slice_param->slice_type = h265_get_slice_type (picture->type);
+  if (encoder->no_p_frame && slice_param->slice_type == GST_H265_P_SLICE) {
+    slice_param->slice_type = GST_H265_B_SLICE;
+  } else if (h265_is_scc (encoder) &&
+      slice_param->slice_type == GST_H265_I_SLICE) {
+    /* In scc mode, the I frame can ref to itself and so need the L0
+       reference list enabled. Just set the I frame to P_SLICE type
+       and leaving all reference unchanged. So all ref_pic_list0's
+       picture is invalid, the only ref is itself enabled by
+       pic_param->scc_fields.bits.pps_curr_pic_ref_enabled_flag. */
+    slice_param->slice_type = GST_H265_P_SLICE;
+  }
+
+  slice_param->slice_pic_parameter_set_id = 0;
+
+  slice_param->slice_fields.bits.num_ref_idx_active_override_flag =
+      reflist_0_count || reflist_1_count;
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_I && reflist_0_count > 0)
+    slice_param->num_ref_idx_l0_active_minus1 = reflist_0_count - 1;
+  else
+    slice_param->num_ref_idx_l0_active_minus1 = 0;
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_B && reflist_1_count > 0)
+    slice_param->num_ref_idx_l1_active_minus1 = reflist_1_count - 1;
+  else
+    slice_param->num_ref_idx_l1_active_minus1 = 0;
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_P && encoder->no_p_frame)
+    slice_param->num_ref_idx_l1_active_minus1 =
+        slice_param->num_ref_idx_l0_active_minus1;
+
+  i_ref = 0;
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_I) {
+    for (; i_ref < reflist_0_count; ++i_ref) {
+      slice_param->ref_pic_list0[i_ref].picture_id =
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_0[i_ref]->pic);
+      slice_param->ref_pic_list0[i_ref].pic_order_cnt = reflist_0[i_ref]->poc;
+    }
+  }
+  for (; i_ref < G_N_ELEMENTS (slice_param->ref_pic_list0); ++i_ref) {
+    slice_param->ref_pic_list0[i_ref].picture_id = VA_INVALID_SURFACE;
+    slice_param->ref_pic_list0[i_ref].flags = VA_PICTURE_HEVC_INVALID;
+  }
+
+  i_ref = 0;
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_B) {
+    for (; i_ref < reflist_1_count; ++i_ref) {
+      slice_param->ref_pic_list1[i_ref].picture_id =
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_1[i_ref]->pic);
+      slice_param->ref_pic_list1[i_ref].pic_order_cnt = reflist_1[i_ref]->poc;
+    }
+  } else if (picture->type == GST_VAAPI_PICTURE_TYPE_P && encoder->no_p_frame) {
+    for (; i_ref < reflist_0_count; ++i_ref) {
+      slice_param->ref_pic_list1[i_ref].picture_id =
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (reflist_0[i_ref]->pic);
+      slice_param->ref_pic_list1[i_ref].pic_order_cnt = reflist_0[i_ref]->poc;
+    }
+  }
+  for (; i_ref < G_N_ELEMENTS (slice_param->ref_pic_list1); ++i_ref) {
+    slice_param->ref_pic_list1[i_ref].picture_id = VA_INVALID_SURFACE;
+    slice_param->ref_pic_list1[i_ref].flags = VA_PICTURE_HEVC_INVALID;
+  }
+
+  slice_param->max_num_merge_cand = 5;  /* MaxNumMergeCand      */
+  slice_param->slice_qp_delta = encoder->qp_i - encoder->init_qp;
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP) {
+    if (picture->type == GST_VAAPI_PICTURE_TYPE_P) {
+      slice_param->slice_qp_delta += encoder->qp_ip;
+    } else if (picture->type == GST_VAAPI_PICTURE_TYPE_B) {
+      slice_param->slice_qp_delta += encoder->qp_ib;
+    }
+    if ((gint) encoder->init_qp + slice_param->slice_qp_delta <
+        (gint) encoder->min_qp) {
+      slice_param->slice_qp_delta = encoder->min_qp - encoder->init_qp;
+    }
+    if ((gint) encoder->init_qp + slice_param->slice_qp_delta >
+        (gint) encoder->max_qp) {
+      slice_param->slice_qp_delta = encoder->max_qp - encoder->init_qp;
+    }
+  }
+
+  slice_param->slice_fields.bits.slice_loop_filter_across_slices_enabled_flag =
+      TRUE;
+
+  return slice;
+}
+
+/* Adds slice headers to picture */
+static gboolean
+add_slice_headers (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiEncoderH265Ref ** reflist_0, guint reflist_0_count,
+    GstVaapiEncoderH265Ref ** reflist_1, guint reflist_1_count)
+{
+  VAEncSliceParameterBufferHEVC *slice_param;
+  GstVaapiEncSlice *slice;
+  guint slice_of_ctus, slice_mod_ctus, cur_slice_ctus;
+  guint ctu_size;
+  guint ctu_width_round_factor;
+  guint last_ctu_index;
+  guint i_slice;
+
+  g_assert (picture);
+
+  if (h265_is_tile_enabled (encoder)) {
+    for (i_slice = 0; i_slice < encoder->num_slices; ++i_slice) {
+      encoder->first_slice_segment_in_pic_flag = (i_slice == 0);
+
+      slice = create_and_fill_one_slice (encoder, picture, reflist_0,
+          reflist_0_count, reflist_1, reflist_1_count);
+      slice_param = slice->param;
+
+      slice_param->slice_segment_address =
+          encoder->tile_slice_address_map[encoder->tile_slice_address[i_slice]];
+      slice_param->num_ctu_in_slice = encoder->tile_slice_ctu_num[i_slice];
+      GST_LOG ("slice %d start tile address is %d, start address is %d,"
+          " CTU num %d", i_slice, encoder->tile_slice_address[i_slice],
+          slice_param->slice_segment_address, slice_param->num_ctu_in_slice);
+
+      if (i_slice == encoder->num_slices - 1)
+        slice_param->slice_fields.bits.last_slice_of_pic_flag = 1;
+
+      if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+              VA_ENC_PACKED_HEADER_SLICE)
+          && !add_packed_slice_header (encoder, picture, slice))
+        goto error_create_packed_slice_hdr;
+
+      gst_vaapi_enc_picture_add_slice (picture, slice);
+      gst_vaapi_codec_object_replace (&slice, NULL);
+    }
+  } else {
+    ctu_size = encoder->ctu_width * encoder->ctu_height;
+
+    g_assert (encoder->num_slices && encoder->num_slices < ctu_size);
+    slice_of_ctus = ctu_size / encoder->num_slices;
+    slice_mod_ctus = ctu_size % encoder->num_slices;
+    last_ctu_index = 0;
+
+    for (i_slice = 0;
+        i_slice < encoder->num_slices && (last_ctu_index < ctu_size);
+        ++i_slice) {
+      cur_slice_ctus = slice_of_ctus;
+      if (slice_mod_ctus) {
+        ++cur_slice_ctus;
+        --slice_mod_ctus;
+      }
+
+      slice = create_and_fill_one_slice (encoder, picture, reflist_0,
+          reflist_0_count, reflist_1, reflist_1_count);
+      slice_param = slice->param;
+
+      /* Work-around for satisfying the VA-Intel driver.
+       * The driver only support multi slice begin from row start address */
+      ctu_width_round_factor =
+          encoder->ctu_width - (cur_slice_ctus % encoder->ctu_width);
+      cur_slice_ctus += ctu_width_round_factor;
+      if ((last_ctu_index + cur_slice_ctus) > ctu_size)
+        cur_slice_ctus = ctu_size - last_ctu_index;
+
+      if (i_slice == 0) {
+        encoder->first_slice_segment_in_pic_flag = TRUE;
+        slice_param->slice_segment_address = 0;
+      } else {
+        encoder->first_slice_segment_in_pic_flag = FALSE;
+        slice_param->slice_segment_address = last_ctu_index;
+      }
+      slice_param->num_ctu_in_slice = cur_slice_ctus;
+
+      /* set calculation for next slice */
+      last_ctu_index += cur_slice_ctus;
+
+      if ((i_slice == encoder->num_slices - 1) || (last_ctu_index == ctu_size))
+        slice_param->slice_fields.bits.last_slice_of_pic_flag = 1;
+
+      if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+              VA_ENC_PACKED_HEADER_SLICE)
+          && !add_packed_slice_header (encoder, picture, slice))
+        goto error_create_packed_slice_hdr;
+
+      gst_vaapi_enc_picture_add_slice (picture, slice);
+      gst_vaapi_codec_object_replace (&slice, NULL);
+    }
+
+    if (i_slice < encoder->num_slices)
+      GST_WARNING
+          ("Using less number of slices than requested, Number of slices per"
+          " pictures is %d", i_slice);
+    g_assert (last_ctu_index == ctu_size);
+  }
+
+  return TRUE;
+
+error_create_packed_slice_hdr:
+  {
+    GST_ERROR ("failed to create packed slice header buffer");
+    gst_vaapi_codec_object_replace (&slice, NULL);
+    return FALSE;
+  }
+}
+
+/* Generates and submits SPS header accordingly into the bitstream */
+static gboolean
+ensure_sequence (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncSequence *sequence = NULL;
+
+  /* submit an SPS header before every new I-frame, if codec config changed */
+  if (!encoder->config_changed || picture->type != GST_VAAPI_PICTURE_TYPE_I)
+    return TRUE;
+
+  sequence = GST_VAAPI_ENC_SEQUENCE_NEW (HEVC, encoder);
+  if (!sequence || !fill_sequence (encoder, sequence))
+    goto error_create_seq_param;
+
+  /* add packed vps and sps headers */
+  if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+          VA_ENC_PACKED_HEADER_SEQUENCE)
+      && !(add_packed_vps_header (encoder, picture, sequence)
+          && add_packed_sequence_header (encoder, picture, sequence))) {
+    goto error_create_packed_seq_hdr;
+  }
+
+  if (sequence) {
+    gst_vaapi_enc_picture_set_sequence (picture, sequence);
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+  }
+
+  encoder->config_changed = FALSE;
+  return TRUE;
+
+  /* ERRORS */
+error_create_seq_param:
+  {
+    GST_ERROR ("failed to create sequence parameter buffer (SPS)");
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+    return FALSE;
+  }
+error_create_packed_seq_hdr:
+  {
+    GST_ERROR ("failed to create packed sequence header buffer");
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+    return FALSE;
+  }
+}
+
+static gboolean
+ensure_control_rate_params (GstVaapiEncoderH265 * encoder)
+{
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
+    return TRUE;
+
+#if VA_CHECK_VERSION(1,1,0)
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_ICQ) {
+    GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).ICQ_quality_factor =
+        encoder->quality_factor;
+    return TRUE;
+  }
+#endif
+
+  /* RateControl params */
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).bits_per_second =
+      encoder->bitrate_bits;
+  /* CPB (Coded picture buffer) length in milliseconds, which could be
+   * provided as a property */
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).window_size = encoder->cpb_length;
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->init_qp;
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).min_qp = encoder->min_qp;
+
+#if VA_CHECK_VERSION(1,1,0)
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).max_qp = encoder->max_qp;
+#endif
+
+#if VA_CHECK_VERSION(1,0,0)
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).rc_flags.bits.mb_rate_control =
+      (guint) encoder->mbbrc;
+#endif
+
+#if VA_CHECK_VERSION(1,3,0)
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).quality_factor =
+      encoder->quality_factor;
+#endif
+
+  /* HRD params */
+  fill_hrd_params (encoder, &GST_VAAPI_ENCODER_VA_HRD (encoder));
+
+  return TRUE;
+}
+
+static gboolean
+ensure_misc_params (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture))
+    return FALSE;
+  if (!gst_vaapi_encoder_ensure_param_roi_regions (base_encoder, picture))
+    return FALSE;
+  if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture))
+    return FALSE;
+  return TRUE;
+}
+
+/* Generates and submits PPS header accordingly into the bitstream */
+static gboolean
+ensure_picture (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiCodedBuffer *const codedbuf =
+      GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
+  gboolean res = FALSE;
+
+  res = fill_picture (encoder, picture, codedbuf, surface);
+
+  if (!res)
+    return FALSE;
+
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_I &&
+      (GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+          VA_ENC_PACKED_HEADER_PICTURE)
+      && !add_packed_picture_header (encoder, picture)) {
+    GST_ERROR ("set picture packed header failed");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+
+/* Generates slice headers */
+static gboolean
+ensure_slices (GstVaapiEncoderH265 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncoderH265Ref *reflist_0[15];
+  GstVaapiEncoderH265Ref *reflist_1[15];
+  GstVaapiH265RefPool *const ref_pool = &encoder->ref_pool;
+  guint reflist_0_count = 0, reflist_1_count = 0;
+
+  g_assert (picture);
+
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_I &&
+      !reference_list_init (encoder, picture,
+          reflist_0, &reflist_0_count, reflist_1, &reflist_1_count)) {
+    GST_ERROR ("reference list reorder failed");
+    return FALSE;
+  }
+
+  g_assert (reflist_0_count + reflist_1_count <= ref_pool->max_ref_frames);
+  if (reflist_0_count > ref_pool->max_reflist0_count)
+    reflist_0_count = ref_pool->max_reflist0_count;
+  if (reflist_1_count > ref_pool->max_reflist1_count)
+    reflist_1_count = ref_pool->max_reflist1_count;
+
+  if (!add_slice_headers (encoder, picture,
+          reflist_0, reflist_0_count, reflist_1, reflist_1_count))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Normalizes bitrate (and CPB size) for HRD conformance */
+static void
+ensure_bitrate_hrd (GstVaapiEncoderH265 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  guint bitrate, cpb_size;
+
+  if (!base_encoder->bitrate) {
+    encoder->bitrate_bits = 0;
+    return;
+  }
+
+  /* Round down bitrate. This is a hard limit mandated by the user */
+  g_assert (SX_BITRATE >= 6);
+  bitrate = (base_encoder->bitrate * 1000) & ~((1U << SX_BITRATE) - 1);
+  if (bitrate != encoder->bitrate_bits) {
+    GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate);
+    encoder->bitrate_bits = bitrate;
+    encoder->config_changed = TRUE;
+  }
+
+  /* Round up CPB size. This is an HRD compliance detail */
+  g_assert (SX_CPB_SIZE >= 4);
+  cpb_size = gst_util_uint64_scale (bitrate, encoder->cpb_length, 1000) &
+      ~((1U << SX_CPB_SIZE) - 1);
+  if (cpb_size != encoder->cpb_length_bits) {
+    GST_DEBUG ("HRD CPB size: %u bits", cpb_size);
+    encoder->cpb_length_bits = cpb_size;
+    encoder->config_changed = TRUE;
+  }
+}
+
+/* Estimates a good enough bitrate if none was supplied */
+static void
+ensure_bitrate (GstVaapiEncoderH265 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
+    case GST_VAAPI_RATECONTROL_CBR:
+    case GST_VAAPI_RATECONTROL_VBR:
+    case GST_VAAPI_RATECONTROL_QVBR:
+      if (!base_encoder->bitrate) {
+        /* FIXME: Provide better estimation */
+        /* Using a 1/6 compression ratio */
+        /* 12 bits per pixel for YUV420 */
+        guint64 factor;
+
+        factor = (guint64) encoder->luma_width * encoder->luma_height * 12 / 6;
+        base_encoder->bitrate =
+            gst_util_uint64_scale (factor, GST_VAAPI_ENCODER_FPS_N (encoder),
+            GST_VAAPI_ENCODER_FPS_D (encoder)) / 1000;
+        GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate);
+      }
+      break;
+    default:
+      base_encoder->bitrate = 0;
+      break;
+  }
+  ensure_bitrate_hrd (encoder);
+}
+
+/* Constructs profile, tier and level information based on user-defined limits */
+static GstVaapiEncoderStatus
+ensure_profile_tier_level (GstVaapiEncoderH265 * encoder)
+{
+  const GstVaapiProfile profile = encoder->profile;
+  const GstVaapiTierH265 tier = encoder->tier;
+  const GstVaapiLevelH265 level = encoder->level;
+
+  if (!ensure_profile (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  encoder->entrypoint =
+      gst_vaapi_encoder_get_entrypoint (GST_VAAPI_ENCODER_CAST (encoder),
+      encoder->profile);
+  g_assert (encoder->entrypoint != GST_VAAPI_ENTRYPOINT_INVALID);
+
+  /* Ensure bitrate if not set already and derive the right level to use */
+  ensure_bitrate (encoder);
+
+  if (!ensure_tier_level (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+
+  if (encoder->profile != profile || encoder->level != level
+      || encoder->tier != tier) {
+    GST_DEBUG ("selected %s profile at tier %s and level %s",
+        gst_vaapi_utils_h265_get_profile_string (encoder->profile),
+        gst_vaapi_utils_h265_get_tier_string (encoder->tier),
+        gst_vaapi_utils_h265_get_level_string (encoder->level));
+    encoder->config_changed = TRUE;
+  }
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static gboolean
+check_ref_list (GstVaapiEncoderH265 * encoder)
+{
+#if VA_CHECK_VERSION(1,9,0)
+  /* Some driver require both r0 and r1 list are non NULL, i.e. no p frame
+     in the stream. The traditional P frame can be converted to B frame with
+     forward dependency only. The new B frame has only forward reference in
+     both r0 and r1 list, which conforms to H265 spec. This can get some gain
+     because there are 2 MVs for each frame and can generate better motion
+     estimation. */
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (encoder);
+  guint value = 0;
+  VAProfile va_profile = gst_vaapi_profile_get_va_profile (encoder->profile);
+  VAEntrypoint va_entrypoint =
+      gst_vaapi_entrypoint_get_va_entrypoint (encoder->entrypoint);
+
+  encoder->no_p_frame = FALSE;
+  if (gst_vaapi_get_config_attribute (base_encoder->display, va_profile,
+          va_entrypoint, VAConfigAttribPredictionDirection, &value)) {
+    gboolean double_ref_list =
+        ((value & VA_PREDICTION_DIRECTION_BI_NOT_EMPTY) != 0);
+    if (double_ref_list) {
+      GST_INFO ("driver does not support P frame, we need to convert P"
+          " frame to forward dependency B frame.");
+      encoder->no_p_frame = double_ref_list;
+    }
+  }
+
+  if (encoder->no_p_frame == TRUE && base_encoder->max_num_ref_frames_1 < 1) {
+    GST_WARNING ("P frame should be converted to forward dependent B,"
+        " but reference list 1 is disabled here. Should be an invalid"
+        " setting or a driver error.");
+    return FALSE;
+  }
+#endif
+
+  return TRUE;
+}
+
+static GstVaapiEncoderStatus
+reset_properties (GstVaapiEncoderH265 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  GstVaapiH265ReorderPool *reorder_pool;
+  GstVaapiH265RefPool *ref_pool;
+  guint ctu_size;
+  gboolean ret;
+
+  if (encoder->idr_period < base_encoder->keyframe_period)
+    encoder->idr_period = base_encoder->keyframe_period;
+
+  if (encoder->min_qp > encoder->init_qp)
+    encoder->min_qp = encoder->init_qp;
+  if (encoder->max_qp < encoder->init_qp)
+    encoder->max_qp = encoder->init_qp;
+
+  encoder->qp_i = encoder->init_qp;
+
+  ctu_size = encoder->ctu_width * encoder->ctu_height;
+  ret = gst_vaapi_encoder_ensure_num_slices (base_encoder, encoder->profile,
+      encoder->entrypoint, (ctu_size + 1) / 2, &encoder->num_slices);
+  g_assert (ret);
+
+  gst_vaapi_encoder_ensure_max_num_ref_frames (base_encoder, encoder->profile,
+      encoder->entrypoint);
+
+  if (!check_ref_list (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+
+  if (base_encoder->max_num_ref_frames_1 < 1 && encoder->num_bframes > 0) {
+    GST_WARNING ("Disabling b-frame since the driver doesn't support it");
+    encoder->num_bframes = 0;
+  }
+
+  if (encoder->num_ref_frames > base_encoder->max_num_ref_frames_0) {
+    GST_INFO ("Lowering the number of reference frames to %d",
+        base_encoder->max_num_ref_frames_0);
+    encoder->num_ref_frames = base_encoder->max_num_ref_frames_0;
+  }
+
+  if (encoder->num_bframes > (base_encoder->keyframe_period + 1) / 2)
+    encoder->num_bframes = (base_encoder->keyframe_period + 1) / 2;
+
+  if (encoder->num_bframes > 0 && GST_VAAPI_ENCODER_FPS_N (encoder) > 0)
+    encoder->cts_offset = gst_util_uint64_scale (GST_SECOND,
+        GST_VAAPI_ENCODER_FPS_D (encoder), GST_VAAPI_ENCODER_FPS_N (encoder));
+  else
+    encoder->cts_offset = 0;
+
+  /* init max_poc */
+  encoder->log2_max_pic_order_cnt =
+      h265_get_log2_max_pic_order_cnt (encoder->idr_period);
+  g_assert (encoder->log2_max_pic_order_cnt >= 4);
+  encoder->max_pic_order_cnt = (1 << encoder->log2_max_pic_order_cnt);
+  encoder->idr_num = 0;
+
+  /* Only Supporting a maximum of two reference frames */
+  if (encoder->num_bframes) {
+    encoder->max_dec_pic_buffering = encoder->num_ref_frames + 2;
+    encoder->max_num_reorder_pics = 1;
+  } else {
+    encoder->max_dec_pic_buffering = encoder->num_ref_frames + 1;
+    encoder->max_num_reorder_pics = 0;
+  }
+
+  ref_pool = &encoder->ref_pool;
+  ref_pool->max_reflist0_count = encoder->num_ref_frames;
+  ref_pool->max_reflist1_count = encoder->num_bframes > 0;
+  ref_pool->max_ref_frames = ref_pool->max_reflist0_count
+      + ref_pool->max_reflist1_count;
+
+  reorder_pool = &encoder->reorder_pool;
+  reorder_pool->frame_index = 0;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static void
+reset_tile (GstVaapiEncoderH265 * encoder)
+{
+  memset (tile_ctu_cols, 0, sizeof (tile_ctu_cols));
+  memset (tile_ctu_rows, 0, sizeof (tile_ctu_rows));
+
+  if (encoder->tile_slice_address)
+    g_free (encoder->tile_slice_address);
+  encoder->tile_slice_address = NULL;
+
+  if (encoder->tile_slice_ctu_num)
+    g_free (encoder->tile_slice_ctu_num);
+  encoder->tile_slice_ctu_num = NULL;
+
+  if (encoder->tile_slice_address_map)
+    g_free (encoder->tile_slice_address_map);
+  encoder->tile_slice_address_map = NULL;
+}
+
+static void
+recalculate_slices_num_by_tile (GstVaapiEncoderH265 * encoder)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+
+  /* If driver has the requirement that the slice should not span tiles,
+     we need to increase slice number if needed. */
+  if (gst_vaapi_display_has_driver_quirks (display,
+          GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE)) {
+    if (encoder->num_slices < encoder->num_tile_cols * encoder->num_tile_rows) {
+      /* encoder->num_slices > 1 means user set it */
+      if (encoder->num_slices > 1)
+        GST_WARNING ("user set num-slices to %d, which is smaller than tile"
+            " num %d. We should make slice not span tiles, just set the"
+            " num-slices to tile num here.",
+            encoder->num_slices,
+            encoder->num_tile_cols * encoder->num_tile_rows);
+      else
+        GST_INFO ("set default slice num to %d, the same as the tile num.",
+            encoder->num_tile_cols * encoder->num_tile_rows);
+      encoder->num_slices = encoder->num_tile_cols * encoder->num_tile_rows;
+    }
+  }
+}
+
+static GstVaapiEncoderStatus
+calculate_slices_start_address (GstVaapiEncoderH265 * encoder)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+  guint32 ctu_per_slice;
+  guint32 left_slices;
+  gint32 i, j, k;
+
+  /* If driver has the requirement that the slice should not span tiles,
+     firstly we should scatter slices uniformly into each tile, bigger
+     tile gets more slices. Then we should assign CTUs within one tile
+     uniformly to each slice in that tile. */
+  if (gst_vaapi_display_has_driver_quirks (display,
+          GST_VAAPI_DRIVER_QUIRK_HEVC_ENC_SLICE_NOT_SPAN_TILE)) {
+    guint32 *slices_per_tile = g_malloc (encoder->num_tile_cols *
+        encoder->num_tile_rows * sizeof (guint32));
+    if (!slices_per_tile)
+      return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+
+    ctu_per_slice = (encoder->ctu_width * encoder->ctu_height +
+        encoder->num_slices - 1) / encoder->num_slices;
+    g_assert (ctu_per_slice > 0);
+    left_slices = encoder->num_slices;
+
+    for (i = 0; i < encoder->num_tile_cols * encoder->num_tile_rows; i++) {
+      slices_per_tile[i] = 1;
+      left_slices--;
+    }
+    while (left_slices) {
+      /* Find the biggest CTUs/slices, and assign more. */
+      gfloat largest = 0.0f;
+      k = -1;
+      for (i = 0; i < encoder->num_tile_cols * encoder->num_tile_rows; i++) {
+        gfloat f;
+        f = ((gfloat) (tile_ctu_cols[i % encoder->num_tile_cols] *
+                tile_ctu_rows[i / encoder->num_tile_cols])) /
+            (gfloat) slices_per_tile[i];
+        g_assert (f >= 1.0f);
+        if (f > largest) {
+          k = i;
+          largest = f;
+        }
+      }
+
+      g_assert (k >= 0);
+      slices_per_tile[k]++;
+      left_slices--;
+    }
+
+    /* Assign CTUs in one tile uniformly to each slice. Note: the slice start
+       address is CTB address in tile scan(see spec 6.5), that is, we accumulate
+       all CTUs in tile0, then tile1, and tile2..., not from the picture's
+       perspective. */
+    encoder->tile_slice_address[0] = 0;
+    k = 1;
+    for (i = 0; i < encoder->num_tile_rows; i++) {
+      for (j = 0; j < encoder->num_tile_cols; j++) {
+        guint32 s_num = slices_per_tile[i * encoder->num_tile_cols + j];
+        guint32 one_tile_ctus = tile_ctu_cols[j] * tile_ctu_rows[i];
+        guint32 s;
+
+        GST_LOG ("Tile(row %d col %d), has CTU in col %d,"
+            " CTU in row is %d, total CTU %d, assigned %d slices", i, j,
+            tile_ctu_cols[j], tile_ctu_rows[i], one_tile_ctus, s_num);
+
+        g_assert (s_num > 0);
+        for (s = 0; s < s_num; s++) {
+          encoder->tile_slice_address[k] =
+              encoder->tile_slice_address[k - 1] + ((s +
+                  1) * one_tile_ctus) / s_num - (s * one_tile_ctus) / s_num;
+          encoder->tile_slice_ctu_num[k - 1] =
+              encoder->tile_slice_address[k] - encoder->tile_slice_address[k -
+              1];
+          k++;
+        }
+      }
+    }
+
+    g_assert (k == encoder->num_slices + 1);
+    /* Calculate the last one */
+    encoder->tile_slice_ctu_num[encoder->num_slices - 1] =
+        encoder->ctu_width * encoder->ctu_height -
+        encoder->tile_slice_address[encoder->num_slices - 1];
+
+    g_free (slices_per_tile);
+  }
+  /* The easy way, just assign CTUs to each slice uniformly */
+  else {
+    ctu_per_slice = (encoder->ctu_width * encoder->ctu_height +
+        encoder->num_slices - 1) / encoder->num_slices;
+    g_assert (ctu_per_slice > 0);
+
+    for (i = 0; i < encoder->num_slices - 1; i++)
+      encoder->tile_slice_ctu_num[i] = ctu_per_slice;
+    encoder->tile_slice_ctu_num[encoder->num_slices - 1] =
+        encoder->ctu_width * encoder->ctu_height -
+        (encoder->num_slices - 1) * ctu_per_slice;
+
+    encoder->tile_slice_address[0] = 0;
+    for (i = 1; i <= encoder->num_slices; i++)
+      encoder->tile_slice_address[i] = encoder->tile_slice_address[i - 1] +
+          encoder->tile_slice_ctu_num[i - 1];
+  }
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+ensure_tile (GstVaapiEncoderH265 * encoder)
+{
+  gint32 i, j, k;
+  guint32 ctu_tile_width_accu[GST_VAAPI_H265_MAX_COL_TILES + 1];
+  guint32 ctu_tile_height_accu[GST_VAAPI_H265_MAX_ROW_TILES + 1];
+  guint32 num_slices;
+  GstVaapiEncoderStatus ret;
+
+  reset_tile (encoder);
+
+  if (!h265_is_tile_enabled (encoder))
+    return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  if (!gst_vaapi_encoder_ensure_tile_support (GST_VAAPI_ENCODER (encoder),
+          encoder->profile, encoder->entrypoint)) {
+    GST_ERROR ("The profile:%s, entrypoint:%d does not support tile.",
+        gst_vaapi_utils_h265_get_profile_string (encoder->profile),
+        encoder->entrypoint);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (encoder->num_tile_cols >
+      gst_vaapi_utils_h265_get_level_limits (encoder->level)->MaxTileColumns) {
+    GST_ERROR ("num_tile_cols:%d exceeds MaxTileColumns:%d",
+        encoder->num_tile_cols,
+        gst_vaapi_utils_h265_get_level_limits (encoder->level)->MaxTileColumns);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  }
+  if (encoder->num_tile_rows >
+      gst_vaapi_utils_h265_get_level_limits (encoder->level)->MaxTileRows) {
+    GST_ERROR ("num_tile_rows:%d exceeds MaxTileRows:%d",
+        encoder->num_tile_rows,
+        gst_vaapi_utils_h265_get_level_limits (encoder->level)->MaxTileRows);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  if (encoder->ctu_width < encoder->num_tile_cols) {
+    GST_WARNING
+        ("Only %d CTUs in width, not enough to split into %d tile columns",
+        encoder->ctu_width, encoder->num_tile_cols);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  }
+  if (encoder->ctu_height < encoder->num_tile_rows) {
+    GST_WARNING
+        ("Only %d CTUs in height, not enough to split into %d tile rows",
+        encoder->ctu_height, encoder->num_tile_rows);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  recalculate_slices_num_by_tile (encoder);
+
+  /* ensure not exceed max supported slices */
+  num_slices = encoder->num_slices;
+  gst_vaapi_encoder_ensure_num_slices (GST_VAAPI_ENCODER_CAST (encoder),
+      encoder->profile, encoder->entrypoint,
+      (encoder->ctu_width * encoder->ctu_height + 1) / 2, &num_slices);
+  if (num_slices != encoder->num_slices) {
+    GST_ERROR ("The tile setting need at least %d slices, but the max"
+        " slice number is just %d", encoder->num_slices, num_slices);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  }
+
+  encoder->tile_slice_address =
+      /* Add one as sentinel, hold val to calculate ctu_num */
+      g_malloc ((encoder->num_slices + 1) * sizeof (guint32));
+  if (!encoder->tile_slice_address)
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  encoder->tile_slice_ctu_num =
+      g_malloc (encoder->num_slices * sizeof (guint32));
+  if (!encoder->tile_slice_ctu_num)
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  encoder->tile_slice_address_map =
+      g_malloc (encoder->ctu_width * encoder->ctu_height * sizeof (guint32));
+  if (!encoder->tile_slice_address_map)
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+
+  /* firstly uniformly separate CTUs into tiles, as the spec 6.5.1 define */
+  for (i = 0; i < encoder->num_tile_cols; i++)
+    tile_ctu_cols[i] =
+        ((i + 1) * encoder->ctu_width) / encoder->num_tile_cols -
+        (i * encoder->ctu_width) / encoder->num_tile_cols;
+  for (i = 0; i < encoder->num_tile_rows; i++)
+    tile_ctu_rows[i] =
+        ((i + 1) * encoder->ctu_height) / encoder->num_tile_rows -
+        (i * encoder->ctu_height) / encoder->num_tile_rows;
+
+  ret = calculate_slices_start_address (encoder);
+  if (ret != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return ret;
+
+  /* Build the map to specifying the conversion between a CTB address in CTB
+     raster scan of a picture and a CTB address in tile scan(see spec 6.5.1
+     for details). */
+  ctu_tile_width_accu[0] = 0;
+  for (i = 1; i <= encoder->num_tile_cols; i++)
+    ctu_tile_width_accu[i] = ctu_tile_width_accu[i - 1] + tile_ctu_cols[i - 1];
+  ctu_tile_height_accu[0] = 0;
+  for (i = 1; i <= encoder->num_tile_rows; i++)
+    ctu_tile_height_accu[i] =
+        ctu_tile_height_accu[i - 1] + tile_ctu_rows[i - 1];
+
+  for (k = 0; k < encoder->ctu_width * encoder->ctu_height; k++) {
+    /* The ctu coordinate in the picture. */
+    guint32 x = k % encoder->ctu_width;
+    guint32 y = k / encoder->ctu_width;
+    /* The ctu coordinate in the tile mode. */
+    guint32 tile_x = 0;
+    guint32 tile_y = 0;
+    /* The index of the CTU in the tile mode. */
+    guint32 tso = 0;
+
+    for (i = 0; i < encoder->num_tile_cols; i++)
+      if (x >= ctu_tile_width_accu[i])
+        tile_x = i;
+    g_assert (tile_x <= encoder->num_tile_cols - 1);
+
+    for (j = 0; j < encoder->num_tile_rows; j++)
+      if (y >= ctu_tile_height_accu[j])
+        tile_y = j;
+    g_assert (tile_y <= encoder->num_tile_rows - 1);
+
+    /* add all ctus in the tiles the same line before us */
+    for (i = 0; i < tile_x; i++)
+      tso += tile_ctu_rows[tile_y] * tile_ctu_cols[i];
+
+    /* add all ctus in the tiles above us */
+    for (j = 0; j < tile_y; j++)
+      tso += encoder->ctu_width * tile_ctu_rows[j];
+
+    /* add the ctus inside the same tile before us */
+    tso += (y - ctu_tile_height_accu[tile_y]) * tile_ctu_cols[tile_x]
+        + x - ctu_tile_width_accu[tile_x];
+
+    g_assert (tso < encoder->ctu_width * encoder->ctu_height);
+
+    encoder->tile_slice_address_map[tso] = k;
+  }
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h265_encode (GstVaapiEncoder * base_encoder,
+    GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
+{
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder);
+  GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  GstVaapiSurfaceProxy *reconstruct = NULL;
+
+  reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
+
+  g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
+
+  if (!ensure_sequence (encoder, picture))
+    goto error;
+  if (!ensure_misc_params (encoder, picture))
+    goto error;
+  if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
+    goto error;
+  if (!ensure_slices (encoder, picture))
+    goto error;
+  if (!gst_vaapi_enc_picture_encode (picture))
+    goto error;
+
+  if (!reference_list_update (encoder, picture, reconstruct))
+    goto error;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    if (reconstruct)
+      gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
+          reconstruct);
+    return ret;
+  }
+}
+
+struct _PendingIterState
+{
+  GstVaapiPictureType pic_type;
+};
+
+static gboolean
+gst_vaapi_encoder_h265_get_pending_reordered (GstVaapiEncoder * base_encoder,
+    GstVaapiEncPicture ** picture, gpointer * state)
+{
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder);
+  GstVaapiH265ReorderPool *reorder_pool;
+  GstVaapiEncPicture *pic;
+  struct _PendingIterState *iter;
+
+  g_return_val_if_fail (state, FALSE);
+
+  if (!*state) {
+    iter = g_new0 (struct _PendingIterState, 1);
+    iter->pic_type = GST_VAAPI_PICTURE_TYPE_P;
+    *state = iter;
+  } else {
+    iter = *state;
+  }
+
+  *picture = NULL;
+
+  reorder_pool = &encoder->reorder_pool;
+  if (g_queue_is_empty (&reorder_pool->reorder_frame_list))
+    return FALSE;
+
+  pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list);
+  g_assert (pic);
+  if (iter->pic_type == GST_VAAPI_PICTURE_TYPE_P) {
+    set_p_frame (pic, encoder);
+    iter->pic_type = GST_VAAPI_PICTURE_TYPE_B;
+  } else if (iter->pic_type == GST_VAAPI_PICTURE_TYPE_B) {
+    set_b_frame (pic, encoder);
+  } else {
+    GST_WARNING ("Unhandled pending picture type");
+  }
+
+  if (GST_CLOCK_TIME_IS_VALID (pic->frame->pts))
+    pic->frame->pts += encoder->cts_offset;
+
+  *picture = pic;
+  return TRUE;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h265_flush (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder);
+  GstVaapiH265ReorderPool *reorder_pool;
+  GstVaapiEncPicture *pic;
+
+  reorder_pool = &encoder->reorder_pool;
+  reorder_pool->frame_index = 0;
+  reorder_pool->cur_present_index = 0;
+
+  while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
+    pic = (GstVaapiEncPicture *)
+        g_queue_pop_head (&reorder_pool->reorder_frame_list);
+    gst_vaapi_enc_picture_unref (pic);
+  }
+  g_queue_clear (&reorder_pool->reorder_frame_list);
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+/* Generate "codec-data" buffer */
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h265_get_codec_data (GstVaapiEncoder * base_encoder,
+    GstBuffer ** out_buffer_ptr)
+{
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder);
+  const guint32 configuration_version = 0x01;
+  const guint32 nal_length_size = 4;
+  GstMapInfo vps_info, sps_info, pps_info;
+  GstBitWriter bs;
+  GstBuffer *buffer;
+  guint min_spatial_segmentation_idc = 0;
+  guint num_arrays = 3;
+
+  if (!encoder->vps_data || !encoder->sps_data || !encoder->pps_data)
+    return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER;
+  if (gst_buffer_get_size (encoder->sps_data) < 4)
+    return GST_VAAPI_ENCODER_STATUS_ERROR_INVALID_HEADER;
+
+  if (!gst_buffer_map (encoder->vps_data, &vps_info, GST_MAP_READ))
+    goto error_map_vps_buffer;
+
+  if (!gst_buffer_map (encoder->sps_data, &sps_info, GST_MAP_READ))
+    goto error_map_sps_buffer;
+
+  if (!gst_buffer_map (encoder->pps_data, &pps_info, GST_MAP_READ))
+    goto error_map_pps_buffer;
+
+  /* Header */
+  gst_bit_writer_init_with_size (&bs,
+      (vps_info.size + sps_info.size + pps_info.size + 64), FALSE);
+  WRITE_UINT32 (&bs, configuration_version, 8);
+  WRITE_UINT32 (&bs, sps_info.data[4], 8);      /* profile_space | tier_flag | profile_idc */
+  WRITE_UINT32 (&bs, sps_info.data[5], 32);     /* profile_compatibility_flag [0-31] */
+  /* progressive_source_flag | interlaced_source_flag | non_packed_constraint_flag |
+   * frame_only_constraint_flag | reserved_zero_bits[0-27] */
+  WRITE_UINT32 (&bs, sps_info.data[9], 32);
+  WRITE_UINT32 (&bs, sps_info.data[13], 16);    /* reserved_zero_bits [28-43] */
+  WRITE_UINT32 (&bs, sps_info.data[15], 8);     /* level_idc */
+  WRITE_UINT32 (&bs, 0x0f, 4);  /* 1111 */
+  WRITE_UINT32 (&bs, min_spatial_segmentation_idc, 12); /* min_spatial_segmentation_idc */
+  WRITE_UINT32 (&bs, 0x3f, 6);  /* 111111 */
+  WRITE_UINT32 (&bs, 0x00, 2);  /* parallelismType */
+  WRITE_UINT32 (&bs, 0x3f, 6);  /* 111111 */
+  WRITE_UINT32 (&bs, 0x01, 2);  /* chroma_format_idc */
+  WRITE_UINT32 (&bs, 0x1f, 5);  /* 11111 */
+  WRITE_UINT32 (&bs, 0x01, 3);  /* bit_depth_luma_minus8 */
+  WRITE_UINT32 (&bs, 0x1f, 5);  /* 11111 */
+  WRITE_UINT32 (&bs, 0x01, 3);  /* bit_depth_chroma_minus8 */
+  WRITE_UINT32 (&bs, 0x00, 16); /* avgFramerate */
+  WRITE_UINT32 (&bs, 0x00, 2);  /* constatnFramerate */
+  WRITE_UINT32 (&bs, 0x00, 3);  /* numTemporalLayers */
+  WRITE_UINT32 (&bs, 0x00, 1);  /* temporalIdNested */
+  WRITE_UINT32 (&bs, nal_length_size - 1, 2);   /* lengthSizeMinusOne */
+  WRITE_UINT32 (&bs, 0x00, 8);  /* numOfArrays */
+
+  WRITE_UINT32 (&bs, num_arrays, 8);    /* numOfArrays */
+
+  /* Write VPS */
+  WRITE_UINT32 (&bs, 0x00, 1);  /* array_completeness */
+  WRITE_UINT32 (&bs, 0x00, 1);  /* reserved zero */
+  WRITE_UINT32 (&bs, GST_H265_NAL_VPS, 6);      /* Nal_unit_type */
+  WRITE_UINT32 (&bs, 0x01, 16); /* numNalus, VPS count = 1 */
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  /* Write Nal unit length and data of VPS */
+  if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, vps_info.data, vps_info.size))
+    goto nal_to_byte_stream_error;
+
+  /* Write SPS */
+  WRITE_UINT32 (&bs, 0x00, 1);  /* array_completeness */
+  WRITE_UINT32 (&bs, 0x00, 1);  /* reserved zero */
+  WRITE_UINT32 (&bs, GST_H265_NAL_SPS, 6);      /* Nal_unit_type */
+  WRITE_UINT32 (&bs, 0x01, 16); /* numNalus, SPS count = 1 */
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&bs) % 8 == 0);
+  /* Write Nal unit length and data of SPS */
+  if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, sps_info.data, sps_info.size))
+    goto nal_to_byte_stream_error;
+
+  /* Write PPS */
+  WRITE_UINT32 (&bs, 0x00, 1);  /* array_completeness */
+  WRITE_UINT32 (&bs, 0x00, 1);  /* reserved zero */
+  WRITE_UINT32 (&bs, GST_H265_NAL_PPS, 6);      /* Nal_unit_type */
+  WRITE_UINT32 (&bs, 0x01, 16); /* numNalus, PPS count = 1 */
+  /* Write Nal unit length and data of PPS */
+  if (!gst_vaapi_utils_h26x_write_nal_unit (&bs, pps_info.data, pps_info.size))
+    goto nal_to_byte_stream_error;
+
+  gst_buffer_unmap (encoder->pps_data, &pps_info);
+  gst_buffer_unmap (encoder->sps_data, &sps_info);
+  gst_buffer_unmap (encoder->vps_data, &vps_info);
+
+  buffer = gst_bit_writer_reset_and_get_buffer (&bs);
+  if (!buffer)
+    goto error_alloc_buffer;
+  if (gst_buffer_n_memory (buffer) == 0) {
+    gst_buffer_unref (buffer);
+    goto error_alloc_buffer;
+  }
+  *out_buffer_ptr = buffer;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+bs_error:
+  {
+    GST_ERROR ("failed to write codec-data");
+    gst_buffer_unmap (encoder->vps_data, &vps_info);
+    gst_buffer_unmap (encoder->sps_data, &sps_info);
+    gst_buffer_unmap (encoder->pps_data, &pps_info);
+    gst_bit_writer_reset (&bs);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+nal_to_byte_stream_error:
+  {
+    GST_ERROR ("failed to write nal unit");
+    gst_buffer_unmap (encoder->vps_data, &vps_info);
+    gst_buffer_unmap (encoder->sps_data, &sps_info);
+    gst_buffer_unmap (encoder->pps_data, &pps_info);
+    gst_bit_writer_reset (&bs);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+error_map_vps_buffer:
+  {
+    GST_ERROR ("failed to map VPS packed header");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+error_map_sps_buffer:
+  {
+    GST_ERROR ("failed to map SPS packed header");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+error_map_pps_buffer:
+  {
+    GST_ERROR ("failed to map PPS packed header");
+    gst_buffer_unmap (encoder->sps_data, &sps_info);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+error_alloc_buffer:
+  {
+    GST_ERROR ("failed to allocate codec-data buffer");
+    gst_bit_writer_reset (&bs);
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+}
+
+/* TODO */
+/* The re-ordering algorithm is similar to what we implemented for
+ * h264 encoder. But We could have a better algorithm for hevc encoder
+ * by having B-frames as reference pictures */
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h265_reordering (GstVaapiEncoder * base_encoder,
+    GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
+{
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder);
+  GstVaapiH265ReorderPool *reorder_pool = NULL;
+  GstVaapiEncPicture *picture;
+  gboolean is_idr = FALSE;
+
+  *output = NULL;
+
+  reorder_pool = &encoder->reorder_pool;
+
+  if (!frame) {
+    if (reorder_pool->reorder_state != GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES)
+      return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
+
+    /* reorder_state = GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES
+       dump B frames from queue, sometime, there may also have P frame or I frame */
+    g_assert (encoder->num_bframes > 0);
+    g_return_val_if_fail (!g_queue_is_empty (&reorder_pool->reorder_frame_list),
+        GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN);
+    picture = g_queue_pop_head (&reorder_pool->reorder_frame_list);
+    g_assert (picture);
+    if (g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
+      reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES;
+    }
+    goto end;
+  }
+
+  /* new frame coming */
+  picture = GST_VAAPI_ENC_PICTURE_NEW (HEVC, encoder, frame);
+  if (!picture) {
+    GST_WARNING ("create H265 picture failed, frame timestamp:%"
+        GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  ++reorder_pool->cur_present_index;
+  picture->poc = ((reorder_pool->cur_present_index * 1) %
+      encoder->max_pic_order_cnt);
+
+  is_idr = (reorder_pool->frame_index == 0 ||
+      reorder_pool->frame_index >= encoder->idr_period);
+
+  /* check key frames */
+  if (is_idr || GST_VIDEO_CODEC_FRAME_IS_FORCE_KEYFRAME (frame) ||
+      (reorder_pool->frame_index %
+          GST_VAAPI_ENCODER_KEYFRAME_PERIOD (encoder)) == 0) {
+    ++reorder_pool->frame_index;
+
+    /* b frame enabled,  check queue of reorder_frame_list */
+    if (encoder->num_bframes
+        && !g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
+      GstVaapiEncPicture *p_pic;
+
+      p_pic = g_queue_pop_tail (&reorder_pool->reorder_frame_list);
+      set_p_frame (p_pic, encoder);
+      g_queue_foreach (&reorder_pool->reorder_frame_list,
+          (GFunc) set_b_frame, encoder);
+      set_key_frame (picture, encoder, is_idr);
+      g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
+      picture = p_pic;
+      reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES;
+    } else {                    /* no b frames in queue */
+      set_key_frame (picture, encoder, is_idr);
+      g_assert (g_queue_is_empty (&reorder_pool->reorder_frame_list));
+      if (encoder->num_bframes)
+        reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES;
+    }
+    goto end;
+  }
+
+  /* new p/b frames coming */
+  ++reorder_pool->frame_index;
+  if (reorder_pool->reorder_state == GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES &&
+      g_queue_get_length (&reorder_pool->reorder_frame_list) <
+      encoder->num_bframes) {
+    g_queue_push_tail (&reorder_pool->reorder_frame_list, picture);
+    return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
+  }
+
+  set_p_frame (picture, encoder);
+
+  if (reorder_pool->reorder_state == GST_VAAPI_ENC_H265_REORD_WAIT_FRAMES) {
+    g_queue_foreach (&reorder_pool->reorder_frame_list, (GFunc) set_b_frame,
+        encoder);
+    reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_DUMP_FRAMES;
+    g_assert (!g_queue_is_empty (&reorder_pool->reorder_frame_list));
+  }
+
+end:
+  g_assert (picture);
+  frame = picture->frame;
+  if (GST_CLOCK_TIME_IS_VALID (frame->pts))
+    frame->pts += encoder->cts_offset;
+  *output = picture;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+set_context_info (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder);
+  GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+  const guint DEFAULT_SURFACES_COUNT = 3;
+
+  /* FIXME: Using only a rough approximation for bitstream headers.
+   * Not taken into account: ScalingList, RefPicListModification,
+   * PredWeightTable */
+  /* Maximum sizes for common headers (in bits) */
+  enum
+  {
+    MAX_PROFILE_TIER_LEVEL_SIZE = 684,
+    MAX_VPS_HDR_SIZE = 13781,
+    MAX_SPS_HDR_SIZE = 615,
+    MAX_SHORT_TERM_REFPICSET_SIZE = 55,
+    MAX_VUI_PARAMS_SIZE = 267,
+    MAX_HRD_PARAMS_SIZE = 8196,
+    MAX_PPS_HDR_SIZE = 274,
+    MAX_SLICE_HDR_SIZE = 33660
+  };
+
+  /* Account for VPS header */
+  base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_VPS_HDR_SIZE +
+      MAX_PROFILE_TIER_LEVEL_SIZE + MAX_HRD_PARAMS_SIZE) / 8;
+
+  /* Account for SPS header */
+  base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_SPS_HDR_SIZE +
+      MAX_PROFILE_TIER_LEVEL_SIZE + 64 * MAX_SHORT_TERM_REFPICSET_SIZE +
+      MAX_VUI_PARAMS_SIZE + MAX_HRD_PARAMS_SIZE) / 8;
+
+  /* Account for PPS header */
+  base_encoder->codedbuf_size += 4 + GST_ROUND_UP_8 (MAX_PPS_HDR_SIZE) / 8;
+
+  /* Account for slice header */
+  base_encoder->codedbuf_size += encoder->num_slices * (4 +
+      GST_ROUND_UP_8 (MAX_SLICE_HDR_SIZE + MAX_SHORT_TERM_REFPICSET_SIZE) / 8);
+
+  GST_VAAPI_ENCODER_CAST (encoder)->profile = encoder->profile;
+
+  base_encoder->num_ref_frames = (encoder->num_ref_frames
+      + (encoder->num_bframes > 0 ? 1 : 0) + DEFAULT_SURFACES_COUNT);
+
+  /* Only YUV 4:2:0 formats are supported for now. */
+  base_encoder->codedbuf_size += GST_ROUND_UP_16 (vip->width) *
+      GST_ROUND_UP_16 (vip->height) * 3 / 2;
+
+  base_encoder->context_info.profile = base_encoder->profile;
+  base_encoder->context_info.entrypoint = encoder->entrypoint;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_h265_reconfigure (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (base_encoder);
+  GstVaapiEncoderStatus status;
+  guint luma_width, luma_height;
+
+  luma_width = GST_VAAPI_ENCODER_WIDTH (encoder);
+  luma_height = GST_VAAPI_ENCODER_HEIGHT (encoder);
+
+  if (luma_width != encoder->luma_width || luma_height != encoder->luma_height) {
+    GST_DEBUG ("resolution: %d %d", GST_VAAPI_ENCODER_WIDTH (encoder),
+        GST_VAAPI_ENCODER_HEIGHT (encoder));
+    encoder->luma_width = GST_ROUND_UP_16 (luma_width);
+    encoder->luma_height = GST_ROUND_UP_16 (luma_height);
+    encoder->config_changed = TRUE;
+    /* Frame Cropping */
+    if ((GST_VAAPI_ENCODER_WIDTH (encoder) & 15) ||
+        (GST_VAAPI_ENCODER_HEIGHT (encoder) & 15)) {
+      /* 6.1, Table 6-1 */
+      static const guint SubWidthC[] = { 1, 2, 2, 1 };
+      static const guint SubHeightC[] = { 1, 2, 1, 1 };
+      guint index = gst_vaapi_utils_h265_get_chroma_format_idc
+          (gst_vaapi_video_format_get_chroma_type (GST_VIDEO_INFO_FORMAT
+              (GST_VAAPI_ENCODER_VIDEO_INFO (encoder))));
+
+      encoder->conformance_window_flag = 1;
+      encoder->conf_win_left_offset = 0;
+      encoder->conf_win_right_offset =
+          (encoder->luma_width -
+          GST_VAAPI_ENCODER_WIDTH (encoder)) / SubWidthC[index];
+      encoder->conf_win_top_offset = 0;
+      encoder->conf_win_bottom_offset =
+          (encoder->luma_height -
+          GST_VAAPI_ENCODER_HEIGHT (encoder)) / SubHeightC[index];
+    }
+  }
+
+  status = ensure_profile_tier_level (encoder);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return status;
+
+  /* Set ctu size based on entrypoint. */
+  if (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP) {
+    encoder->ctu_width = (encoder->luma_width + 63) / 64;
+    encoder->ctu_height = (encoder->luma_height + 63) / 64;
+  } else {
+    encoder->ctu_width = (encoder->luma_width + 31) / 32;
+    encoder->ctu_height = (encoder->luma_height + 31) / 32;
+  }
+
+  status = reset_properties (encoder);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return status;
+
+  status = ensure_tile (encoder);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return status;
+  ensure_control_rate_params (encoder);
+  return set_context_info (base_encoder);
+}
+
+static void
+gst_vaapi_encoder_h265_init (GstVaapiEncoderH265 * encoder)
+{
+  GstVaapiH265ReorderPool *reorder_pool;
+  GstVaapiH265RefPool *ref_pool;
+
+  /* Default encoding entrypoint */
+  encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
+  encoder->tier = GST_VAAPI_TIER_H265_UNKNOWN;
+
+  encoder->conformance_window_flag = 0;
+  encoder->num_slices = 1;
+  encoder->no_p_frame = FALSE;
+
+  /* re-ordering  list initialize */
+  reorder_pool = &encoder->reorder_pool;
+  g_queue_init (&reorder_pool->reorder_frame_list);
+  reorder_pool->reorder_state = GST_VAAPI_ENC_H265_REORD_NONE;
+  reorder_pool->frame_index = 0;
+  reorder_pool->cur_present_index = 0;
+
+  /* reference list info initialize */
+  ref_pool = &encoder->ref_pool;
+  g_queue_init (&ref_pool->ref_list);
+  ref_pool->max_ref_frames = 0;
+  ref_pool->max_reflist0_count = 1;
+  ref_pool->max_reflist1_count = 1;
+
+  encoder->allowed_profiles = NULL;
+}
+
+struct _GstVaapiEncoderH265Class
+{
+  GstVaapiEncoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiEncoderH265, gst_vaapi_encoder_h265,
+    GST_TYPE_VAAPI_ENCODER);
+
+static void
+gst_vaapi_encoder_h265_finalize (GObject * object)
+{
+  /*free private buffers */
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (object);
+  GstVaapiEncPicture *pic;
+  GstVaapiEncoderH265Ref *ref;
+  GstVaapiH265RefPool *ref_pool;
+  GstVaapiH265ReorderPool *reorder_pool;
+
+  gst_buffer_replace (&encoder->vps_data, NULL);
+  gst_buffer_replace (&encoder->sps_data, NULL);
+  gst_buffer_replace (&encoder->pps_data, NULL);
+
+  /* reference list info de-init */
+  ref_pool = &encoder->ref_pool;
+  while (!g_queue_is_empty (&ref_pool->ref_list)) {
+    ref = (GstVaapiEncoderH265Ref *) g_queue_pop_head (&ref_pool->ref_list);
+    reference_pic_free (encoder, ref);
+  }
+  g_queue_clear (&ref_pool->ref_list);
+
+  /* re-ordering  list initialize */
+  reorder_pool = &encoder->reorder_pool;
+  while (!g_queue_is_empty (&reorder_pool->reorder_frame_list)) {
+    pic = (GstVaapiEncPicture *)
+        g_queue_pop_head (&reorder_pool->reorder_frame_list);
+    gst_vaapi_enc_picture_unref (pic);
+  }
+  g_queue_clear (&reorder_pool->reorder_frame_list);
+
+  reset_tile (encoder);
+
+  if (encoder->allowed_profiles)
+    g_array_unref (encoder->allowed_profiles);
+
+  G_OBJECT_CLASS (gst_vaapi_encoder_h265_parent_class)->finalize (object);
+}
+
+/**
+ * @ENCODER_H265_PROP_RATECONTROL: Rate control (#GstVaapiRateControl).
+ * @ENCODER_H265_PROP_TUNE: The tuning options (#GstVaapiEncoderTune).
+ * @ENCODER_H265_PROP_MAX_BFRAMES: Number of B-frames between I
+ *   and P (uint).
+ * @ENCODER_H265_PROP_INIT_QP: Initial quantizer value (uint).
+ * @ENCODER_H265_PROP_MIN_QP: Minimal quantizer value (uint).
+ * @ENCODER_H265_PROP_NUM_SLICES: Number of slices per frame (uint).
+ * @ENCODER_H265_PROP_NUM_REF_FRAMES: Maximum number of reference frames.
+ * @ENCODER_H265_PROP_CPB_LENGTH: Length of the CPB buffer
+ *   in milliseconds (uint).
+ * @ENCODER_H265_PROP_MBBRC: Macroblock level Bitrate Control.
+ * @ENCODER_H265_PROP_QP_IP: Difference of QP between I and P frame.
+ * @ENCODER_H265_PROP_QP_IB: Difference of QP between I and B frame.
+ * @ENCODER_H265_PROP_LOW_DELAY_B: use low delay b feature.
+ * @ENCODER_H265_PROP_MAX_QP: Maximal quantizer value (uint).
+ *
+ * The set of H.265 encoder specific configurable properties.
+ */
+enum
+{
+  ENCODER_H265_PROP_RATECONTROL = 1,
+  ENCODER_H265_PROP_TUNE,
+  ENCODER_H265_PROP_MAX_BFRAMES,
+  ENCODER_H265_PROP_INIT_QP,
+  ENCODER_H265_PROP_MIN_QP,
+  ENCODER_H265_PROP_NUM_SLICES,
+  ENCODER_H265_PROP_NUM_REF_FRAMES,
+  ENCODER_H265_PROP_CPB_LENGTH,
+  ENCODER_H265_PROP_MBBRC,
+  ENCODER_H265_PROP_QP_IP,
+  ENCODER_H265_PROP_QP_IB,
+#ifndef GST_REMOVE_DEPRECATED
+  ENCODER_H265_PROP_LOW_DELAY_B,
+#endif
+  ENCODER_H265_PROP_MAX_QP,
+  ENCODER_H265_PROP_QUALITY_FACTOR,
+  ENCODER_H265_PROP_NUM_TILE_COLS,
+  ENCODER_H265_PROP_NUM_TILE_ROWS,
+  ENCODER_H265_N_PROPERTIES
+};
+
+static GParamSpec *properties[ENCODER_H265_N_PROPERTIES];
+
+static void
+gst_vaapi_encoder_h265_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (object);
+
+  if (base_encoder->num_codedbuf_queued > 0) {
+    GST_ERROR_OBJECT (object,
+        "failed to set any property after encoding started");
+    return;
+  }
+
+  switch (prop_id) {
+    case ENCODER_H265_PROP_RATECONTROL:
+      gst_vaapi_encoder_set_rate_control (base_encoder,
+          g_value_get_enum (value));
+      break;
+    case ENCODER_H265_PROP_TUNE:
+      gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value));
+      break;
+    case ENCODER_H265_PROP_MAX_BFRAMES:
+      encoder->num_bframes = g_value_get_uint (value);
+      break;
+    case ENCODER_H265_PROP_INIT_QP:
+      encoder->init_qp = g_value_get_uint (value);
+      break;
+    case ENCODER_H265_PROP_MIN_QP:
+      encoder->min_qp = g_value_get_uint (value);
+      break;
+    case ENCODER_H265_PROP_QP_IP:
+      encoder->qp_ip = g_value_get_int (value);
+      break;
+    case ENCODER_H265_PROP_QP_IB:
+      encoder->qp_ib = g_value_get_int (value);
+      break;
+    case ENCODER_H265_PROP_NUM_SLICES:
+      encoder->num_slices = g_value_get_uint (value);
+      break;
+    case ENCODER_H265_PROP_CPB_LENGTH:
+      encoder->cpb_length = g_value_get_uint (value);
+      break;
+    case ENCODER_H265_PROP_NUM_REF_FRAMES:
+      encoder->num_ref_frames = g_value_get_uint (value);
+      break;
+    case ENCODER_H265_PROP_MBBRC:
+      encoder->mbbrc = g_value_get_enum (value);
+      break;
+#ifndef GST_REMOVE_DEPRECATED
+    case ENCODER_H265_PROP_LOW_DELAY_B:
+#if !VA_CHECK_VERSION(1,9,0)
+      encoder->no_p_frame = g_value_get_boolean (value);
+#else
+      if (g_value_get_boolean (value) == TRUE) {
+        GST_WARNING ("Deprecate low-delay-b property. Driver now already"
+            " has the ability to detect whether supporting P frames. this"
+            " value should not be set manually and will take no effect.");
+      }
+#endif
+      break;
+#endif
+    case ENCODER_H265_PROP_MAX_QP:
+      encoder->max_qp = g_value_get_uint (value);
+      break;
+    case ENCODER_H265_PROP_QUALITY_FACTOR:
+      encoder->quality_factor = g_value_get_uint (value);
+      break;
+    case ENCODER_H265_PROP_NUM_TILE_COLS:
+      encoder->num_tile_cols = g_value_get_uint (value);
+      break;
+    case ENCODER_H265_PROP_NUM_TILE_ROWS:
+      encoder->num_tile_rows = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_encoder_h265_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoderH265 *const encoder = GST_VAAPI_ENCODER_H265 (object);
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+
+  switch (prop_id) {
+    case ENCODER_H265_PROP_RATECONTROL:
+      g_value_set_enum (value, base_encoder->rate_control);
+      break;
+    case ENCODER_H265_PROP_TUNE:
+      g_value_set_enum (value, base_encoder->tune);
+      break;
+    case ENCODER_H265_PROP_MAX_BFRAMES:
+      g_value_set_uint (value, encoder->num_bframes);
+      break;
+    case ENCODER_H265_PROP_INIT_QP:
+      g_value_set_uint (value, encoder->init_qp);
+      break;
+    case ENCODER_H265_PROP_MIN_QP:
+      g_value_set_uint (value, encoder->min_qp);
+      break;
+    case ENCODER_H265_PROP_QP_IP:
+      g_value_set_int (value, encoder->qp_ip);
+      break;
+    case ENCODER_H265_PROP_QP_IB:
+      g_value_set_int (value, encoder->qp_ib);
+      break;
+    case ENCODER_H265_PROP_NUM_SLICES:
+      g_value_set_uint (value, encoder->num_slices);
+      break;
+    case ENCODER_H265_PROP_CPB_LENGTH:
+      g_value_set_uint (value, encoder->cpb_length);
+      break;
+    case ENCODER_H265_PROP_NUM_REF_FRAMES:
+      g_value_set_uint (value, encoder->num_ref_frames);
+      break;
+    case ENCODER_H265_PROP_MBBRC:
+      g_value_set_enum (value, encoder->mbbrc);
+      break;
+#ifndef GST_REMOVE_DEPRECATED
+    case ENCODER_H265_PROP_LOW_DELAY_B:
+      g_value_set_boolean (value, encoder->no_p_frame);
+      break;
+#endif
+    case ENCODER_H265_PROP_MAX_QP:
+      g_value_set_uint (value, encoder->max_qp);
+      break;
+    case ENCODER_H265_PROP_QUALITY_FACTOR:
+      g_value_set_uint (value, encoder->quality_factor);
+      break;
+    case ENCODER_H265_PROP_NUM_TILE_COLS:
+      g_value_set_uint (value, encoder->num_tile_cols);
+      break;
+    case ENCODER_H265_PROP_NUM_TILE_ROWS:
+      g_value_set_uint (value, encoder->num_tile_rows);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (H265);
+
+static void
+gst_vaapi_encoder_h265_class_init (GstVaapiEncoderH265Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass);
+
+  encoder_class->class_data = &g_class_data;
+  encoder_class->reconfigure = gst_vaapi_encoder_h265_reconfigure;
+  encoder_class->reordering = gst_vaapi_encoder_h265_reordering;
+  encoder_class->encode = gst_vaapi_encoder_h265_encode;
+  encoder_class->flush = gst_vaapi_encoder_h265_flush;
+  encoder_class->get_codec_data = gst_vaapi_encoder_h265_get_codec_data;
+  encoder_class->get_pending_reordered =
+      gst_vaapi_encoder_h265_get_pending_reordered;
+
+  object_class->set_property = gst_vaapi_encoder_h265_set_property;
+  object_class->get_property = gst_vaapi_encoder_h265_get_property;
+  object_class->finalize = gst_vaapi_encoder_h265_finalize;
+
+  /**
+   * GstVaapiEncoderH265:rate-control:
+   *
+   * The desired rate control mode, expressed as a #GstVaapiRateControl.
+   */
+  properties[ENCODER_H265_PROP_RATECONTROL] =
+      g_param_spec_enum ("rate-control",
+      "Rate Control", "Rate control mode",
+      g_class_data.rate_control_get_type (),
+      g_class_data.default_rate_control,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:tune:
+   *
+   * The desired encoder tuning option.
+   */
+  properties[ENCODER_H265_PROP_TUNE] =
+      g_param_spec_enum ("tune",
+      "Encoder Tuning",
+      "Encoder tuning option",
+      g_class_data.encoder_tune_get_type (),
+      g_class_data.default_encoder_tune,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:max-bframes:
+   *
+   * The number of B-frames between I and P.
+   */
+  properties[ENCODER_H265_PROP_MAX_BFRAMES] =
+      g_param_spec_uint ("max-bframes",
+      "Max B-Frames", "Number of B-frames between I and P", 0, 10, 0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:refs:
+   *
+   * The number of reference frames.
+   * If B frame is encoded, it will add 1 reference frame more.
+   */
+  properties[ENCODER_H265_PROP_NUM_REF_FRAMES] =
+      g_param_spec_uint ("refs",
+      "Number of Reference Frames", "Number of reference frames", 1, 3, 1,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:init-qp:
+   *
+   * The initial quantizer value.
+   */
+  properties[ENCODER_H265_PROP_INIT_QP] =
+      g_param_spec_uint ("init-qp",
+      "Initial QP", "Initial quantizer value", 0, 51, 26,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:min-qp:
+   *
+   * The minimum quantizer value.
+   */
+  properties[ENCODER_H265_PROP_MIN_QP] =
+      g_param_spec_uint ("min-qp",
+      "Minimum QP", "Minimum quantizer value", 0, 51, 1,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:max-qp:
+   *
+   * The maximum quantizer value.
+   *
+   * Since: 1.18
+   */
+  properties[ENCODER_H265_PROP_MAX_QP] =
+      g_param_spec_uint ("max-qp",
+      "Maximum QP", "Maximum quantizer value", 0, 51, 51,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:qp-ip:
+   *
+   * The difference of QP between I and P Frame.
+   * This is available only on CQP mode.
+   */
+  properties[ENCODER_H265_PROP_QP_IP] =
+      g_param_spec_int ("qp-ip",
+      "Difference of QP between I and P frame",
+      "Difference of QP between I and P frame (available only on CQP)",
+      -51, 51, 0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:qp-ib:
+   *
+   * The difference of QP between I and B Frame.
+   * This is available only on CQP mode.
+   */
+  properties[ENCODER_H265_PROP_QP_IB] =
+      g_param_spec_int ("qp-ib",
+      "Difference of QP between I and B frame",
+      "Difference of QP between I and B frame (available only on CQP)",
+      -51, 51, 0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /* FIXME: there seems to be issues with multi-slice encoding */
+  /**
+   * GstVaapiEncoderH265:num-slices:
+   *
+   * The number of slices per frame.
+   */
+  properties[ENCODER_H265_PROP_NUM_SLICES] =
+      g_param_spec_uint ("num-slices",
+      "Number of Slices",
+      "Number of slices per frame",
+      1, 200, 1,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:cpb-length:
+   *
+   * The size of the CPB buffer in milliseconds.
+   */
+  properties[ENCODER_H265_PROP_CPB_LENGTH] =
+      g_param_spec_uint ("cpb-length",
+      "CPB Length", "Length of the CPB buffer in milliseconds",
+      1, 10000, DEFAULT_CPB_LENGTH,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:mbbrc:
+   *
+   * Macroblock level bitrate control.
+   * This is not compatible with Constant QP rate control.
+   */
+  properties[ENCODER_H265_PROP_MBBRC] =
+      g_param_spec_enum ("mbbrc",
+      "Macroblock level Bitrate Control",
+      "Macroblock level Bitrate Control",
+      GST_VAAPI_TYPE_ENCODER_MBBRC, GST_VAAPI_ENCODER_MBBRC_AUTO,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+#ifndef GST_REMOVE_DEPRECATED
+  /**
+   * GstVaapiEncoderH265:low_delay_b:
+   *
+   * Enable low delay b frame, which will change P frame with B frame.
+   */
+  properties[ENCODER_H265_PROP_LOW_DELAY_B] =
+      g_param_spec_boolean ("low-delay-b",
+      "Enable low delay b",
+      "Transforms P frames into predictive B frames."
+      " Enable it when P frames are not supported.",
+      FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+#endif
+
+  /**
+   * GstVaapiEncoderH265:quality_factor:
+   *
+   * Quality factor used with ICQ/QVBR bitrate control mode.
+   */
+  properties[ENCODER_H265_PROP_QUALITY_FACTOR] =
+      g_param_spec_uint ("quality-factor",
+      "Quality factor for ICQ/QVBR",
+      "quality factor for ICQ/QBVR bitrate control mode"
+      " (lower value means higher quality, higher value means lower quality)",
+      1, 51, 26,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:num-tile-cols:
+   *
+   * The number of tile columns when tile encoding is enabled.
+   */
+  properties[ENCODER_H265_PROP_NUM_TILE_COLS] =
+      g_param_spec_uint ("num-tile-cols",
+      "number of tile columns",
+      "the number of columns for tile encoding", 1,
+      GST_VAAPI_H265_MAX_COL_TILES, 1,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderH265:num-tile-rows:
+   *
+   * The number of tile rows when tile encoding is enabled.
+   */
+  properties[ENCODER_H265_PROP_NUM_TILE_ROWS] =
+      g_param_spec_uint ("num-tile-rows",
+      "number of tile rows",
+      "the number of rows for tile encoding", 1,
+      GST_VAAPI_H265_MAX_ROW_TILES, 1,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  g_object_class_install_properties (object_class, ENCODER_H265_N_PROPERTIES,
+      properties);
+
+  gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0);
+  gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0);
+}
+
+/**
+ * gst_vaapi_encoder_h265_new:
+ * @display: a #GstVaapiDisplay
+ *
+ * Creates a new #GstVaapiEncoder for H.265 encoding. Note that the
+ * only supported output stream format is "byte-stream" format.
+ *
+ * Return value: the newly allocated #GstVaapiEncoder object
+ */
+GstVaapiEncoder *
+gst_vaapi_encoder_h265_new (GstVaapiDisplay * display)
+{
+  return g_object_new (GST_TYPE_VAAPI_ENCODER_H265, "display", display, NULL);
+}
+
+/**
+ * gst_vaapi_encoder_h265_set_allowed_profiles:
+ * @encoder: a #GstVaapiEncoderH265
+ * @profiles: a #GArray of all allowed #GstVaapiProfile.
+ *
+ * Set the all allowed profiles for the encoder.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_encoder_h265_set_allowed_profiles (GstVaapiEncoderH265 * encoder,
+    GArray * profiles)
+{
+  g_return_val_if_fail (encoder != NULL, FALSE);
+  g_return_val_if_fail (profiles, FALSE);
+
+  encoder->allowed_profiles = g_array_ref (profiles);
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_encoder_h265_get_profile_tier_level:
+ * @encoder: a #GstVaapiEncoderH265
+ * @out_profile_ptr: return location for the #GstVaapiProfile
+ * @out_level_ptr: return location for the #GstVaapiLevelH265
+ * @out_tier_ptr: return location for the #GstVaapiTierH265
+ *
+ * Queries the H.265 @encoder for the active profile and level. That
+ * information is only constructed and valid after the encoder is
+ * configured, i.e. after the gst_vaapi_encoder_set_codec_state()
+ * function is called.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_encoder_h265_get_profile_tier_level (GstVaapiEncoderH265 * encoder,
+    GstVaapiProfile * out_profile_ptr, GstVaapiTierH265 * out_tier_ptr,
+    GstVaapiLevelH265 * out_level_ptr)
+{
+  g_return_val_if_fail (encoder != NULL, FALSE);
+
+  if (!encoder->profile || encoder->tier == GST_VAAPI_TIER_H265_UNKNOWN
+      || !encoder->level)
+    return FALSE;
+
+  if (out_profile_ptr)
+    *out_profile_ptr = encoder->profile;
+  if (out_level_ptr)
+    *out_level_ptr = encoder->level;
+  if (out_tier_ptr)
+    *out_tier_ptr = encoder->tier;
+
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h265.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_h265.h
new file mode 100644 (file)
index 0000000..60da074
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *  gstvaapiencoder_h265.h - H.265 encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_H265_H
+#define GST_VAAPI_ENCODER_H265_H
+
+#include <gst/vaapi/gstvaapiencoder.h>
+#include <gst/vaapi/gstvaapiutils_h265.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_ENCODER_H265 \
+    (gst_vaapi_encoder_h265_get_type ())
+#define GST_VAAPI_ENCODER_H265(encoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_H265, GstVaapiEncoderH265))
+#define GST_IS_VAAPI_ENCODER_H265(encoder) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_H265))
+
+typedef struct _GstVaapiEncoderH265 GstVaapiEncoderH265;
+typedef struct _GstVaapiEncoderH265Class GstVaapiEncoderH265Class;
+
+GType
+gst_vaapi_encoder_h265_get_type (void) G_GNUC_CONST;
+
+GstVaapiEncoder *
+gst_vaapi_encoder_h265_new (GstVaapiDisplay * display);
+
+gboolean
+gst_vaapi_encoder_h265_set_allowed_profiles (GstVaapiEncoderH265 * encoder,
+    GArray * profiles);
+
+gboolean
+gst_vaapi_encoder_h265_get_profile_tier_level (GstVaapiEncoderH265 * encoder,
+    GstVaapiProfile * out_profile_ptr, GstVaapiTierH265 *out_tier_ptr, GstVaapiLevelH265 * out_level_ptr);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderH265, gst_object_unref)
+
+G_END_DECLS
+
+#endif /*GST_VAAPI_ENCODER_H265_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.c
new file mode 100644 (file)
index 0000000..00d1597
--- /dev/null
@@ -0,0 +1,914 @@
+/*
+ *  gstvaapiencoder_jpeg.c - JPEG encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <gst/base/gstbitwriter.h>
+#include <gst/codecparsers/gstjpegparser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiencoder_priv.h"
+#include "gstvaapiencoder_jpeg.h"
+#include "gstvaapicodedbufferproxy_priv.h"
+#include "gstvaapisurface.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/* Define default rate control mode ("constant-qp") */
+#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_NONE
+
+/* Supported set of VA rate controls, within this implementation */
+#define SUPPORTED_RATECONTROLS                  \
+  (GST_VAAPI_RATECONTROL_MASK (NONE))
+
+/* Supported set of tuning options, within this implementation */
+#define SUPPORTED_TUNE_OPTIONS \
+  (GST_VAAPI_ENCODER_TUNE_MASK (NONE))
+
+/* Supported set of VA packed headers, within this implementation */
+#define SUPPORTED_PACKED_HEADERS                \
+  (VA_ENC_PACKED_HEADER_RAW_DATA)
+
+#define NUM_DC_RUN_SIZE_BITS 16
+#define NUM_AC_RUN_SIZE_BITS 16
+#define NUM_AC_CODE_WORDS_HUFFVAL 162
+#define NUM_DC_CODE_WORDS_HUFFVAL 12
+
+/* ------------------------------------------------------------------------- */
+/* --- JPEG Encoder                                                      --- */
+/* ------------------------------------------------------------------------- */
+
+struct _GstVaapiEncoderJpeg
+{
+  GstVaapiEncoder parent_instance;
+  GstVaapiProfile profile;
+  guint quality;
+  GstJpegQuantTables quant_tables;
+  GstJpegQuantTables scaled_quant_tables;
+  gboolean has_quant_tables;
+  GstJpegHuffmanTables huff_tables;
+  gboolean has_huff_tables;
+  gint cwidth[GST_VIDEO_MAX_COMPONENTS];
+  gint cheight[GST_VIDEO_MAX_COMPONENTS];
+  gint h_samp[GST_VIDEO_MAX_COMPONENTS];
+  gint v_samp[GST_VIDEO_MAX_COMPONENTS];
+  gint h_max_samp;
+  gint v_max_samp;
+  guint n_components;
+};
+
+/* based on upstream gst-plugins-good jpegencoder */
+static void
+generate_sampling_factors (GstVaapiEncoderJpeg * encoder)
+{
+  GstVideoInfo *vinfo;
+  gint i;
+
+  vinfo = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+
+  if (GST_VIDEO_INFO_FORMAT (vinfo) == GST_VIDEO_FORMAT_ENCODED) {
+    /* Use native I420 format */
+    encoder->n_components = 3;
+    for (i = 0; i < encoder->n_components; ++i) {
+      if (i == 0)
+        encoder->h_samp[i] = encoder->v_samp[i] = 2;
+      else
+        encoder->h_samp[i] = encoder->v_samp[i] = 1;
+      GST_DEBUG ("sampling factors: %d %d", encoder->h_samp[i],
+          encoder->v_samp[i]);
+    }
+    return;
+  }
+
+  encoder->n_components = GST_VIDEO_INFO_N_COMPONENTS (vinfo);
+
+  encoder->h_max_samp = 0;
+  encoder->v_max_samp = 0;
+  for (i = 0; i < encoder->n_components; ++i) {
+    encoder->cwidth[i] = GST_VIDEO_INFO_COMP_WIDTH (vinfo, i);
+    encoder->cheight[i] = GST_VIDEO_INFO_COMP_HEIGHT (vinfo, i);
+    encoder->h_samp[i] =
+        GST_ROUND_UP_4 (GST_VIDEO_INFO_WIDTH (vinfo)) / encoder->cwidth[i];
+    encoder->h_max_samp = MAX (encoder->h_max_samp, encoder->h_samp[i]);
+    encoder->v_samp[i] =
+        GST_ROUND_UP_4 (GST_VIDEO_INFO_HEIGHT (vinfo)) / encoder->cheight[i];
+    encoder->v_max_samp = MAX (encoder->v_max_samp, encoder->v_samp[i]);
+  }
+  /* samp should only be 1, 2 or 4 */
+  g_assert (encoder->h_max_samp <= 4);
+  g_assert (encoder->v_max_samp <= 4);
+
+  /* now invert */
+  /* maximum is invariant, as one of the components should have samp 1 */
+  for (i = 0; i < encoder->n_components; ++i) {
+    encoder->h_samp[i] = encoder->h_max_samp / encoder->h_samp[i];
+    encoder->v_samp[i] = encoder->v_max_samp / encoder->v_samp[i];
+    GST_DEBUG ("sampling factors: %d %d", encoder->h_samp[i],
+        encoder->v_samp[i]);
+  }
+}
+
+/* Derives the profile that suits best to the configuration */
+static GstVaapiEncoderStatus
+ensure_profile (GstVaapiEncoderJpeg * encoder)
+{
+  /* Always start from "simple" profile for maximum compatibility */
+  encoder->profile = GST_VAAPI_PROFILE_JPEG_BASELINE;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+/* Derives the profile supported by the underlying hardware */
+static gboolean
+ensure_hw_profile (GstVaapiEncoderJpeg * encoder)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+  GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE;
+  GstVaapiProfile profile, profiles[2];
+  guint i, num_profiles = 0;
+
+  profiles[num_profiles++] = encoder->profile;
+
+  profile = GST_VAAPI_PROFILE_UNKNOWN;
+  for (i = 0; i < num_profiles; i++) {
+    if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
+      profile = profiles[i];
+      break;
+    }
+  }
+  if (profile == GST_VAAPI_PROFILE_UNKNOWN)
+    goto error_unsupported_profile;
+
+  GST_VAAPI_ENCODER_CAST (encoder)->profile = profile;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_profile:
+  {
+    GST_ERROR ("unsupported HW profile %s",
+        gst_vaapi_profile_get_va_name (encoder->profile));
+    return FALSE;
+  }
+}
+
+static GstVaapiEncoderStatus
+set_context_info (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderJpeg *encoder = GST_VAAPI_ENCODER_JPEG (base_encoder);
+  GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+
+  /* Maximum sizes for common headers (in bytes) */
+  enum
+  {
+    MAX_APP_HDR_SIZE = 20,
+    MAX_FRAME_HDR_SIZE = 19,
+    MAX_QUANT_TABLE_SIZE = 138,
+    MAX_HUFFMAN_TABLE_SIZE = 432,
+    MAX_SCAN_HDR_SIZE = 14
+  };
+
+  if (!ensure_hw_profile (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  base_encoder->num_ref_frames = 0;
+
+  /* Only YUV 4:2:0 formats are supported for now. */
+  base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) *
+      GST_ROUND_UP_16 (vip->height) * 3 / 2;
+
+  base_encoder->codedbuf_size += MAX_APP_HDR_SIZE + MAX_FRAME_HDR_SIZE +
+      MAX_QUANT_TABLE_SIZE + MAX_HUFFMAN_TABLE_SIZE + MAX_SCAN_HDR_SIZE;
+
+  base_encoder->context_info.profile = base_encoder->profile;
+  base_encoder->context_info.entrypoint = GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static gboolean
+fill_picture (GstVaapiEncoderJpeg * encoder,
+    GstVaapiEncPicture * picture,
+    GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
+{
+  guint i;
+  VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
+
+  memset (pic_param, 0, sizeof (VAEncPictureParameterBufferJPEG));
+
+  pic_param->reconstructed_picture =
+      GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
+  pic_param->picture_width = GST_VAAPI_ENCODER_WIDTH (encoder);
+  pic_param->picture_height = GST_VAAPI_ENCODER_HEIGHT (encoder);
+  pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf);
+
+  pic_param->pic_flags.bits.profile = 0;        /* Profile = Baseline */
+  pic_param->pic_flags.bits.progressive = 0;    /* Sequential encoding */
+  pic_param->pic_flags.bits.huffman = 1;        /* Uses Huffman coding */
+  pic_param->pic_flags.bits.interleaved = 0;    /* Input format is non interleaved (YUV) */
+  pic_param->pic_flags.bits.differential = 0;   /* non-Differential Encoding */
+  pic_param->sample_bit_depth = 8;
+  pic_param->num_scan = 1;
+  pic_param->num_components = encoder->n_components;
+  pic_param->quality = encoder->quality;
+  for (i = 0; i < pic_param->num_components; i++) {
+    pic_param->component_id[i] = i + 1;
+    if (i != 0)
+      pic_param->quantiser_table_selector[i] = 1;
+  }
+  return TRUE;
+}
+
+static gboolean
+ensure_picture (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture,
+    GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiCodedBuffer *const codedbuf =
+      GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
+
+  if (!fill_picture (encoder, picture, codedbuf, surface))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* This is a work-around: Normalize the quality factor and scale QM
+ * values similar to what VA-Intel driver is doing. Otherwise the
+ * generated packed headers will be wrong, since the driver itself
+ * is scaling the QM values using the normalized quality factor */
+static void
+generate_scaled_qm (GstJpegQuantTables * quant_tables,
+    GstJpegQuantTables * scaled_quant_tables, guint quality, guint shift)
+{
+  guint qt_val, nm_quality, i;
+  nm_quality = quality == 0 ? 1 : quality;
+  nm_quality =
+      (nm_quality < 50) ? (5000 / nm_quality) : (200 - (nm_quality * 2));
+
+  g_assert (quant_tables != NULL);
+  g_assert (scaled_quant_tables != NULL);
+
+  for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
+    /* Luma QM */
+    qt_val =
+        (quant_tables->quant_tables[0].quant_table[i] * nm_quality +
+        shift) / 100;
+    scaled_quant_tables->quant_tables[0].quant_table[i] =
+        CLAMP (qt_val, 1, 255);
+    /* Chroma QM */
+    qt_val =
+        (quant_tables->quant_tables[1].quant_table[i] * nm_quality +
+        shift) / 100;
+    scaled_quant_tables->quant_tables[1].quant_table[i] =
+        CLAMP (qt_val, 1, 255);
+  }
+}
+
+static gboolean
+fill_quantization_table (GstVaapiEncoderJpeg * encoder,
+    GstVaapiEncPicture * picture)
+{
+  VAQMatrixBufferJPEG *q_matrix;
+  int i;
+
+  g_assert (picture);
+
+  picture->q_matrix = GST_VAAPI_ENC_Q_MATRIX_NEW (JPEG, encoder);
+  if (!picture->q_matrix) {
+    GST_ERROR ("failed to allocate quantiser table");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  q_matrix = picture->q_matrix->param;
+
+  if (!encoder->has_quant_tables) {
+    GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+    guint shift = 0;
+
+    if (gst_vaapi_display_has_driver_quirks (display,
+            GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50))
+      shift = 50;
+
+    gst_jpeg_get_default_quantization_tables (&encoder->quant_tables);
+    encoder->has_quant_tables = TRUE;
+    generate_scaled_qm (&encoder->quant_tables, &encoder->scaled_quant_tables,
+        encoder->quality, shift);
+  }
+  q_matrix->load_lum_quantiser_matrix = 1;
+  for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
+    q_matrix->lum_quantiser_matrix[i] =
+        encoder->quant_tables.quant_tables[0].quant_table[i];
+  }
+
+  q_matrix->load_chroma_quantiser_matrix = 1;
+  for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
+    q_matrix->chroma_quantiser_matrix[i] =
+        encoder->quant_tables.quant_tables[1].quant_table[i];
+  }
+
+  return TRUE;
+}
+
+static gboolean
+ensure_quantization_table (GstVaapiEncoderJpeg * encoder,
+    GstVaapiEncPicture * picture)
+{
+  g_assert (picture);
+
+  if (!fill_quantization_table (encoder, picture))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+fill_huffman_table (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
+{
+  VAHuffmanTableBufferJPEGBaseline *huffman_table;
+  guint i, num_tables;
+
+  g_assert (picture);
+
+  picture->huf_table = GST_VAAPI_ENC_HUFFMAN_TABLE_NEW (JPEGBaseline, encoder);
+  if (!picture->huf_table) {
+    GST_ERROR ("failed to allocate Huffman tables");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+  huffman_table = picture->huf_table->param;
+
+  num_tables = MIN (G_N_ELEMENTS (huffman_table->huffman_table),
+      GST_JPEG_MAX_SCAN_COMPONENTS);
+
+  if (!encoder->has_huff_tables) {
+    gst_jpeg_get_default_huffman_tables (&encoder->huff_tables);
+    encoder->has_huff_tables = TRUE;
+  }
+
+  for (i = 0; i < num_tables; i++) {
+    huffman_table->load_huffman_table[i] =
+        encoder->huff_tables.dc_tables[i].valid
+        && encoder->huff_tables.ac_tables[i].valid;
+    if (!huffman_table->load_huffman_table[i])
+      continue;
+
+    memcpy (huffman_table->huffman_table[i].num_dc_codes,
+        encoder->huff_tables.dc_tables[i].huf_bits,
+        sizeof (huffman_table->huffman_table[i].num_dc_codes));
+    memcpy (huffman_table->huffman_table[i].dc_values,
+        encoder->huff_tables.dc_tables[i].huf_values,
+        sizeof (huffman_table->huffman_table[i].dc_values));
+    memcpy (huffman_table->huffman_table[i].num_ac_codes,
+        encoder->huff_tables.ac_tables[i].huf_bits,
+        sizeof (huffman_table->huffman_table[i].num_ac_codes));
+    memcpy (huffman_table->huffman_table[i].ac_values,
+        encoder->huff_tables.ac_tables[i].huf_values,
+        sizeof (huffman_table->huffman_table[i].ac_values));
+    memset (huffman_table->huffman_table[i].pad,
+        0, sizeof (huffman_table->huffman_table[i].pad));
+  }
+
+  return TRUE;
+}
+
+static gboolean
+ensure_huffman_table (GstVaapiEncoderJpeg * encoder,
+    GstVaapiEncPicture * picture)
+{
+  g_assert (picture);
+
+  if (!fill_huffman_table (encoder, picture))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+fill_slices (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
+{
+  VAEncSliceParameterBufferJPEG *slice_param;
+  GstVaapiEncSlice *slice;
+  VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
+
+  slice = GST_VAAPI_ENC_SLICE_NEW (JPEG, encoder);
+  g_assert (slice && slice->param_id != VA_INVALID_ID);
+  slice_param = slice->param;
+
+  memset (slice_param, 0, sizeof (VAEncSliceParameterBufferJPEG));
+
+  slice_param->restart_interval = 0;
+  slice_param->num_components = pic_param->num_components;
+
+  slice_param->components[0].component_selector = 1;
+  slice_param->components[0].dc_table_selector = 0;
+  slice_param->components[0].ac_table_selector = 0;
+
+  slice_param->components[1].component_selector = 2;
+  slice_param->components[1].dc_table_selector = 1;
+  slice_param->components[1].ac_table_selector = 1;
+
+  slice_param->components[2].component_selector = 3;
+  slice_param->components[2].dc_table_selector = 1;
+  slice_param->components[2].ac_table_selector = 1;
+
+  gst_vaapi_enc_picture_add_slice (picture, slice);
+  gst_vaapi_codec_object_replace (&slice, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+ensure_slices (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
+{
+  g_assert (picture);
+
+  if (!fill_slices (encoder, picture))
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+generate_frame_hdr (GstJpegFrameHdr * frame_hdr, GstVaapiEncoderJpeg * encoder,
+    GstVaapiEncPicture * picture)
+{
+  VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
+  guint i;
+
+  memset (frame_hdr, 0, sizeof (GstJpegFrameHdr));
+  frame_hdr->sample_precision = 8;
+  frame_hdr->width = pic_param->picture_width;
+  frame_hdr->height = pic_param->picture_height;
+  frame_hdr->num_components = pic_param->num_components;
+
+  for (i = 0; i < frame_hdr->num_components; i++) {
+    frame_hdr->components[i].identifier = pic_param->component_id[i];
+    frame_hdr->components[i].horizontal_factor = encoder->h_samp[i];
+    frame_hdr->components[i].vertical_factor = encoder->v_samp[i];
+    frame_hdr->components[i].quant_table_selector =
+        pic_param->quantiser_table_selector[i];
+  }
+}
+
+static void
+generate_scan_hdr (GstJpegScanHdr * scan_hdr, GstVaapiEncPicture * picture)
+{
+
+  VAEncPictureParameterBufferJPEG *const pic_param = picture->param;
+
+  memset (scan_hdr, 0, sizeof (GstJpegScanHdr));
+  scan_hdr->num_components = pic_param->num_components;
+  //Y Component
+  scan_hdr->components[0].component_selector = 1;
+  scan_hdr->components[0].dc_selector = 0;
+  scan_hdr->components[0].ac_selector = 0;
+
+
+  //U Component
+  scan_hdr->components[1].component_selector = 2;
+  scan_hdr->components[1].dc_selector = 1;
+  scan_hdr->components[1].ac_selector = 1;
+
+  //V Component
+  scan_hdr->components[2].component_selector = 3;
+  scan_hdr->components[2].dc_selector = 1;
+  scan_hdr->components[2].ac_selector = 1;
+}
+
+static gboolean
+bs_write_jpeg_header (GstBitWriter * bs, GstVaapiEncoderJpeg * encoder,
+    GstVaapiEncPicture * picture)
+{
+  GstJpegFrameHdr frame_hdr;
+  GstJpegScanHdr scan_hdr;
+  guint i, j;
+
+  gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
+  gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOI, 8);
+  gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
+  gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_APP_MIN, 8);
+  gst_bit_writer_put_bits_uint16 (bs, 16, 16);
+  gst_bit_writer_put_bits_uint8 (bs, 0x4A, 8);  //J
+  gst_bit_writer_put_bits_uint8 (bs, 0x46, 8);  //F
+  gst_bit_writer_put_bits_uint8 (bs, 0x49, 8);  //I
+  gst_bit_writer_put_bits_uint8 (bs, 0x46, 8);  //F
+  gst_bit_writer_put_bits_uint8 (bs, 0x00, 8);  //0
+  gst_bit_writer_put_bits_uint8 (bs, 1, 8);     //Major Version
+  gst_bit_writer_put_bits_uint8 (bs, 1, 8);     //Minor Version
+  gst_bit_writer_put_bits_uint8 (bs, 0, 8);     //Density units 0:no units, 1:pixels per inch, 2: pixels per cm
+  gst_bit_writer_put_bits_uint16 (bs, 1, 16);   //X density (pixel-aspect-ratio)
+  gst_bit_writer_put_bits_uint16 (bs, 1, 16);   //Y density (pixel-aspect-ratio)
+  gst_bit_writer_put_bits_uint8 (bs, 0, 8);     //Thumbnail width
+  gst_bit_writer_put_bits_uint8 (bs, 0, 8);     //Thumbnail height
+
+  /* Add  quantization table */
+  if (!encoder->has_quant_tables) {
+    GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+    guint shift = 0;
+
+    if (gst_vaapi_display_has_driver_quirks (display,
+            GST_VAAPI_DRIVER_QUIRK_JPEG_ENC_SHIFT_VALUE_BY_50))
+      shift = 50;
+
+    gst_jpeg_get_default_quantization_tables (&encoder->quant_tables);
+    generate_scaled_qm (&encoder->quant_tables, &encoder->scaled_quant_tables,
+        encoder->quality, shift);
+    encoder->has_quant_tables = TRUE;
+  }
+
+  gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
+  gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DQT, 8);
+  gst_bit_writer_put_bits_uint16 (bs, 3 + GST_JPEG_MAX_QUANT_ELEMENTS, 16);     //Lq
+  gst_bit_writer_put_bits_uint8 (bs, encoder->quant_tables.quant_tables[0].quant_precision, 4); //Pq
+  gst_bit_writer_put_bits_uint8 (bs, 0, 4);     //Tq
+  for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
+    gst_bit_writer_put_bits_uint16 (bs,
+        encoder->scaled_quant_tables.quant_tables[0].quant_table[i], 8);
+  }
+  gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
+  gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DQT, 8);
+  gst_bit_writer_put_bits_uint16 (bs, 3 + GST_JPEG_MAX_QUANT_ELEMENTS, 16);     //Lq
+  gst_bit_writer_put_bits_uint8 (bs, encoder->quant_tables.quant_tables[1].quant_precision, 4); //Pq
+  gst_bit_writer_put_bits_uint8 (bs, 1, 4);     //Tq
+  for (i = 0; i < GST_JPEG_MAX_QUANT_ELEMENTS; i++) {
+    gst_bit_writer_put_bits_uint16 (bs,
+        encoder->scaled_quant_tables.quant_tables[1].quant_table[i], 8);
+  }
+
+  /*Add frame header */
+  generate_frame_hdr (&frame_hdr, encoder, picture);
+  gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
+  gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOF_MIN, 8);
+  gst_bit_writer_put_bits_uint16 (bs, 8 + (3 * 3), 16); //lf, Size of FrameHeader in bytes without the Marker SOF
+  gst_bit_writer_put_bits_uint8 (bs, frame_hdr.sample_precision, 8);
+  gst_bit_writer_put_bits_uint16 (bs, frame_hdr.height, 16);
+  gst_bit_writer_put_bits_uint16 (bs, frame_hdr.width, 16);
+  gst_bit_writer_put_bits_uint8 (bs, frame_hdr.num_components, 8);
+  for (i = 0; i < frame_hdr.num_components; i++) {
+    gst_bit_writer_put_bits_uint8 (bs, frame_hdr.components[i].identifier, 8);
+    gst_bit_writer_put_bits_uint8 (bs,
+        frame_hdr.components[i].horizontal_factor, 4);
+    gst_bit_writer_put_bits_uint8 (bs, frame_hdr.components[i].vertical_factor,
+        4);
+    gst_bit_writer_put_bits_uint8 (bs,
+        frame_hdr.components[i].quant_table_selector, 8);
+  }
+
+  /* Add Huffman table */
+  if (!encoder->has_huff_tables) {
+    gst_jpeg_get_default_huffman_tables (&encoder->huff_tables);
+    encoder->has_huff_tables = TRUE;
+  }
+  for (i = 0; i < 2; i++) {
+    gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
+    gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DHT, 8);
+    gst_bit_writer_put_bits_uint16 (bs, 0x1F, 16);      //length of table
+    gst_bit_writer_put_bits_uint8 (bs, 0, 4);
+    gst_bit_writer_put_bits_uint8 (bs, i, 4);
+    for (j = 0; j < NUM_DC_RUN_SIZE_BITS; j++) {
+      gst_bit_writer_put_bits_uint8 (bs,
+          encoder->huff_tables.dc_tables[i].huf_bits[j], 8);
+    }
+
+    for (j = 0; j < NUM_DC_CODE_WORDS_HUFFVAL; j++) {
+      gst_bit_writer_put_bits_uint8 (bs,
+          encoder->huff_tables.dc_tables[i].huf_values[j], 8);
+    }
+
+    gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
+    gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_DHT, 8);
+    gst_bit_writer_put_bits_uint16 (bs, 0xB5, 16);      //length of table
+    gst_bit_writer_put_bits_uint8 (bs, 1, 4);
+    gst_bit_writer_put_bits_uint8 (bs, i, 4);
+    for (j = 0; j < NUM_AC_RUN_SIZE_BITS; j++) {
+      gst_bit_writer_put_bits_uint8 (bs,
+          encoder->huff_tables.ac_tables[i].huf_bits[j], 8);
+    }
+
+    for (j = 0; j < NUM_AC_CODE_WORDS_HUFFVAL; j++) {
+      gst_bit_writer_put_bits_uint8 (bs,
+          encoder->huff_tables.ac_tables[i].huf_values[j], 8);
+    }
+  }
+
+  /* Add ScanHeader */
+  generate_scan_hdr (&scan_hdr, picture);
+  gst_bit_writer_put_bits_uint8 (bs, 0xFF, 8);
+  gst_bit_writer_put_bits_uint8 (bs, GST_JPEG_MARKER_SOS, 8);
+  gst_bit_writer_put_bits_uint16 (bs, 12, 16);  //Length of Scan
+  gst_bit_writer_put_bits_uint8 (bs, scan_hdr.num_components, 8);
+
+  for (i = 0; i < scan_hdr.num_components; i++) {
+    gst_bit_writer_put_bits_uint8 (bs,
+        scan_hdr.components[i].component_selector, 8);
+    gst_bit_writer_put_bits_uint8 (bs, scan_hdr.components[i].dc_selector, 4);
+    gst_bit_writer_put_bits_uint8 (bs, scan_hdr.components[i].ac_selector, 4);
+  }
+  gst_bit_writer_put_bits_uint8 (bs, 0, 8);     //0 for Baseline
+  gst_bit_writer_put_bits_uint8 (bs, 63, 8);    //63 for Baseline
+  gst_bit_writer_put_bits_uint8 (bs, 0, 4);     //0 for Baseline
+  gst_bit_writer_put_bits_uint8 (bs, 0, 4);     //0 for Baseline
+
+  return TRUE;
+}
+
+static gboolean
+add_packed_header (GstVaapiEncoderJpeg * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncPackedHeader *packed_raw_data_hdr;
+  GstBitWriter bs;
+  VAEncPackedHeaderParameterBuffer packed_raw_data_hdr_param = { 0 };
+  guint32 data_bit_size;
+  guint8 *data;
+
+  gst_bit_writer_init_with_size (&bs, 128, FALSE);
+  bs_write_jpeg_header (&bs, encoder, picture);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&bs);
+  data = GST_BIT_WRITER_DATA (&bs);
+
+  packed_raw_data_hdr_param.type = VAEncPackedHeaderRawData;
+  packed_raw_data_hdr_param.bit_length = data_bit_size;
+  packed_raw_data_hdr_param.has_emulation_bytes = 0;
+
+  packed_raw_data_hdr =
+      gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_raw_data_hdr_param, sizeof (packed_raw_data_hdr_param), data,
+      (data_bit_size + 7) / 8);
+  g_assert (packed_raw_data_hdr);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_raw_data_hdr);
+  gst_vaapi_codec_object_replace (&packed_raw_data_hdr, NULL);
+
+  gst_bit_writer_reset (&bs);
+
+  return TRUE;
+}
+
+static gboolean
+ensure_packed_headers (GstVaapiEncoderJpeg * encoder,
+    GstVaapiEncPicture * picture)
+{
+  g_assert (picture);
+
+  if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+          VA_ENC_PACKED_HEADER_RAW_DATA)
+      && !add_packed_header (encoder, picture))
+    goto error_create_packed_hdr;
+
+  return TRUE;
+
+  /* ERRORS */
+error_create_packed_hdr:
+  {
+    GST_ERROR ("failed to create packed raw data header buffer");
+    return FALSE;
+  }
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_jpeg_encode (GstVaapiEncoder * base_encoder,
+    GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
+{
+  GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (base_encoder);
+  GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  GstVaapiSurfaceProxy *reconstruct = NULL;
+
+  reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
+
+  g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
+
+  if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
+    goto error;
+  if (!ensure_quantization_table (encoder, picture))
+    goto error;
+  if (!ensure_huffman_table (encoder, picture))
+    goto error;
+  if (!ensure_slices (encoder, picture))
+    goto error;
+  if (!ensure_packed_headers (encoder, picture))
+    goto error;
+  if (!gst_vaapi_enc_picture_encode (picture))
+    goto error;
+  if (reconstruct)
+    gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
+        reconstruct);
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    if (reconstruct)
+      gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
+          reconstruct);
+    return ret;
+  }
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_jpeg_flush (GstVaapiEncoder * base_encoder)
+{
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_jpeg_reordering (GstVaapiEncoder * base_encoder,
+    GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
+{
+  GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (base_encoder);
+  GstVaapiEncPicture *picture = NULL;
+  GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  if (!frame)
+    return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
+
+  picture = GST_VAAPI_ENC_PICTURE_NEW (JPEG, encoder, frame);
+  if (!picture) {
+    GST_WARNING ("create JPEG picture failed, frame timestamp:%"
+        GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  *output = picture;
+  return status;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_jpeg_reconfigure (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (base_encoder);
+  GstVaapiEncoderStatus status;
+
+  status = ensure_profile (encoder);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return status;
+
+  /* generate sampling factors (A.1.1) */
+  generate_sampling_factors (encoder);
+
+  return set_context_info (base_encoder);
+}
+
+struct _GstVaapiEncoderJpegClass
+{
+  GstVaapiEncoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiEncoderJpeg, gst_vaapi_encoder_jpeg,
+    GST_TYPE_VAAPI_ENCODER);
+
+static void
+gst_vaapi_encoder_jpeg_init (GstVaapiEncoderJpeg * encoder)
+{
+  encoder->has_quant_tables = FALSE;
+  memset (&encoder->quant_tables, 0, sizeof (encoder->quant_tables));
+  memset (&encoder->scaled_quant_tables, 0,
+      sizeof (encoder->scaled_quant_tables));
+  encoder->has_huff_tables = FALSE;
+  memset (&encoder->huff_tables, 0, sizeof (encoder->huff_tables));
+}
+
+/**
+ * @ENCODER_JPEG_PROP_RATECONTROL: Rate control (#GstVaapiRateControl).
+ * @ENCODER_JPEG_PROP_TUNE: The tuning options (#GstVaapiEncoderTune).
+ * @ENCODER_JPEG_PROP_QUALITY: Quality Factor value (uint).
+ *
+ * The set of JPEG encoder specific configurable properties.
+ */
+enum
+{
+  ENCODER_JPEG_PROP_RATECONTROL = 1,
+  ENCODER_JPEG_PROP_TUNE,
+  ENCODER_JPEG_PROP_QUALITY,
+  ENCODER_JPEG_N_PROPERTIES
+};
+
+static GParamSpec *properties[ENCODER_JPEG_N_PROPERTIES];
+
+static void
+gst_vaapi_encoder_jpeg_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+  GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (object);
+
+  if (base_encoder->num_codedbuf_queued > 0) {
+    GST_ERROR_OBJECT (object,
+        "failed to set any property after encoding started");
+    return;
+  }
+
+  switch (prop_id) {
+    case ENCODER_JPEG_PROP_RATECONTROL:
+      gst_vaapi_encoder_set_rate_control (base_encoder,
+          g_value_get_enum (value));
+      break;
+    case ENCODER_JPEG_PROP_TUNE:
+      gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value));
+      break;
+    case ENCODER_JPEG_PROP_QUALITY:
+      encoder->quality = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_encoder_jpeg_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoderJpeg *const encoder = GST_VAAPI_ENCODER_JPEG (object);
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+
+  switch (prop_id) {
+    case ENCODER_JPEG_PROP_RATECONTROL:
+      g_value_set_enum (value, base_encoder->rate_control);
+      break;
+    case ENCODER_JPEG_PROP_TUNE:
+      g_value_set_enum (value, base_encoder->tune);
+      break;
+    case ENCODER_JPEG_PROP_QUALITY:
+      g_value_set_uint (value, encoder->quality);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (JPEG);
+
+static void
+gst_vaapi_encoder_jpeg_class_init (GstVaapiEncoderJpegClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass);
+
+  encoder_class->class_data = &g_class_data;
+  encoder_class->reconfigure = gst_vaapi_encoder_jpeg_reconfigure;
+  encoder_class->reordering = gst_vaapi_encoder_jpeg_reordering;
+  encoder_class->encode = gst_vaapi_encoder_jpeg_encode;
+  encoder_class->flush = gst_vaapi_encoder_jpeg_flush;
+
+  object_class->set_property = gst_vaapi_encoder_jpeg_set_property;
+  object_class->get_property = gst_vaapi_encoder_jpeg_get_property;
+
+  properties[ENCODER_JPEG_PROP_RATECONTROL] =
+      g_param_spec_enum ("rate-control",
+      "Rate Control", "Rate control mode",
+      g_class_data.rate_control_get_type (),
+      g_class_data.default_rate_control,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_JPEG_PROP_TUNE] =
+      g_param_spec_enum ("tune",
+      "Encoder Tuning",
+      "Encoder tuning option",
+      g_class_data.encoder_tune_get_type (),
+      g_class_data.default_encoder_tune,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_JPEG_PROP_QUALITY] =
+      g_param_spec_uint ("quality",
+      "Quality factor",
+      "Quality factor", 0, 100, 50,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  g_object_class_install_properties (object_class, ENCODER_JPEG_N_PROPERTIES,
+      properties);
+
+  gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0);
+  gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0);
+}
+
+/**
+ * gst_vaapi_encoder_jpeg_new:
+ * @display: a #GstVaapiDisplay
+ *
+ * Creates a new #GstVaapiEncoder for JPEG encoding.
+ *
+ * Return value: the newly allocated #GstVaapiEncoder object
+ */
+GstVaapiEncoder *
+gst_vaapi_encoder_jpeg_new (GstVaapiDisplay * display)
+{
+  return g_object_new (GST_TYPE_VAAPI_ENCODER_JPEG, "display", display, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_jpeg.h
new file mode 100644 (file)
index 0000000..b3b2474
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  gstvaapiencoder_jpeg.h JPEGG encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_JPEG_H
+#define GST_VAAPI_ENCODER_JPEG_H
+
+#include <gst/vaapi/gstvaapiencoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_ENCODER_JPEG \
+    (gst_vaapi_encoder_jpeg_get_type ())
+#define GST_VAAPI_ENCODER_JPEG(encoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_JPEG, GstVaapiEncoderJpeg))
+#define GST_IS_VAAPI_ENCODER_JPEG(encoder) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_JPEG))
+
+typedef struct _GstVaapiEncoderJpeg GstVaapiEncoderJpeg;
+typedef struct _GstVaapiEncoderJpegClass GstVaapiEncoderJpegClass;
+
+GType
+gst_vaapi_encoder_jpeg_get_type (void) G_GNUC_CONST;
+
+GstVaapiEncoder *
+gst_vaapi_encoder_jpeg_new (GstVaapiDisplay * display);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderJpeg, gst_object_unref)
+
+G_END_DECLS
+
+#endif /*GST_VAAPI_ENCODER_JPEG_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.c
new file mode 100644 (file)
index 0000000..731b03e
--- /dev/null
@@ -0,0 +1,1098 @@
+/*
+ *  gstvaapiencoder_mpeg2.c - MPEG-2 encoder
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Guangxin Xu <guangxin.xu@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include <math.h>
+#include "sysdeps.h"
+#include <gst/base/gstbitwriter.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiencoder_mpeg2.h"
+#include "gstvaapiencoder_mpeg2_priv.h"
+#include "gstvaapiutils_mpeg2_priv.h"
+#include "gstvaapicodedbufferproxy_priv.h"
+#include "gstvaapicontext.h"
+#include "gstvaapisurface.h"
+#include "gstvaapidisplay_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/* Define default rate control mode ("constant-qp") */
+#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP
+
+/* Supported set of VA rate controls, within this implementation */
+#define SUPPORTED_RATECONTROLS                  \
+  (GST_VAAPI_RATECONTROL_MASK (CQP)  |          \
+   GST_VAAPI_RATECONTROL_MASK (CBR))
+
+/* Supported set of tuning options, within this implementation */
+#define SUPPORTED_TUNE_OPTIONS \
+  (GST_VAAPI_ENCODER_TUNE_MASK (NONE))
+
+/* Supported set of VA packed headers, within this implementation */
+#define SUPPORTED_PACKED_HEADERS                \
+  (VA_ENC_PACKED_HEADER_SEQUENCE |              \
+   VA_ENC_PACKED_HEADER_PICTURE)
+
+static gboolean
+gst_bit_writer_write_sps (GstBitWriter * bitwriter,
+    const VAEncSequenceParameterBufferMPEG2 * seq_param);
+
+static gboolean
+gst_bit_writer_write_pps (GstBitWriter * bitwriter,
+    const VAEncPictureParameterBufferMPEG2 * pic_param);
+
+static void clear_references (GstVaapiEncoderMpeg2 * encoder);
+
+static void push_reference (GstVaapiEncoderMpeg2 * encoder,
+    GstVaapiSurfaceProxy * ref);
+
+/* Derives the profile supported by the underlying hardware */
+static gboolean
+ensure_hw_profile (GstVaapiEncoderMpeg2 * encoder)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+  GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
+  GstVaapiProfile profile, profiles[2];
+  guint i, num_profiles = 0;
+
+  profiles[num_profiles++] = encoder->profile;
+  switch (encoder->profile) {
+    case GST_VAAPI_PROFILE_MPEG2_SIMPLE:
+      profiles[num_profiles++] = GST_VAAPI_PROFILE_MPEG2_MAIN;
+      break;
+    default:
+      break;
+  }
+
+  profile = GST_VAAPI_PROFILE_UNKNOWN;
+  for (i = 0; i < num_profiles; i++) {
+    if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
+      profile = profiles[i];
+      break;
+    }
+  }
+  if (profile == GST_VAAPI_PROFILE_UNKNOWN)
+    goto error_unsupported_profile;
+
+  GST_VAAPI_ENCODER_CAST (encoder)->profile = profile;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_profile:
+  {
+    GST_ERROR ("unsupported HW profile %s",
+        gst_vaapi_profile_get_va_name (encoder->profile));
+    return FALSE;
+  }
+}
+
+/* Derives the minimum profile from the active coding tools */
+static gboolean
+ensure_profile (GstVaapiEncoderMpeg2 * encoder)
+{
+  GstVaapiProfile profile;
+
+  /* Always start from "simple" profile for maximum compatibility */
+  profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
+
+  /* Main profile coding tools */
+  if (encoder->ip_period > 0)
+    profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
+
+  encoder->profile = profile;
+  encoder->profile_idc = gst_vaapi_utils_mpeg2_get_profile_idc (profile);
+  return TRUE;
+}
+
+/* Derives the minimum level from the current configuration */
+static gboolean
+ensure_level (GstVaapiEncoderMpeg2 * encoder)
+{
+  const GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+  const guint fps = (vip->fps_n + vip->fps_d - 1) / vip->fps_d;
+  const guint bitrate = GST_VAAPI_ENCODER_CAST (encoder)->bitrate;
+  const GstVaapiMPEG2LevelLimits *limits_table;
+  guint i, num_limits, num_samples;
+
+  num_samples = gst_util_uint64_scale_int_ceil (vip->width * vip->height,
+      vip->fps_n, vip->fps_d);
+
+  limits_table = gst_vaapi_utils_mpeg2_get_level_limits_table (&num_limits);
+  for (i = 0; i < num_limits; i++) {
+    const GstVaapiMPEG2LevelLimits *const limits = &limits_table[i];
+    if (vip->width <= limits->horizontal_size_value &&
+        vip->height <= limits->vertical_size_value &&
+        fps <= limits->frame_rate_value &&
+        num_samples <= limits->sample_rate &&
+        (!bitrate || bitrate <= limits->bit_rate))
+      break;
+  }
+  if (i == num_limits)
+    goto error_unsupported_level;
+
+  encoder->level = limits_table[i].level;
+  encoder->level_idc = limits_table[i].level_idc;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_level:
+  {
+    GST_ERROR ("failed to find a suitable level matching codec config");
+    return FALSE;
+  }
+}
+
+/* Derives the profile and level that suits best to the configuration */
+static GstVaapiEncoderStatus
+ensure_profile_and_level (GstVaapiEncoderMpeg2 * encoder)
+{
+  if (!ensure_profile (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  if (!ensure_level (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static gboolean
+ensure_bitrate (GstVaapiEncoderMpeg2 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  /* Default compression: 64 bits per macroblock */
+  switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
+    case GST_VAAPI_RATECONTROL_CBR:
+      if (!base_encoder->bitrate)
+        base_encoder->bitrate =
+            gst_util_uint64_scale (GST_VAAPI_ENCODER_WIDTH (encoder) *
+            GST_VAAPI_ENCODER_HEIGHT (encoder),
+            GST_VAAPI_ENCODER_FPS_N (encoder),
+            GST_VAAPI_ENCODER_FPS_D (encoder)) / 4 / 1000;
+      break;
+    default:
+      base_encoder->bitrate = 0;
+      break;
+  }
+  return TRUE;
+}
+
+static gboolean
+fill_sequence (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncSequence * sequence)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  VAEncSequenceParameterBufferMPEG2 *const seq_param = sequence->param;
+
+  memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferMPEG2));
+
+  seq_param->intra_period = base_encoder->keyframe_period;
+  seq_param->ip_period = encoder->ip_period;
+  seq_param->picture_width = GST_VAAPI_ENCODER_WIDTH (encoder);
+  seq_param->picture_height = GST_VAAPI_ENCODER_HEIGHT (encoder);
+
+  if (base_encoder->bitrate > 0)
+    seq_param->bits_per_second = base_encoder->bitrate * 1000;
+  else
+    seq_param->bits_per_second = 0;
+
+  if (GST_VAAPI_ENCODER_FPS_D (encoder))
+    seq_param->frame_rate =
+        GST_VAAPI_ENCODER_FPS_N (encoder) / GST_VAAPI_ENCODER_FPS_D (encoder);
+  else
+    seq_param->frame_rate = 0;
+
+  seq_param->aspect_ratio_information = 1;
+  seq_param->vbv_buffer_size = 3;       /* B = 16 * 1024 * vbv_buffer_size */
+
+  seq_param->sequence_extension.bits.profile_and_level_indication =
+      (encoder->profile_idc << 4) | encoder->level_idc;
+  seq_param->sequence_extension.bits.progressive_sequence = 1;  /* progressive frame-pictures */
+  seq_param->sequence_extension.bits.chroma_format =
+      gst_vaapi_utils_mpeg2_get_chroma_format_idc
+      (GST_VAAPI_CHROMA_TYPE_YUV420);
+  seq_param->sequence_extension.bits.low_delay = 0;     /* FIXME */
+  seq_param->sequence_extension.bits.frame_rate_extension_n = 0;        /* FIXME */
+  seq_param->sequence_extension.bits.frame_rate_extension_d = 0;
+
+  seq_param->gop_header.bits.time_code = (1 << 12);     /* bit12: marker_bit */
+  seq_param->gop_header.bits.closed_gop = 0;
+  seq_param->gop_header.bits.broken_link = 0;
+
+  return TRUE;
+}
+
+static VAEncPictureType
+get_va_enc_picture_type (GstVaapiPictureType type)
+{
+  switch (type) {
+    case GST_VAAPI_PICTURE_TYPE_I:
+      return VAEncPictureTypeIntra;
+    case GST_VAAPI_PICTURE_TYPE_P:
+      return VAEncPictureTypePredictive;
+    case GST_VAAPI_PICTURE_TYPE_B:
+      return VAEncPictureTypeBidirectional;
+    default:
+      return -1;
+  }
+  return -1;
+}
+
+static gboolean
+fill_picture (GstVaapiEncoderMpeg2 * encoder,
+    GstVaapiEncPicture * picture,
+    GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
+{
+  VAEncPictureParameterBufferMPEG2 *const pic_param = picture->param;
+  guint8 f_code_x, f_code_y;
+
+  memset (pic_param, 0, sizeof (VAEncPictureParameterBufferMPEG2));
+
+  pic_param->reconstructed_picture =
+      GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
+  pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf);
+  pic_param->picture_type = get_va_enc_picture_type (picture->type);
+  pic_param->temporal_reference = picture->frame_num & (1024 - 1);
+  pic_param->vbv_delay = 0xFFFF;
+
+  f_code_x = 0xf;
+  f_code_y = 0xf;
+  if (pic_param->picture_type != VAEncPictureTypeIntra) {
+    switch (encoder->level) {
+      case GST_VAAPI_LEVEL_MPEG2_LOW:
+        f_code_x = 7;
+        f_code_y = 4;
+        break;
+      case GST_VAAPI_LEVEL_MPEG2_MAIN:
+        f_code_x = 8;
+        f_code_y = 5;
+        break;
+      default:                 /* High-1440 and High levels */
+        f_code_x = 9;
+        f_code_y = 5;
+        break;
+    }
+  }
+
+  if (pic_param->picture_type == VAEncPictureTypeIntra) {
+    pic_param->f_code[0][0] = 0xf;
+    pic_param->f_code[0][1] = 0xf;
+    pic_param->f_code[1][0] = 0xf;
+    pic_param->f_code[1][1] = 0xf;
+    pic_param->forward_reference_picture = VA_INVALID_SURFACE;
+    pic_param->backward_reference_picture = VA_INVALID_SURFACE;
+  } else if (pic_param->picture_type == VAEncPictureTypePredictive) {
+    pic_param->f_code[0][0] = f_code_x;
+    pic_param->f_code[0][1] = f_code_y;
+    pic_param->f_code[1][0] = 0xf;
+    pic_param->f_code[1][1] = 0xf;
+    pic_param->forward_reference_picture =
+        GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->forward);
+    pic_param->backward_reference_picture = VA_INVALID_SURFACE;
+  } else if (pic_param->picture_type == VAEncPictureTypeBidirectional) {
+    pic_param->f_code[0][0] = f_code_x;
+    pic_param->f_code[0][1] = f_code_y;
+    pic_param->f_code[1][0] = f_code_x;
+    pic_param->f_code[1][1] = f_code_y;
+    pic_param->forward_reference_picture =
+        GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->forward);
+    pic_param->backward_reference_picture =
+        GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->backward);
+  } else {
+    g_assert (0);
+  }
+
+  pic_param->picture_coding_extension.bits.intra_dc_precision = 0;      /* 8bits */
+  pic_param->picture_coding_extension.bits.picture_structure = 3;       /* frame picture */
+  pic_param->picture_coding_extension.bits.top_field_first = 0;
+  pic_param->picture_coding_extension.bits.frame_pred_frame_dct = 1;    /* FIXME */
+  pic_param->picture_coding_extension.bits.concealment_motion_vectors = 0;
+  pic_param->picture_coding_extension.bits.q_scale_type = 0;
+  pic_param->picture_coding_extension.bits.intra_vlc_format = 0;
+  pic_param->picture_coding_extension.bits.alternate_scan = 0;
+  pic_param->picture_coding_extension.bits.repeat_first_field = 0;
+  pic_param->picture_coding_extension.bits.progressive_frame = 1;
+  pic_param->picture_coding_extension.bits.composite_display_flag = 0;
+
+  return TRUE;
+}
+
+static gboolean
+set_sequence_packed_header (GstVaapiEncoderMpeg2 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiEncSequence * sequence)
+{
+  GstVaapiEncPackedHeader *packed_seq;
+  GstBitWriter writer;
+  VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
+  const VAEncSequenceParameterBufferMPEG2 *const seq_param = sequence->param;
+  guint32 data_bit_size;
+  guint8 *data;
+
+  gst_bit_writer_init_with_size (&writer, 128, FALSE);
+  if (encoder->new_gop)
+    gst_bit_writer_write_sps (&writer, seq_param);
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&writer) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&writer);
+  data = GST_BIT_WRITER_DATA (&writer);
+
+  packed_header_param_buffer.type = VAEncPackedHeaderSequence;
+  packed_header_param_buffer.bit_length = data_bit_size;
+  packed_header_param_buffer.has_emulation_bytes = 0;
+
+  packed_seq = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_header_param_buffer, sizeof (packed_header_param_buffer),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_seq);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_seq);
+  gst_vaapi_codec_object_replace (&packed_seq, NULL);
+  gst_bit_writer_reset (&writer);
+
+  return TRUE;
+}
+
+static gboolean
+set_picture_packed_header (GstVaapiEncoderMpeg2 * encoder,
+    GstVaapiEncPicture * picture)
+{
+  GstVaapiEncPackedHeader *packed_pic;
+  GstBitWriter writer;
+  VAEncPackedHeaderParameterBuffer packed_header_param_buffer = { 0 };
+  const VAEncPictureParameterBufferMPEG2 *const pic_param = picture->param;
+  guint32 data_bit_size;
+  guint8 *data;
+
+  gst_bit_writer_init_with_size (&writer, 128, FALSE);
+  gst_bit_writer_write_pps (&writer, pic_param);
+  g_assert (GST_BIT_WRITER_BIT_SIZE (&writer) % 8 == 0);
+  data_bit_size = GST_BIT_WRITER_BIT_SIZE (&writer);
+  data = GST_BIT_WRITER_DATA (&writer);
+
+  packed_header_param_buffer.type = VAEncPackedHeaderPicture;
+  packed_header_param_buffer.bit_length = data_bit_size;
+  packed_header_param_buffer.has_emulation_bytes = 0;
+
+  packed_pic = gst_vaapi_enc_packed_header_new (GST_VAAPI_ENCODER (encoder),
+      &packed_header_param_buffer, sizeof (packed_header_param_buffer),
+      data, (data_bit_size + 7) / 8);
+  g_assert (packed_pic);
+
+  gst_vaapi_enc_picture_add_packed_header (picture, packed_pic);
+  gst_vaapi_codec_object_replace (&packed_pic, NULL);
+  gst_bit_writer_reset (&writer);
+
+  return TRUE;
+}
+
+static gboolean
+ensure_sequence (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncSequence *sequence;
+
+  g_assert (picture);
+  sequence = GST_VAAPI_ENC_SEQUENCE_NEW (MPEG2, encoder);
+  g_assert (sequence);
+  if (!sequence)
+    goto error;
+
+  if (!fill_sequence (encoder, sequence))
+    goto error;
+
+  if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+          VA_ENC_PACKED_HEADER_SEQUENCE)
+      && picture->type == GST_VAAPI_PICTURE_TYPE_I
+      && !set_sequence_packed_header (encoder, picture, sequence))
+    goto error;
+  gst_vaapi_enc_picture_set_sequence (picture, sequence);
+  gst_vaapi_codec_object_replace (&sequence, NULL);
+  return TRUE;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+    return FALSE;
+  }
+}
+
+static gboolean
+ensure_picture (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiCodedBuffer *const codedbuf =
+      GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
+
+  if (!fill_picture (encoder, picture, codedbuf, surface))
+    return FALSE;
+
+  if ((GST_VAAPI_ENCODER_PACKED_HEADERS (encoder) &
+          VA_ENC_PACKED_HEADER_PICTURE)
+      && !set_picture_packed_header (encoder, picture)) {
+    GST_ERROR ("set picture packed header failed");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+static gboolean
+ensure_control_rate_params (GstVaapiEncoderMpeg2 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
+    return TRUE;
+
+  /* RateControl params */
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->cqp;
+
+  /* *INDENT-OFF* */
+  /* HRD params */
+  GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) {
+    .buffer_size = base_encoder->bitrate * 1000 * 8,
+    .initial_buffer_fullness = base_encoder->bitrate * 1000 * 4,
+  };
+  /* *INDENT-ON* */
+
+  return TRUE;
+}
+
+static gboolean
+set_misc_parameters (GstVaapiEncoderMpeg2 * encoder,
+    GstVaapiEncPicture * picture)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture))
+    return FALSE;
+  if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+fill_slices (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncPicture * picture)
+{
+  VAEncSliceParameterBufferMPEG2 *slice_param;
+  GstVaapiEncSlice *slice;
+  guint width_in_mbs, height_in_mbs;
+  guint i_slice;
+
+  g_assert (picture);
+
+  width_in_mbs = (GST_VAAPI_ENCODER_WIDTH (encoder) + 15) / 16;
+  height_in_mbs = (GST_VAAPI_ENCODER_HEIGHT (encoder) + 15) / 16;
+
+  for (i_slice = 0; i_slice < height_in_mbs; ++i_slice) {
+    slice = GST_VAAPI_ENC_SLICE_NEW (MPEG2, encoder);
+    g_assert (slice && slice->param_id != VA_INVALID_ID);
+    slice_param = slice->param;
+
+    memset (slice_param, 0, sizeof (VAEncSliceParameterBufferMPEG2));
+
+    slice_param->macroblock_address = i_slice * width_in_mbs;
+    slice_param->num_macroblocks = width_in_mbs;
+    slice_param->is_intra_slice = (picture->type == GST_VAAPI_PICTURE_TYPE_I);
+    slice_param->quantiser_scale_code = encoder->cqp / 2;
+
+    gst_vaapi_enc_picture_add_slice (picture, slice);
+    gst_vaapi_codec_object_replace (&slice, NULL);
+  }
+  return TRUE;
+}
+
+static gboolean
+ensure_slices (GstVaapiEncoderMpeg2 * encoder, GstVaapiEncPicture * picture)
+{
+  g_assert (picture);
+
+  if (!fill_slices (encoder, picture))
+    return FALSE;
+
+  return TRUE;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_mpeg2_encode (GstVaapiEncoder * base_encoder,
+    GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
+{
+  GstVaapiEncoderMpeg2 *const encoder =
+      GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder);
+  GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  GstVaapiSurfaceProxy *reconstruct = NULL;
+
+  reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
+
+  g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
+
+  if (!ensure_sequence (encoder, picture))
+    goto error;
+  if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
+    goto error;
+  if (!set_misc_parameters (encoder, picture))
+    goto error;
+  if (!ensure_slices (encoder, picture))
+    goto error;
+  if (!gst_vaapi_enc_picture_encode (picture))
+    goto error;
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_B) {
+    if (encoder->new_gop)
+      clear_references (encoder);
+    push_reference (encoder, reconstruct);
+  } else if (reconstruct)
+    gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
+        reconstruct);
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    if (reconstruct)
+      gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
+          reconstruct);
+    return ret;
+  }
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_mpeg2_flush (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderMpeg2 *const encoder =
+      GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder);
+  GstVaapiEncPicture *pic;
+
+  while (!g_queue_is_empty (&encoder->b_frames)) {
+    pic = g_queue_pop_head (&encoder->b_frames);
+    gst_vaapi_enc_picture_unref (pic);
+  }
+  g_queue_clear (&encoder->b_frames);
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_mpeg2_reordering (GstVaapiEncoder * base_encoder,
+    GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
+{
+  GstVaapiEncoderMpeg2 *const encoder =
+      GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder);
+  GstVaapiEncPicture *picture = NULL;
+  GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  if (!frame) {
+    if (g_queue_is_empty (&encoder->b_frames) && encoder->dump_frames) {
+      push_reference (encoder, NULL);
+      encoder->dump_frames = FALSE;
+    }
+    if (!encoder->dump_frames) {
+      return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
+    }
+    picture = g_queue_pop_head (&encoder->b_frames);
+    g_assert (picture);
+    goto end;
+  }
+
+  picture = GST_VAAPI_ENC_PICTURE_NEW (MPEG2, encoder, frame);
+  if (!picture) {
+    GST_WARNING ("create MPEG2 picture failed, frame timestamp:%"
+        GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  if (encoder->frame_num >= base_encoder->keyframe_period) {
+    encoder->frame_num = 0;
+    clear_references (encoder);
+  }
+  if (encoder->frame_num == 0) {
+    picture->type = GST_VAAPI_PICTURE_TYPE_I;
+    GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
+    encoder->new_gop = TRUE;
+  } else {
+    encoder->new_gop = FALSE;
+    if ((encoder->frame_num % (encoder->ip_period + 1)) == 0 ||
+        encoder->frame_num == base_encoder->keyframe_period - 1) {
+      picture->type = GST_VAAPI_PICTURE_TYPE_P;
+      encoder->dump_frames = TRUE;
+    } else {
+      picture->type = GST_VAAPI_PICTURE_TYPE_B;
+      status = GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
+    }
+  }
+  picture->frame_num = encoder->frame_num++;
+
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_B) {
+    g_queue_push_tail (&encoder->b_frames, picture);
+    picture = NULL;
+  }
+
+end:
+  *output = picture;
+  return status;
+}
+
+static GstVaapiEncoderStatus
+set_context_info (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderMpeg2 *const encoder =
+      GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder);
+  GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+
+  /* Maximum sizes for common headers (in bytes) */
+  enum
+  {
+    MAX_SEQ_HDR_SIZE = 140,
+    MAX_SEQ_EXT_SIZE = 10,
+    MAX_GOP_SIZE = 8,
+    MAX_PIC_HDR_SIZE = 10,
+    MAX_PIC_EXT_SIZE = 11,
+    MAX_SLICE_HDR_SIZE = 8,
+  };
+
+  if (!ensure_hw_profile (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  base_encoder->num_ref_frames = 2;
+
+  /* Only YUV 4:2:0 formats are supported for now. This means that we
+     have a limit of 4608 bits per macroblock. */
+  base_encoder->codedbuf_size = (GST_ROUND_UP_16 (vip->width) *
+      GST_ROUND_UP_16 (vip->height) / 256) * 576;
+
+  /* Account for Sequence, GOP, and Picture headers */
+  /* XXX: exclude unused Sequence Display Extension, Sequence Scalable
+     Extension, Quantization Matrix Extension, Picture Display Extension,
+     Picture Temporal Scalable Extension, Picture Spatial Scalable
+     Extension */
+  base_encoder->codedbuf_size += MAX_SEQ_HDR_SIZE + MAX_SEQ_EXT_SIZE +
+      MAX_GOP_SIZE + MAX_PIC_HDR_SIZE + MAX_PIC_EXT_SIZE;
+
+  /* Account for Slice headers. We use one slice per line of macroblock */
+  base_encoder->codedbuf_size += (GST_ROUND_UP_16 (vip->height) / 16) *
+      MAX_SLICE_HDR_SIZE;
+
+  base_encoder->context_info.profile = base_encoder->profile;
+  base_encoder->context_info.entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_mpeg2_reconfigure (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderMpeg2 *const encoder =
+      GST_VAAPI_ENCODER_MPEG2_CAST (base_encoder);
+  GstVaapiEncoderStatus status;
+
+  if (encoder->ip_period > base_encoder->keyframe_period) {
+    encoder->ip_period = base_encoder->keyframe_period - 1;
+  }
+
+  status = ensure_profile_and_level (encoder);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return status;
+
+  if (!ensure_bitrate (encoder))
+    goto error;
+  ensure_control_rate_params (encoder);
+  return set_context_info (base_encoder);
+
+  /* ERRORS */
+error:
+  {
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+}
+
+struct _GstVaapiEncoderMpeg2Class
+{
+  GstVaapiEncoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiEncoderMpeg2, gst_vaapi_encoder_mpeg2,
+    GST_TYPE_VAAPI_ENCODER);
+
+static void
+gst_vaapi_encoder_mpeg2_init (GstVaapiEncoderMpeg2 * encoder)
+{
+  /* re-ordering */
+  g_queue_init (&encoder->b_frames);
+}
+
+static void
+clear_ref (GstVaapiEncoderMpeg2 * encoder, GstVaapiSurfaceProxy ** ref)
+{
+  if (*ref) {
+    gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), *ref);
+    *ref = NULL;
+  }
+}
+
+static void
+clear_references (GstVaapiEncoderMpeg2 * encoder)
+{
+  clear_ref (encoder, &encoder->forward);
+  clear_ref (encoder, &encoder->backward);
+}
+
+static void
+push_reference (GstVaapiEncoderMpeg2 * encoder, GstVaapiSurfaceProxy * ref)
+{
+  if (encoder->backward) {
+    clear_ref (encoder, &encoder->forward);
+    encoder->forward = encoder->backward;
+    encoder->backward = NULL;
+  }
+  if (encoder->forward)
+    encoder->backward = ref;
+  else
+    encoder->forward = ref;
+}
+
+static void
+gst_vaapi_encoder_mpeg2_finalize (GObject * object)
+{
+  /* free private buffers */
+  GstVaapiEncoderMpeg2 *const encoder = GST_VAAPI_ENCODER_MPEG2 (object);
+  GstVaapiEncPicture *pic;
+
+  clear_references (encoder);
+
+  while (!g_queue_is_empty (&encoder->b_frames)) {
+    pic = g_queue_pop_head (&encoder->b_frames);
+    gst_vaapi_enc_picture_unref (pic);
+  }
+  g_queue_clear (&encoder->b_frames);
+
+  G_OBJECT_CLASS (gst_vaapi_encoder_mpeg2_parent_class)->finalize (object);
+}
+
+/**
+ * @ENCODER_MPEG2_PROP_RATECONTROL: Rate control (#GstVaapiRateControl).
+ * @ENCODER_MPEG2_PROP_TUNE: The tuning options (#GstVaapiEncoderTune).
+ * @ENCODER_MPEG2_PROP_QUANTIZER: Constant quantizer value (uint).
+ * @ENCODER_MPEG2_PROP_MAX_BFRAMES: Number of B-frames between I
+ *   and P (uint).
+ *
+ * The set of MPEG-2 encoder specific configurable properties.
+ */
+enum
+{
+  ENCODER_MPEG2_PROP_RATECONTROL = 1,
+  ENCODER_MPEG2_PROP_TUNE,
+  ENCODER_MPEG2_PROP_QUANTIZER,
+  ENCODER_MPEG2_PROP_MAX_BFRAMES,
+  ENCODER_MPEG2_N_PROPERTIES
+};
+
+static GParamSpec *properties[ENCODER_MPEG2_N_PROPERTIES];
+
+static void
+gst_vaapi_encoder_mpeg2_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+  GstVaapiEncoderMpeg2 *const encoder = GST_VAAPI_ENCODER_MPEG2 (object);
+
+  if (base_encoder->num_codedbuf_queued > 0) {
+    GST_ERROR_OBJECT (object,
+        "failed to set any property after encoding started");
+    return;
+  }
+
+  switch (prop_id) {
+    case ENCODER_MPEG2_PROP_RATECONTROL:
+      gst_vaapi_encoder_set_rate_control (base_encoder,
+          g_value_get_enum (value));
+      break;
+    case ENCODER_MPEG2_PROP_TUNE:
+      gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value));
+      break;
+    case ENCODER_MPEG2_PROP_QUANTIZER:
+      encoder->cqp = g_value_get_uint (value);
+      break;
+    case ENCODER_MPEG2_PROP_MAX_BFRAMES:
+      encoder->ip_period = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_encoder_mpeg2_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoderMpeg2 *const encoder = GST_VAAPI_ENCODER_MPEG2 (object);
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+
+  switch (prop_id) {
+    case ENCODER_MPEG2_PROP_RATECONTROL:
+      g_value_set_enum (value, base_encoder->rate_control);
+      break;
+    case ENCODER_MPEG2_PROP_TUNE:
+      g_value_set_enum (value, base_encoder->tune);
+      break;
+    case ENCODER_MPEG2_PROP_QUANTIZER:
+      g_value_set_uint (value, encoder->cqp);
+      break;
+    case ENCODER_MPEG2_PROP_MAX_BFRAMES:
+      g_value_set_uint (value, encoder->ip_period);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (MPEG2);
+
+static void
+gst_vaapi_encoder_mpeg2_class_init (GstVaapiEncoderMpeg2Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass);
+
+  encoder_class->class_data = &g_class_data;
+  encoder_class->reconfigure = gst_vaapi_encoder_mpeg2_reconfigure;
+  encoder_class->reordering = gst_vaapi_encoder_mpeg2_reordering;
+  encoder_class->encode = gst_vaapi_encoder_mpeg2_encode;
+  encoder_class->flush = gst_vaapi_encoder_mpeg2_flush;
+
+  object_class->set_property = gst_vaapi_encoder_mpeg2_set_property;
+  object_class->get_property = gst_vaapi_encoder_mpeg2_get_property;
+  object_class->finalize = gst_vaapi_encoder_mpeg2_finalize;
+
+  /**
+   * GstVaapiEncoderMpeg2:rate-control:
+   *
+   * The desired rate control mode, expressed as a #GstVaapiRateControl.
+   */
+  properties[ENCODER_MPEG2_PROP_RATECONTROL] =
+      g_param_spec_enum ("rate-control",
+      "Rate Control", "Rate control mode",
+      g_class_data.rate_control_get_type (),
+      g_class_data.default_rate_control,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderMpeg2:tune:
+   *
+   * The desired encoder tuning option.
+   */
+  properties[ENCODER_MPEG2_PROP_TUNE] =
+      g_param_spec_enum ("tune",
+      "Encoder Tuning",
+      "Encoder tuning option",
+      g_class_data.encoder_tune_get_type (),
+      g_class_data.default_encoder_tune,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_MPEG2_PROP_QUANTIZER] =
+      g_param_spec_uint ("quantizer",
+      "Constant Quantizer",
+      "Constant quantizer (if rate-control mode is CQP)",
+      2, 62, 8, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_MPEG2_PROP_MAX_BFRAMES] =
+      g_param_spec_uint ("max-bframes", "Max B-Frames",
+      "Number of B-frames between I and P", 0, 16, 0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  g_object_class_install_properties (object_class, ENCODER_MPEG2_N_PROPERTIES,
+      properties);
+
+  gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0);
+  gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0);
+}
+
+/**
+ * gst_vaapi_encoder_mpeg2_new:
+ * @display: a #GstVaapiDisplay
+ *
+ * Creates a new #GstVaapiEncoder for MPEG-2 encoding.
+ *
+ * Return value: the newly allocated #GstVaapiEncoder object
+ */
+GstVaapiEncoder *
+gst_vaapi_encoder_mpeg2_new (GstVaapiDisplay * display)
+{
+  return g_object_new (GST_TYPE_VAAPI_ENCODER_MPEG2, "display", display, NULL);
+}
+
+static struct
+{
+  int code;
+  float value;
+} frame_rate_tab[] = {
+  /* *INDENT-OFF* */
+  { 1, 23.976 },
+  { 2, 24.0   },
+  { 3, 25.0   },
+  { 4, 29.97  },
+  { 5, 30     },
+  { 6, 50     },
+  { 7, 59.94  },
+  { 8, 60     }
+  /* *INDENT-ON* */
+};
+
+static int
+find_frame_rate_code (const VAEncSequenceParameterBufferMPEG2 * seq_param)
+{
+  unsigned int ndelta, delta = -1;
+  int code = 1, i;
+  float frame_rate_value = seq_param->frame_rate *
+      (seq_param->sequence_extension.bits.frame_rate_extension_d + 1) /
+      (seq_param->sequence_extension.bits.frame_rate_extension_n + 1);
+
+  for (i = 0; i < G_N_ELEMENTS (frame_rate_tab); i++) {
+
+    ndelta = fabsf (1000 * frame_rate_tab[i].value - 1000 * frame_rate_value);
+    if (ndelta < delta) {
+      code = frame_rate_tab[i].code;
+      delta = ndelta;
+    }
+  }
+  return code;
+}
+
+static gboolean
+gst_bit_writer_write_sps (GstBitWriter * bitwriter,
+    const VAEncSequenceParameterBufferMPEG2 * seq_param)
+{
+  gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_SEQ, 32);
+  gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->picture_width, 12);
+  gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->picture_height, 12);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->aspect_ratio_information, 4);
+  gst_bit_writer_put_bits_uint32 (bitwriter, find_frame_rate_code (seq_param), 4);      /* frame_rate_code */
+  gst_bit_writer_put_bits_uint32 (bitwriter, (seq_param->bits_per_second + 399) / 400, 18);     /* the low 18 bits of bit_rate */
+  gst_bit_writer_put_bits_uint32 (bitwriter, 1, 1);     /* marker_bit */
+  gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->vbv_buffer_size, 10);
+  gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1);     /* constraint_parameter_flag, always 0 for MPEG-2 */
+  gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1);     /* load_intra_quantiser_matrix */
+  gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1);     /* load_non_intra_quantiser_matrix */
+
+  gst_bit_writer_align_bytes (bitwriter, 0);
+
+  gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_EXT, 32);
+  gst_bit_writer_put_bits_uint32 (bitwriter, 1, 4);     /* sequence_extension id */
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->sequence_extension.bits.profile_and_level_indication, 8);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->sequence_extension.bits.progressive_sequence, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->sequence_extension.bits.chroma_format, 2);
+  gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->picture_width >> 12, 2);
+  gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->picture_height >> 12,
+      2);
+  gst_bit_writer_put_bits_uint32 (bitwriter, ((seq_param->bits_per_second + 399) / 400) >> 18, 12);     /* bit_rate_extension */
+  gst_bit_writer_put_bits_uint32 (bitwriter, 1, 1);     /* marker_bit */
+  gst_bit_writer_put_bits_uint32 (bitwriter, seq_param->vbv_buffer_size >> 10,
+      8);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->sequence_extension.bits.low_delay, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->sequence_extension.bits.frame_rate_extension_n, 2);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->sequence_extension.bits.frame_rate_extension_d, 5);
+
+  gst_bit_writer_align_bytes (bitwriter, 0);
+
+  /* gop header */
+  gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_GOP, 32);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->gop_header.bits.time_code, 25);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->gop_header.bits.closed_gop, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      seq_param->gop_header.bits.broken_link, 1);
+
+  gst_bit_writer_align_bytes (bitwriter, 0);
+
+  return TRUE;
+}
+
+static gboolean
+gst_bit_writer_write_pps (GstBitWriter * bitwriter,
+    const VAEncPictureParameterBufferMPEG2 * pic_param)
+{
+  gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_PICUTRE, 32);
+  gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->temporal_reference, 10);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_type == VAEncPictureTypeIntra ? 1 :
+      pic_param->picture_type == VAEncPictureTypePredictive ? 2 : 3, 3);
+  gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->vbv_delay, 16);
+
+  if (pic_param->picture_type == VAEncPictureTypePredictive ||
+      pic_param->picture_type == VAEncPictureTypeBidirectional) {
+    gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1);   /* full_pel_forward_vector, always 0 for MPEG-2 */
+    gst_bit_writer_put_bits_uint32 (bitwriter, 7, 3);   /* forward_f_code, always 7 for MPEG-2 */
+  }
+
+  if (pic_param->picture_type == VAEncPictureTypeBidirectional) {
+    gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1);   /* full_pel_backward_vector, always 0 for MPEG-2 */
+    gst_bit_writer_put_bits_uint32 (bitwriter, 7, 3);   /* backward_f_code, always 7 for MPEG-2 */
+  }
+
+  gst_bit_writer_put_bits_uint32 (bitwriter, 0, 1);     /* extra_bit_picture, 0 */
+
+  gst_bit_writer_align_bytes (bitwriter, 0);
+
+  gst_bit_writer_put_bits_uint32 (bitwriter, START_CODE_EXT, 32);
+  gst_bit_writer_put_bits_uint32 (bitwriter, 8, 4);     /* Picture Coding Extension ID: 8 */
+  gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->f_code[0][0], 4);
+  gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->f_code[0][1], 4);
+  gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->f_code[1][0], 4);
+  gst_bit_writer_put_bits_uint32 (bitwriter, pic_param->f_code[1][1], 4);
+
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.intra_dc_precision, 2);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.picture_structure, 2);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.top_field_first, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.frame_pred_frame_dct, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.concealment_motion_vectors, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.q_scale_type, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.intra_vlc_format, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.alternate_scan, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.repeat_first_field, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter, 1, 1);     /* always chroma 420 */
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.progressive_frame, 1);
+  gst_bit_writer_put_bits_uint32 (bitwriter,
+      pic_param->picture_coding_extension.bits.composite_display_flag, 1);
+
+  gst_bit_writer_align_bytes (bitwriter, 0);
+
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2.h
new file mode 100644 (file)
index 0000000..a4384ef
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  gstvaapiencoder_mpeg2.h - MPEG-2 encoder
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Guangxin Xu <guangxin.xu@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_MPEG2_H
+#define GST_VAAPI_ENCODER_MPEG2_H
+
+#include <gst/vaapi/gstvaapiencoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_ENCODER_MPEG2 \
+    (gst_vaapi_encoder_mpeg2_get_type ())
+#define GST_VAAPI_ENCODER_MPEG2(encoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_MPEG2, GstVaapiEncoderMpeg2))
+#define GST_IS_VAAPI_ENCODER_MPEG2(encoder) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_MPEG2))
+
+typedef struct _GstVaapiEncoderMpeg2 GstVaapiEncoderMpeg2;
+typedef struct _GstVaapiEncoderMpeg2Class GstVaapiEncoderMpeg2Class;
+
+GType
+gst_vaapi_encoder_mpeg2_get_type (void) G_GNUC_CONST;
+
+GstVaapiEncoder *
+gst_vaapi_encoder_mpeg2_new (GstVaapiDisplay * display);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderMpeg2, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_ENCODER_MPEG2_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_mpeg2_priv.h
new file mode 100644 (file)
index 0000000..cded80d
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ *  gstvaapiencoder_mpeg2_priv.h - MPEG-2 encoder (private definitions)
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Guangxin Xu <guangxin.xu@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_MPEG2_PRIV_H
+#define GST_VAAPI_ENCODER_MPEG2_PRIV_H
+
+#include "gstvaapiencoder_priv.h"
+#include "gstvaapiutils_mpeg2.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_ENCODER_MPEG2_CAST(encoder) \
+  ((GstVaapiEncoderMpeg2 *) (encoder))
+
+#define START_CODE_PICUTRE      0x00000100
+#define START_CODE_SLICE        0x00000101
+#define START_CODE_USER         0x000001B2
+#define START_CODE_SEQ          0x000001B3
+#define START_CODE_EXT          0x000001B5
+#define START_CODE_GOP          0x000001B8
+
+struct _GstVaapiEncoderMpeg2
+{
+  GstVaapiEncoder parent_instance;
+
+  GstVaapiProfile profile;
+  GstVaapiLevelMPEG2 level;
+  guint8 profile_idc;
+  guint8 level_idc;
+  guint32 cqp; /* quantizer value for CQP mode */
+  guint32 ip_period;
+
+  /* re-ordering */
+  GQueue b_frames;
+  gboolean dump_frames;
+  gboolean new_gop;
+
+  /* reference list */
+  GstVaapiSurfaceProxy *forward;
+  GstVaapiSurfaceProxy *backward;
+  guint32 frame_num;            /* same value picture header, but it's not mod by 1024 */
+};
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_ENCODER_MPEG2_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_objects.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_objects.c
new file mode 100644 (file)
index 0000000..af1cf61
--- /dev/null
@@ -0,0 +1,583 @@
+/*
+ *  gstvaapiencoder_objects.c - VA encoder objects abstraction
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiencoder_objects.h"
+#include "gstvaapiencoder_priv.h"
+#include "gstvaapisurfaceproxy_priv.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GET_ENCODER(obj)    GST_VAAPI_ENCODER_CAST((obj)->parent_instance.codec)
+#define GET_VA_DISPLAY(obj) GET_ENCODER(obj)->va_display
+#define GET_VA_CONTEXT(obj) GET_ENCODER(obj)->va_context
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Packed Header                                             --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncPackedHeader,
+    gst_vaapi_enc_packed_header);
+
+void
+gst_vaapi_enc_packed_header_destroy (GstVaapiEncPackedHeader * header)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (header), &header->param_id);
+  vaapi_destroy_buffer (GET_VA_DISPLAY (header), &header->data_id);
+  header->param = NULL;
+  header->data = NULL;
+}
+
+gboolean
+gst_vaapi_enc_packed_header_create (GstVaapiEncPackedHeader * header,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  gboolean success;
+
+  header->param_id = VA_INVALID_ID;
+  header->data_id = VA_INVALID_ID;
+
+  success = vaapi_create_buffer (GET_VA_DISPLAY (header),
+      GET_VA_CONTEXT (header),
+      VAEncPackedHeaderParameterBufferType,
+      args->param_size, args->param, &header->param_id, &header->param);
+  if (!success)
+    return FALSE;
+
+  if (!args->data_size)
+    return TRUE;
+
+  success = vaapi_create_buffer (GET_VA_DISPLAY (header),
+      GET_VA_CONTEXT (header),
+      VAEncPackedHeaderDataBufferType,
+      args->data_size, args->data, &header->data_id, &header->data);
+  if (!success)
+    return FALSE;
+  return TRUE;
+}
+
+GstVaapiEncPackedHeader *
+gst_vaapi_enc_packed_header_new (GstVaapiEncoder * encoder,
+    gconstpointer param, guint param_size, gconstpointer data, guint data_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiEncPackedHeaderClass,
+      GST_VAAPI_CODEC_BASE (encoder), param, param_size, data, data_size, 0);
+  return GST_VAAPI_ENC_PACKED_HEADER (object);
+}
+
+gboolean
+gst_vaapi_enc_packed_header_set_data (GstVaapiEncPackedHeader * header,
+    gconstpointer data, guint data_size)
+{
+  gboolean success;
+
+  vaapi_destroy_buffer (GET_VA_DISPLAY (header), &header->data_id);
+  header->data = NULL;
+
+  success = vaapi_create_buffer (GET_VA_DISPLAY (header),
+      GET_VA_CONTEXT (header),
+      VAEncPackedHeaderDataBufferType,
+      data_size, data, &header->data_id, &header->data);
+  if (!success)
+    return FALSE;
+  return TRUE;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Sequence                                                  --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncSequence, gst_vaapi_enc_sequence);
+
+void
+gst_vaapi_enc_sequence_destroy (GstVaapiEncSequence * sequence)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (sequence), &sequence->param_id);
+  sequence->param = NULL;
+}
+
+gboolean
+gst_vaapi_enc_sequence_create (GstVaapiEncSequence * sequence,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  gboolean success;
+
+  sequence->param_id = VA_INVALID_ID;
+  success = vaapi_create_buffer (GET_VA_DISPLAY (sequence),
+      GET_VA_CONTEXT (sequence),
+      VAEncSequenceParameterBufferType,
+      args->param_size, args->param, &sequence->param_id, &sequence->param);
+  if (!success)
+    return FALSE;
+  return TRUE;
+}
+
+GstVaapiEncSequence *
+gst_vaapi_enc_sequence_new (GstVaapiEncoder * encoder,
+    gconstpointer param, guint param_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiEncSequenceClass,
+      GST_VAAPI_CODEC_BASE (encoder), param, param_size, NULL, 0, 0);
+  return GST_VAAPI_ENC_SEQUENCE (object);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Slice                                                     --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncSlice, gst_vaapi_enc_slice);
+
+void
+gst_vaapi_enc_slice_destroy (GstVaapiEncSlice * slice)
+{
+  if (slice->packed_headers) {
+    g_ptr_array_unref (slice->packed_headers);
+    slice->packed_headers = NULL;
+  }
+
+  vaapi_destroy_buffer (GET_VA_DISPLAY (slice), &slice->param_id);
+  slice->param = NULL;
+}
+
+gboolean
+gst_vaapi_enc_slice_create (GstVaapiEncSlice * slice,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  gboolean success;
+
+  slice->param_id = VA_INVALID_ID;
+  success = vaapi_create_buffer (GET_VA_DISPLAY (slice),
+      GET_VA_CONTEXT (slice),
+      VAEncSliceParameterBufferType,
+      args->param_size, args->param, &slice->param_id, &slice->param);
+  if (!success)
+    return FALSE;
+
+  slice->packed_headers = g_ptr_array_new_with_free_func ((GDestroyNotify)
+      gst_vaapi_mini_object_unref);
+  if (!slice->packed_headers)
+    return FALSE;
+
+  return TRUE;
+}
+
+GstVaapiEncSlice *
+gst_vaapi_enc_slice_new (GstVaapiEncoder * encoder,
+    gconstpointer param, guint param_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiEncSliceClass,
+      GST_VAAPI_CODEC_BASE (encoder), param, param_size, NULL, 0, 0);
+  return GST_VAAPI_ENC_SLICE (object);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Misc Parameter Buffer                                     --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncMiscParam, gst_vaapi_enc_misc_param);
+
+void
+gst_vaapi_enc_misc_param_destroy (GstVaapiEncMiscParam * misc)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (misc), &misc->param_id);
+  misc->param = NULL;
+  misc->data = NULL;
+}
+
+gboolean
+gst_vaapi_enc_misc_param_create (GstVaapiEncMiscParam * misc,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  gboolean success;
+
+  misc->param_id = VA_INVALID_ID;
+  success = vaapi_create_buffer (GET_VA_DISPLAY (misc),
+      GET_VA_CONTEXT (misc),
+      VAEncMiscParameterBufferType,
+      args->param_size, args->param, &misc->param_id, &misc->param);
+  if (!success)
+    return FALSE;
+  return TRUE;
+}
+
+GstVaapiEncMiscParam *
+gst_vaapi_enc_misc_param_new (GstVaapiEncoder * encoder,
+    VAEncMiscParameterType type, guint data_size)
+{
+  GstVaapiCodecObject *object;
+  GstVaapiEncMiscParam *misc;
+  VAEncMiscParameterBuffer *va_misc;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiEncMiscParamClass,
+      GST_VAAPI_CODEC_BASE (encoder),
+      NULL, sizeof (VAEncMiscParameterBuffer) + data_size, NULL, 0, 0);
+  if (!object)
+    return NULL;
+
+  misc = GST_VAAPI_ENC_MISC_PARAM (object);
+  va_misc = misc->param;
+  va_misc->type = type;
+  misc->data = va_misc->data;
+  return misc;
+}
+
+/* ------------------------------------------------------------------------- */
+/* ---  Quantization Matrices                                            --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncQMatrix, gst_vaapi_enc_q_matrix);
+
+void
+gst_vaapi_enc_q_matrix_destroy (GstVaapiEncQMatrix * q_matrix)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (q_matrix), &q_matrix->param_id);
+  q_matrix->param = NULL;
+}
+
+gboolean
+gst_vaapi_enc_q_matrix_create (GstVaapiEncQMatrix * q_matrix,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  q_matrix->param_id = VA_INVALID_ID;
+  return vaapi_create_buffer (GET_VA_DISPLAY (q_matrix),
+      GET_VA_CONTEXT (q_matrix), VAQMatrixBufferType,
+      args->param_size, args->param, &q_matrix->param_id, &q_matrix->param);
+}
+
+GstVaapiEncQMatrix *
+gst_vaapi_enc_q_matrix_new (GstVaapiEncoder * encoder,
+    gconstpointer param, guint param_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiEncQMatrixClass,
+      GST_VAAPI_CODEC_BASE (encoder), param, param_size, NULL, 0, 0);
+  if (!object)
+    return NULL;
+  return GST_VAAPI_ENC_Q_MATRIX_CAST (object);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- JPEG Huffman Tables                                               --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncHuffmanTable,
+    gst_vaapi_enc_huffman_table);
+
+void
+gst_vaapi_enc_huffman_table_destroy (GstVaapiEncHuffmanTable * huf_table)
+{
+  vaapi_destroy_buffer (GET_VA_DISPLAY (huf_table), &huf_table->param_id);
+  huf_table->param = NULL;
+}
+
+gboolean
+gst_vaapi_enc_huffman_table_create (GstVaapiEncHuffmanTable * huf_table,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  huf_table->param_id = VA_INVALID_ID;
+  return vaapi_create_buffer (GET_VA_DISPLAY (huf_table),
+      GET_VA_CONTEXT (huf_table), VAHuffmanTableBufferType, args->param_size,
+      args->param, &huf_table->param_id, (void **) &huf_table->param);
+}
+
+GstVaapiEncHuffmanTable *
+gst_vaapi_enc_huffman_table_new (GstVaapiEncoder * encoder,
+    guint8 * data, guint data_size)
+{
+  GstVaapiCodecObject *object;
+
+  object = gst_vaapi_codec_object_new (&GstVaapiEncHuffmanTableClass,
+      GST_VAAPI_CODEC_BASE (encoder), data, data_size, NULL, 0, 0);
+  if (!object)
+    return NULL;
+  return GST_VAAPI_ENC_HUFFMAN_TABLE_CAST (object);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Picture                                                   --- */
+/* ------------------------------------------------------------------------- */
+
+GST_VAAPI_CODEC_DEFINE_TYPE (GstVaapiEncPicture, gst_vaapi_enc_picture);
+
+void
+gst_vaapi_enc_picture_destroy (GstVaapiEncPicture * picture)
+{
+  if (picture->packed_headers) {
+    g_ptr_array_unref (picture->packed_headers);
+    picture->packed_headers = NULL;
+  }
+  if (picture->misc_params) {
+    g_ptr_array_unref (picture->misc_params);
+    picture->misc_params = NULL;
+  }
+  if (picture->slices) {
+    g_ptr_array_unref (picture->slices);
+    picture->slices = NULL;
+  }
+
+  gst_vaapi_codec_object_replace (&picture->q_matrix, NULL);
+  gst_vaapi_codec_object_replace (&picture->huf_table, NULL);
+
+  gst_vaapi_codec_object_replace (&picture->sequence, NULL);
+
+  gst_vaapi_surface_proxy_replace (&picture->proxy, NULL);
+  picture->surface_id = VA_INVALID_ID;
+  picture->surface = NULL;
+
+  vaapi_destroy_buffer (GET_VA_DISPLAY (picture), &picture->param_id);
+  picture->param = NULL;
+
+  if (picture->frame) {
+    gst_video_codec_frame_unref (picture->frame);
+    picture->frame = NULL;
+  }
+}
+
+gboolean
+gst_vaapi_enc_picture_create (GstVaapiEncPicture * picture,
+    const GstVaapiCodecObjectConstructorArgs * args)
+{
+  GstVideoCodecFrame *const frame = (GstVideoCodecFrame *) args->data;
+  gboolean success;
+
+  picture->proxy = gst_video_codec_frame_get_user_data (frame);
+  if (!gst_vaapi_surface_proxy_ref (picture->proxy))
+    return FALSE;
+
+  picture->surface = GST_VAAPI_SURFACE_PROXY_SURFACE (picture->proxy);
+  if (!picture->surface)
+    return FALSE;
+
+  picture->surface_id = GST_VAAPI_SURFACE_ID (picture->surface);
+  if (picture->surface_id == VA_INVALID_ID)
+    return FALSE;
+
+  picture->type = GST_VAAPI_PICTURE_TYPE_NONE;
+  picture->pts = GST_CLOCK_TIME_NONE;
+  picture->frame_num = 0;
+  picture->poc = 0;
+
+  picture->param_id = VA_INVALID_ID;
+  picture->param_size = args->param_size;
+  success = vaapi_create_buffer (GET_VA_DISPLAY (picture),
+      GET_VA_CONTEXT (picture),
+      VAEncPictureParameterBufferType,
+      args->param_size, args->param, &picture->param_id, &picture->param);
+  if (!success)
+    return FALSE;
+  picture->param_size = args->param_size;
+
+  picture->packed_headers = g_ptr_array_new_with_free_func ((GDestroyNotify)
+      gst_vaapi_mini_object_unref);
+  if (!picture->packed_headers)
+    return FALSE;
+
+  picture->misc_params = g_ptr_array_new_with_free_func ((GDestroyNotify)
+      gst_vaapi_mini_object_unref);
+  if (!picture->misc_params)
+    return FALSE;
+
+  picture->slices = g_ptr_array_new_with_free_func ((GDestroyNotify)
+      gst_vaapi_mini_object_unref);
+  if (!picture->slices)
+    return FALSE;
+
+  picture->frame = gst_video_codec_frame_ref (frame);
+  return TRUE;
+}
+
+GstVaapiEncPicture *
+gst_vaapi_enc_picture_new (GstVaapiEncoder * encoder,
+    gconstpointer param, guint param_size, GstVideoCodecFrame * frame)
+{
+  GstVaapiCodecObject *object;
+
+  g_return_val_if_fail (frame != NULL, NULL);
+
+  object = gst_vaapi_codec_object_new (&GstVaapiEncPictureClass,
+      GST_VAAPI_CODEC_BASE (encoder), param, param_size, frame, 0, 0);
+  return GST_VAAPI_ENC_PICTURE (object);
+}
+
+void
+gst_vaapi_enc_picture_set_sequence (GstVaapiEncPicture * picture,
+    GstVaapiEncSequence * sequence)
+{
+  g_return_if_fail (picture != NULL);
+  g_return_if_fail (sequence != NULL);
+
+  gst_vaapi_codec_object_replace (&picture->sequence, sequence);
+}
+
+void
+gst_vaapi_enc_picture_add_packed_header (GstVaapiEncPicture * picture,
+    GstVaapiEncPackedHeader * header)
+{
+  g_return_if_fail (picture != NULL);
+  g_return_if_fail (header != NULL);
+
+  g_ptr_array_add (picture->packed_headers,
+      gst_vaapi_codec_object_ref (header));
+}
+
+void
+gst_vaapi_enc_picture_add_misc_param (GstVaapiEncPicture * picture,
+    GstVaapiEncMiscParam * misc)
+{
+  g_return_if_fail (picture != NULL);
+  g_return_if_fail (misc != NULL);
+
+  g_ptr_array_add (picture->misc_params, gst_vaapi_codec_object_ref (misc));
+}
+
+void
+gst_vaapi_enc_picture_add_slice (GstVaapiEncPicture * picture,
+    GstVaapiEncSlice * slice)
+{
+  g_return_if_fail (picture != NULL);
+  g_return_if_fail (slice != NULL);
+
+  g_ptr_array_add (picture->slices, gst_vaapi_codec_object_ref (slice));
+}
+
+void
+gst_vaapi_enc_slice_add_packed_header (GstVaapiEncSlice * slice,
+    GstVaapiEncPackedHeader * header)
+{
+  g_return_if_fail (slice != NULL);
+  g_return_if_fail (header != NULL);
+
+  g_ptr_array_add (slice->packed_headers, gst_vaapi_codec_object_ref (header));
+}
+
+static gboolean
+do_encode (VADisplay dpy, VAContextID ctx, VABufferID * buf_id, void **buf_ptr)
+{
+  VAStatus status;
+
+  vaapi_unmap_buffer (dpy, *buf_id, buf_ptr);
+
+  status = vaRenderPicture (dpy, ctx, buf_id, 1);
+  if (!vaapi_check_status (status, "vaRenderPicture()"))
+    return FALSE;
+
+  /* XXX: vaRenderPicture() is meant to destroy the VA buffer implicitly */
+  vaapi_destroy_buffer (dpy, buf_id);
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_enc_picture_encode (GstVaapiEncPicture * picture)
+{
+  GstVaapiEncSequence *sequence;
+  GstVaapiEncQMatrix *q_matrix;
+  GstVaapiEncHuffmanTable *huf_table;
+  VADisplay va_display;
+  VAContextID va_context;
+  VAStatus status;
+  guint i;
+
+  g_return_val_if_fail (picture != NULL, FALSE);
+  g_return_val_if_fail (picture->surface_id != VA_INVALID_SURFACE, FALSE);
+
+  va_display = GET_VA_DISPLAY (picture);
+  va_context = GET_VA_CONTEXT (picture);
+
+  GST_DEBUG ("encode picture 0x%08x", picture->surface_id);
+
+  status = vaBeginPicture (va_display, va_context, picture->surface_id);
+  if (!vaapi_check_status (status, "vaBeginPicture()"))
+    return FALSE;
+
+  /* Submit Sequence parameter */
+  sequence = picture->sequence;
+  if (sequence && !do_encode (va_display, va_context,
+          &sequence->param_id, &sequence->param))
+    return FALSE;
+
+  /* Submit Quantization matrix */
+  q_matrix = picture->q_matrix;
+  if (q_matrix && !do_encode (va_display, va_context,
+          &q_matrix->param_id, &q_matrix->param))
+    return FALSE;
+
+  /* Submit huffman table */
+  huf_table = picture->huf_table;
+  if (huf_table && !do_encode (va_display, va_context,
+          &huf_table->param_id, (void **) &huf_table->param))
+    return FALSE;
+
+  /* Submit Packed Headers */
+  for (i = 0; i < picture->packed_headers->len; i++) {
+    GstVaapiEncPackedHeader *const header =
+        g_ptr_array_index (picture->packed_headers, i);
+    if (!do_encode (va_display, va_context,
+            &header->param_id, &header->param) ||
+        !do_encode (va_display, va_context, &header->data_id, &header->data))
+      return FALSE;
+  }
+
+  /* Submit Picture parameter */
+  if (!do_encode (va_display, va_context, &picture->param_id, &picture->param))
+    return FALSE;
+
+  /* Submit Misc Params */
+  for (i = 0; i < picture->misc_params->len; i++) {
+    GstVaapiEncMiscParam *const misc =
+        g_ptr_array_index (picture->misc_params, i);
+    if (!do_encode (va_display, va_context, &misc->param_id, &misc->param))
+      return FALSE;
+  }
+
+  /* Submit Slice parameters */
+  for (i = 0; i < picture->slices->len; i++) {
+    GstVaapiEncSlice *const slice = g_ptr_array_index (picture->slices, i);
+    guint j;
+
+    /* Submit packed_slice_header and packed_raw_data */
+    for (j = 0; j < slice->packed_headers->len; j++) {
+      GstVaapiEncPackedHeader *const header =
+          g_ptr_array_index (slice->packed_headers, j);
+      if (!do_encode (va_display, va_context,
+              &header->param_id, &header->param) ||
+          !do_encode (va_display, va_context, &header->data_id, &header->data))
+        return FALSE;
+    }
+    if (!do_encode (va_display, va_context, &slice->param_id, &slice->param))
+      return FALSE;
+  }
+
+  status = vaEndPicture (va_display, va_context);
+  if (!vaapi_check_status (status, "vaEndPicture()"))
+    return FALSE;
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_objects.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_objects.h
new file mode 100644 (file)
index 0000000..49f271d
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ *  gstvaapiencoder_objects.h - VA encoder objects abstraction
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_OBJECTS_H
+#define GST_VAAPI_ENCODER_OBJECTS_H
+
+#include <gst/vaapi/gstvaapicodec_objects.h>
+#include <gst/vaapi/gstvaapidecoder_objects.h>
+#include <gst/vaapi/gstvaapiencoder.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiEncPicture GstVaapiEncPicture;
+typedef struct _GstVaapiEncSequence GstVaapiEncSequence;
+typedef struct _GstVaapiEncMiscParam GstVaapiEncMiscParam;
+typedef struct _GstVaapiEncSlice GstVaapiEncSlice;
+typedef struct _GstVaapiEncQMatrix GstVaapiEncQMatrix;
+typedef struct _GstVaapiEncHuffmanTable GstVaapiEncHuffmanTable;
+typedef struct _GstVaapiEncPackedHeader GstVaapiEncPackedHeader;
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Packed Header                                             --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_ENC_PACKED_HEADER(obj) \
+  ((GstVaapiEncPackedHeader *) (obj))
+
+/**
+ * GstVaapiEncPackedHeader:
+ *
+ * A #GstVaapiCodecObject holding a packed header (param/data) for the
+ * encoder.
+ */
+struct _GstVaapiEncPackedHeader
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+
+  /*< public >*/
+  VABufferID param_id;
+  gpointer param;
+  VABufferID data_id;
+  gpointer data;
+};
+
+G_GNUC_INTERNAL
+GstVaapiEncPackedHeader *
+gst_vaapi_enc_packed_header_new (GstVaapiEncoder * encoder,
+    gconstpointer param, guint param_size, gconstpointer data, guint data_size);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_enc_packed_header_set_data (GstVaapiEncPackedHeader * header,
+    gconstpointer data, guint data_size);
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Sequence                                                  --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_ENC_SEQUENCE(obj) \
+  ((GstVaapiEncSequence *) (obj))
+
+/**
+ * GstVaapiEncSequence:
+ *
+ * A #GstVaapiCodecObject holding a sequence parameter for encoding.
+ */
+struct _GstVaapiEncSequence
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+
+  /*< public >*/
+  VABufferID param_id;
+  gpointer param;
+};
+
+G_GNUC_INTERNAL
+GstVaapiEncSequence *
+gst_vaapi_enc_sequence_new (GstVaapiEncoder * encoder,
+    gconstpointer param, guint param_size);
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Slice                                                     --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_ENC_SLICE(obj) \
+  ((GstVaapiEncSlice *) (obj))
+
+/**
+ * GstVaapiEncSlice:
+ *
+ * A #GstVaapiCodecObject holding a slice parameter used for encoding.
+ */
+struct _GstVaapiEncSlice
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+
+  /*< public >*/
+  VABufferID param_id;
+  gpointer param;
+  GPtrArray *packed_headers;
+};
+
+G_GNUC_INTERNAL
+GstVaapiEncSlice *
+gst_vaapi_enc_slice_new (GstVaapiEncoder * encoder,
+    gconstpointer param, guint param_size);
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Misc Parameter Buffer                                     --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_ENC_MISC_PARAM(obj) \
+  ((GstVaapiEncMiscParam *) (obj))
+
+/**
+ * GstVaapiEncMiscParam:
+ *
+ * A #GstVaapiCodecObject holding a misc parameter and associated data
+ * used for controlling the encoder dynamically.
+ */
+struct _GstVaapiEncMiscParam
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+  gpointer param;
+
+  /*< public >*/
+  VABufferID param_id;
+  gpointer data;
+};
+
+G_GNUC_INTERNAL
+GstVaapiEncMiscParam *
+gst_vaapi_enc_misc_param_new (GstVaapiEncoder * encoder,
+    VAEncMiscParameterType type, guint data_size);
+
+/* ------------------------------------------------------------------------- */
+/* ---  Quantization Matrices                                            --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_ENC_Q_MATRIX_CAST(obj) \
+  ((GstVaapiEncQMatrix *) (obj))
+
+/**
+ * GstVaapiEncQMatrix:
+ *
+ * A #GstVaapiCodecObject holding a quantization matrix parameter.
+ */
+struct _GstVaapiEncQMatrix
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+  VABufferID param_id;
+
+  /*< public >*/
+  gpointer param;
+};
+
+G_GNUC_INTERNAL
+GstVaapiEncQMatrix *
+gst_vaapi_enc_q_matrix_new (GstVaapiEncoder * encoder, gconstpointer param,
+    guint param_size);
+
+/* ------------------------------------------------------------------------- */
+/* --- JPEG Huffman Tables                                               --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_ENC_HUFFMAN_TABLE_CAST(obj) \
+  ((GstVaapiEncHuffmanTable *) (obj))
+
+/**
+ * GstVaapiEncHuffmanTable:
+ *
+ * A #GstVaapiCodecObject holding huffman table.
+ */
+struct _GstVaapiEncHuffmanTable
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+  VABufferID param_id;
+
+  /*< public >*/
+  gpointer param;
+};
+
+G_GNUC_INTERNAL
+GstVaapiEncHuffmanTable *
+gst_vaapi_enc_huffman_table_new (GstVaapiEncoder * encoder, guint8 * data,
+    guint data_size);
+
+/* ------------------------------------------------------------------------- */
+/* --- Encoder Picture                                                   --- */
+/* ------------------------------------------------------------------------- */
+
+#define GST_VAAPI_ENC_PICTURE(obj) \
+  ((GstVaapiEncPicture *) (obj))
+
+typedef enum
+{
+  GST_VAAPI_ENC_PICTURE_FLAG_IDR          = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 0),
+  GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE    = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 1),
+  GST_VAAPI_ENC_PICTURE_FLAG_LAST         = (GST_VAAPI_CODEC_OBJECT_FLAG_LAST << 2),
+} GstVaapiEncPictureFlags;
+
+#define GST_VAAPI_ENC_PICTURE_FLAGS         GST_VAAPI_MINI_OBJECT_FLAGS
+#define GST_VAAPI_ENC_PICTURE_FLAG_IS_SET   GST_VAAPI_MINI_OBJECT_FLAG_IS_SET
+#define GST_VAAPI_ENC_PICTURE_FLAG_SET      GST_VAAPI_MINI_OBJECT_FLAG_SET
+#define GST_VAAPI_ENC_PICTURE_FLAG_UNSET    GST_VAAPI_MINI_OBJECT_FLAG_UNSET
+
+#define GST_VAAPI_ENC_PICTURE_IS_IDR(picture) \
+    GST_VAAPI_ENC_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_ENC_PICTURE_FLAG_IDR)
+
+#define GST_VAAPI_ENC_PICTURE_IS_REFRENCE(picture) \
+    GST_VAAPI_ENC_PICTURE_FLAG_IS_SET(picture, GST_VAAPI_ENC_PICTURE_FLAG_REFERENCE)
+
+/**
+ * GstVaapiEncPicture:
+ *
+ * A #GstVaapiCodecObject holding a picture parameter for encoding.
+ */
+struct _GstVaapiEncPicture
+{
+  /*< private >*/
+  GstVaapiCodecObject parent_instance;
+  GstVideoCodecFrame *frame;
+  GstVaapiSurfaceProxy *proxy;
+  GstVaapiSurface *surface;
+  VABufferID param_id;
+  guint param_size;
+
+  /* Additional data to pass down */
+  GstVaapiEncSequence *sequence;
+  GPtrArray *packed_headers;
+  GPtrArray *misc_params;
+
+  /*< public >*/
+  GstVaapiPictureType type;
+  VASurfaceID surface_id;
+  gpointer param;
+  GPtrArray *slices;
+  GstVaapiEncQMatrix *q_matrix;
+  GstVaapiEncHuffmanTable *huf_table;
+  GstClockTime pts;
+  guint frame_num;
+  guint poc;
+  guint temporal_id;
+  gboolean has_roi;
+};
+
+G_GNUC_INTERNAL
+GstVaapiEncPicture *
+gst_vaapi_enc_picture_new (GstVaapiEncoder * encoder,
+    gconstpointer param, guint param_size, GstVideoCodecFrame * frame);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_enc_picture_set_sequence (GstVaapiEncPicture * picture,
+    GstVaapiEncSequence * sequence);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_enc_picture_add_packed_header (GstVaapiEncPicture * picture,
+    GstVaapiEncPackedHeader * header);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_enc_picture_add_misc_param (GstVaapiEncPicture * picture,
+    GstVaapiEncMiscParam * misc);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_enc_picture_add_slice (GstVaapiEncPicture * picture,
+    GstVaapiEncSlice * slice);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_enc_slice_add_packed_header (GstVaapiEncSlice *slice,
+    GstVaapiEncPackedHeader * header);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_enc_picture_encode (GstVaapiEncPicture * picture);
+
+#define gst_vaapi_enc_picture_ref(picture) \
+  gst_vaapi_codec_object_ref (picture)
+#define gst_vaapi_enc_picture_unref(picture) \
+  gst_vaapi_codec_object_unref (picture)
+#define gst_vaapi_enc_picture_replace(old_picture_ptr, new_picture) \
+  gst_vaapi_codec_object_replace (old_picture_ptr, new_picture)
+
+/* ------------------------------------------------------------------------- */
+/* --- Helpers to create codec-dependent objects                         --- */
+/* ------------------------------------------------------------------------- */
+
+/* GstVaapiEncSequence */
+#define GST_VAAPI_ENC_SEQUENCE_NEW(codec, encoder)                      \
+  gst_vaapi_enc_sequence_new (GST_VAAPI_ENCODER_CAST (encoder),         \
+      NULL, sizeof (G_PASTE (VAEncSequenceParameterBuffer, codec)))
+
+/* GstVaapiEncMiscParam */
+#define GST_VAAPI_ENC_MISC_PARAM_NEW(type, encoder)                     \
+  gst_vaapi_enc_misc_param_new (GST_VAAPI_ENCODER_CAST (encoder),       \
+      G_PASTE (VAEncMiscParameterType, type),                           \
+      sizeof (G_PASTE (VAEncMiscParameter, type)))
+
+/* GstVaapiEncQualityLevelMiscParam */
+#define GST_VAAPI_ENC_QUALITY_LEVEL_MISC_PARAM_NEW(encoder)             \
+  gst_vaapi_enc_misc_param_new (GST_VAAPI_ENCODER_CAST (encoder),       \
+      VAEncMiscParameterTypeQualityLevel,                               \
+      sizeof (VAEncMiscParameterBufferQualityLevel))
+
+/* GstVaapiEncQuantizationMiscParam */
+#define GST_VAAPI_ENC_QUANTIZATION_MISC_PARAM_NEW(encoder)              \
+  gst_vaapi_enc_misc_param_new (GST_VAAPI_ENCODER_CAST (encoder),       \
+      VAEncMiscParameterTypeQuantization,                               \
+      sizeof (VAEncMiscParameterQuantization))
+
+/* GstVaapiEncPicture  */
+#define GST_VAAPI_ENC_PICTURE_NEW(codec, encoder, frame)                \
+  gst_vaapi_enc_picture_new (GST_VAAPI_ENCODER_CAST (encoder),          \
+      NULL, sizeof (G_PASTE (VAEncPictureParameterBuffer, codec)), frame)
+
+/* GstVaapiEncSlice */
+#define GST_VAAPI_ENC_SLICE_NEW(codec, encoder)                         \
+  gst_vaapi_enc_slice_new (GST_VAAPI_ENCODER_CAST (encoder),            \
+      NULL, sizeof(G_PASTE (VAEncSliceParameterBuffer, codec)))
+
+/* GstVaapiEncQuantMatrix */
+#define GST_VAAPI_ENC_Q_MATRIX_NEW(codec, encoder)                      \
+  gst_vaapi_enc_q_matrix_new (GST_VAAPI_ENCODER_CAST (encoder),         \
+      NULL, sizeof (G_PASTE (VAQMatrixBuffer, codec)))
+
+/* GstVaapiEncHuffmanTable */
+#define GST_VAAPI_ENC_HUFFMAN_TABLE_NEW(codec, encoder)                 \
+  gst_vaapi_enc_huffman_table_new (GST_VAAPI_ENCODER_CAST (encoder),    \
+      NULL, sizeof (G_PASTE (VAHuffmanTableBuffer, codec)))
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_ENCODER_OBJECTS_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_priv.h
new file mode 100644 (file)
index 0000000..189c379
--- /dev/null
@@ -0,0 +1,394 @@
+/*
+ *  gstvaapiencoder_priv.h - VA encoder abstraction (private definitions)
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_PRIV_H
+#define GST_VAAPI_ENCODER_PRIV_H
+
+#include <gst/vaapi/gstvaapiencoder.h>
+#include <gst/vaapi/gstvaapiencoder_objects.h>
+#include <gst/vaapi/gstvaapicontext.h>
+#include <gst/vaapi/gstvaapivideopool.h>
+#include <gst/video/gstvideoutils.h>
+#include <gst/vaapi/gstvaapivalue.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_ENCODER_CAST(encoder) \
+    ((GstVaapiEncoder *)(encoder))
+
+#define GST_VAAPI_ENCODER_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_ENCODER, GstVaapiEncoderClass))
+
+#define GST_VAAPI_ENCODER_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_ENCODER, GstVaapiEncoderClass))
+
+/**
+ * GST_VAAPI_ENCODER_PACKED_HEADERS:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the required set of VA packed headers that
+ * need to be submitted along with the corresponding param buffers.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_PACKED_HEADERS
+#define GST_VAAPI_ENCODER_PACKED_HEADERS(encoder) \
+    GST_VAAPI_ENCODER_CAST(encoder)->packed_headers
+
+/**
+ * GST_VAAPI_ENCODER_DISPLAY:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the #GstVaapiDisplay of @encoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_DISPLAY
+#define GST_VAAPI_ENCODER_DISPLAY(encoder) \
+    GST_VAAPI_ENCODER_CAST(encoder)->display
+
+/**
+ * GST_VAAPI_ENCODER_CONTEXT:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the #GstVaapiContext of @encoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_CONTEXT
+#define GST_VAAPI_ENCODER_CONTEXT(encoder) \
+    GST_VAAPI_ENCODER_CAST(encoder)->context
+
+/**
+ * GST_VAAPI_ENCODER_VIDEO_INFO:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the #GstVideoInfo of @encoder.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_VIDEO_INFO
+#define GST_VAAPI_ENCODER_VIDEO_INFO(encoder) \
+  (&GST_VAAPI_ENCODER_CAST (encoder)->video_info)
+
+/**
+ * GST_VAAPI_ENCODER_WIDTH:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the coded width of the picture.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_WIDTH
+#define GST_VAAPI_ENCODER_WIDTH(encoder) \
+  (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->width)
+
+/**
+ * GST_VAAPI_ENCODER_HEIGHT:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the coded height of the picture.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_HEIGHT
+#define GST_VAAPI_ENCODER_HEIGHT(encoder) \
+  (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->height)
+
+/**
+ * GST_VAAPI_ENCODER_FPS_N:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the coded framerate numerator.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_FPS_N
+#define GST_VAAPI_ENCODER_FPS_N(encoder) \
+  (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->fps_n)
+
+/**
+ * GST_VAAPI_ENCODER_FPS_D:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the coded framerate denominator.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_FPS_D
+#define GST_VAAPI_ENCODER_FPS_D(encoder) \
+  (GST_VAAPI_ENCODER_VIDEO_INFO (encoder)->fps_d)
+
+/**
+ * GST_VAAPI_ENCODER_RATE_CONTROL:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the rate control.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_RATE_CONTROL
+#define GST_VAAPI_ENCODER_RATE_CONTROL(encoder) \
+  (GST_VAAPI_ENCODER_CAST (encoder)->rate_control)
+
+/**
+ * GST_VAAPI_ENCODER_KEYFRAME_PERIOD:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the keyframe period.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_KEYFRAME_PERIOD
+#define GST_VAAPI_ENCODER_KEYFRAME_PERIOD(encoder) \
+  (GST_VAAPI_ENCODER_CAST (encoder)->keyframe_period)
+
+/**
+ * GST_VAAPI_ENCODER_TUNE:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the tuning option.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_TUNE
+#define GST_VAAPI_ENCODER_TUNE(encoder) \
+  (GST_VAAPI_ENCODER_CAST (encoder)->tune)
+
+/**
+ * GST_VAAPI_ENCODER_QUALITY_LEVEL:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to the quality level
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_QUALITY_LEVEL
+#define GST_VAAPI_ENCODER_QUALITY_LEVEL(encoder) \
+  (GST_VAAPI_ENCODER_CAST (encoder)->va_quality_level.quality_level)
+
+/**
+ * GST_VAAPI_ENCODER_VA_RATE_CONTROL:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to #VAEncMiscParameterRateControl
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_VA_RATE_CONTROL
+#define GST_VAAPI_ENCODER_VA_RATE_CONTROL(encoder) \
+  (GST_VAAPI_ENCODER_CAST (encoder)->va_ratecontrol)
+
+/**
+ * GST_VAAPI_ENCODER_VA_FRAME_RATE:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to #VAEncMiscParameterFrameRate
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_VA_FRAME_RATE
+#define GST_VAAPI_ENCODER_VA_FRAME_RATE(encoder) \
+  (GST_VAAPI_ENCODER_CAST (encoder)->va_framerate)
+
+/**
+ * GST_VAAPI_ENCODER_VA_HRD:
+ * @encoder: a #GstVaapiEncoder
+ *
+ * Macro that evaluates to #VAEncMiscParameterHRD
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_ENCODER_VA_HRD
+#define GST_VAAPI_ENCODER_VA_HRD(encoder) \
+  (GST_VAAPI_ENCODER_CAST (encoder)->va_hrd)
+
+/* Generate a mask for the supplied tuning option (internal) */
+#define GST_VAAPI_ENCODER_TUNE_MASK(TUNE) \
+  (1U << G_PASTE (GST_VAAPI_ENCODER_TUNE_, TUNE))
+
+#define GST_VAAPI_TYPE_ENCODER_TUNE \
+  (gst_vaapi_encoder_tune_get_type ())
+
+#define GST_VAAPI_TYPE_ENCODER_MBBRC \
+  (gst_vaapi_encoder_mbbrc_get_type ())
+
+typedef struct _GstVaapiEncoderClass GstVaapiEncoderClass;
+typedef struct _GstVaapiEncoderClassData GstVaapiEncoderClassData;
+
+struct _GstVaapiEncoder
+{
+  /*< private >*/
+  GstObject parent_instance;
+
+  GPtrArray *properties;
+  GstVaapiDisplay *display;
+  GstVaapiContext *context;
+  GstVaapiContextInfo context_info;
+  GstVaapiEncoderTune tune;
+  guint packed_headers;
+
+  VADisplay va_display;
+  VAContextID va_context;
+  GstVideoInfo video_info;
+  GstVaapiProfile profile;
+  guint num_ref_frames;
+  GstVaapiRateControl rate_control;
+  guint32 rate_control_mask;
+  guint bitrate; /* kbps */
+  guint target_percentage;
+  guint keyframe_period;
+
+  /* Maximum number of reference frames supported
+   * for the reference picture list 0 and list 2 */
+  guint max_num_ref_frames_0;
+  guint max_num_ref_frames_1;
+
+  /* parameters */
+  VAEncMiscParameterBufferQualityLevel va_quality_level;
+
+  GMutex mutex;
+  GCond surface_free;
+  GCond codedbuf_free;
+  guint codedbuf_size;
+  GstVaapiVideoPool *codedbuf_pool;
+  GAsyncQueue *codedbuf_queue;
+  guint32 num_codedbuf_queued;
+
+  guint got_packed_headers:1;
+  guint got_rate_control_mask:1;
+
+  /* miscellaneous buffer parameters */
+  VAEncMiscParameterRateControl va_ratecontrol;
+  VAEncMiscParameterFrameRate va_framerate;
+  VAEncMiscParameterHRD va_hrd;
+
+  gint8 default_roi_value;
+
+  /* trellis quantization */
+  gboolean trellis;
+};
+
+struct _GstVaapiEncoderClassData
+{
+  /*< private >*/
+  GstVaapiCodec codec;
+  guint32 packed_headers;
+
+  GType (*rate_control_get_type)(void);
+  GstVaapiRateControl default_rate_control;
+  guint32 rate_control_mask;
+
+  GType (*encoder_tune_get_type)(void);
+  GstVaapiEncoderTune default_encoder_tune;
+  guint32 encoder_tune_mask;
+};
+
+#define GST_VAAPI_ENCODER_DEFINE_CLASS_DATA(CODEC)                      \
+  GST_VAAPI_TYPE_DEFINE_ENUM_SUBSET_FROM_MASK(                          \
+      G_PASTE (GstVaapiRateControl, CODEC),                             \
+      G_PASTE (gst_vaapi_rate_control_, CODEC),                         \
+      GST_VAAPI_TYPE_RATE_CONTROL, SUPPORTED_RATECONTROLS);             \
+                                                                        \
+  GST_VAAPI_TYPE_DEFINE_ENUM_SUBSET_FROM_MASK(                          \
+      G_PASTE (GstVaapiEncoderTune, CODEC),                             \
+      G_PASTE (gst_vaapi_encoder_tune_, CODEC),                         \
+      GST_VAAPI_TYPE_ENCODER_TUNE, SUPPORTED_TUNE_OPTIONS);             \
+                                                                        \
+  static const GstVaapiEncoderClassData g_class_data = {                \
+    .codec = G_PASTE (GST_VAAPI_CODEC_, CODEC),                         \
+    .packed_headers = SUPPORTED_PACKED_HEADERS,                         \
+    .rate_control_get_type =                                            \
+        G_PASTE (G_PASTE (gst_vaapi_rate_control_, CODEC), _get_type),  \
+    .default_rate_control = DEFAULT_RATECONTROL,                        \
+    .rate_control_mask = SUPPORTED_RATECONTROLS,                        \
+    .encoder_tune_get_type =                                            \
+        G_PASTE (G_PASTE (gst_vaapi_encoder_tune_, CODEC), _get_type),  \
+    .default_encoder_tune = GST_VAAPI_ENCODER_TUNE_NONE,                \
+    .encoder_tune_mask = SUPPORTED_TUNE_OPTIONS,                        \
+  }
+
+struct _GstVaapiEncoderClass
+{
+  /*< private >*/
+  GstObjectClass parent_class;
+
+  const GstVaapiEncoderClassData *class_data;
+
+  GstVaapiEncoderStatus (*reconfigure)  (GstVaapiEncoder * encoder);
+  GstVaapiEncoderStatus (*reordering)   (GstVaapiEncoder * encoder,
+                                         GstVideoCodecFrame * in,
+                                         GstVaapiEncPicture ** out);
+  GstVaapiEncoderStatus (*encode)       (GstVaapiEncoder * encoder,
+                                         GstVaapiEncPicture * picture,
+                                         GstVaapiCodedBufferProxy * codedbuf);
+
+  GstVaapiEncoderStatus (*flush)        (GstVaapiEncoder * encoder);
+
+  /* get_codec_data can be NULL */
+  GstVaapiEncoderStatus (*get_codec_data) (GstVaapiEncoder * encoder,
+                                           GstBuffer ** codec_data);
+
+  /* Iterator that retrieves the pending pictures in the reordered
+   * list */
+  gboolean              (*get_pending_reordered) (GstVaapiEncoder * encoder,
+                                                  GstVaapiEncPicture ** picture,
+                                                  gpointer * state);
+};
+
+G_GNUC_INTERNAL
+GstVaapiSurfaceProxy *
+gst_vaapi_encoder_create_surface (GstVaapiEncoder *
+    encoder);
+
+static inline void
+gst_vaapi_encoder_release_surface (GstVaapiEncoder * encoder,
+    GstVaapiSurfaceProxy * proxy)
+{
+  gst_vaapi_surface_proxy_unref (proxy);
+}
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_encoder_ensure_param_quality_level (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture * picture);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_encoder_ensure_param_control_rate (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture * picture);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_encoder_ensure_param_roi_regions (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture * picture);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_encoder_ensure_param_trellis (GstVaapiEncoder * encoder,
+    GstVaapiEncPicture * picture);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_encoder_ensure_num_slices (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint,
+    guint media_max_slices, guint * num_slices);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_encoder_ensure_max_num_ref_frames (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_encoder_ensure_tile_support (GstVaapiEncoder * encoder,
+    GstVaapiProfile profile, GstVaapiEntrypoint entrypoint);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_ENCODER_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp8.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp8.c
new file mode 100644 (file)
index 0000000..99ffa46
--- /dev/null
@@ -0,0 +1,701 @@
+/*
+ *  gstvaapiencoder_vp8.c - VP8 encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <gst/base/gstbitwriter.h>
+#include <gst/codecparsers/gstvp8parser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiencoder_priv.h"
+#include "gstvaapiencoder_vp8.h"
+#include "gstvaapicodedbufferproxy_priv.h"
+#include "gstvaapisurface.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/* Define default rate control mode ("constant-qp") */
+#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP
+
+/* Supported set of VA rate controls, within this implementation */
+#define SUPPORTED_RATECONTROLS                  \
+  (GST_VAAPI_RATECONTROL_MASK (CQP) |           \
+   GST_VAAPI_RATECONTROL_MASK (CBR) |           \
+   GST_VAAPI_RATECONTROL_MASK (VBR))
+
+/* Supported set of tuning options, within this implementation */
+#define SUPPORTED_TUNE_OPTIONS \
+  (GST_VAAPI_ENCODER_TUNE_MASK (NONE))
+
+/* Supported set of VA packed headers, within this implementation */
+#define SUPPORTED_PACKED_HEADERS                \
+  (VA_ENC_PACKED_HEADER_NONE)
+
+#define DEFAULT_LOOP_FILTER_LEVEL 0
+#define DEFAULT_SHARPNESS_LEVEL 0
+#define DEFAULT_YAC_QI 40
+
+/* ------------------------------------------------------------------------- */
+/* --- VP8 Encoder                                                      --- */
+/* ------------------------------------------------------------------------- */
+
+struct _GstVaapiEncoderVP8
+{
+  GstVaapiEncoder parent_instance;
+  GstVaapiProfile profile;
+  guint loop_filter_level;
+  guint sharpness_level;
+  guint yac_qi;
+  guint frame_num;
+  /* reference list */
+  GstVaapiSurfaceProxy *last_ref;
+  GstVaapiSurfaceProxy *golden_ref;
+  GstVaapiSurfaceProxy *alt_ref;
+};
+
+/* Derives the profile that suits best to the configuration */
+static GstVaapiEncoderStatus
+ensure_profile (GstVaapiEncoderVP8 * encoder)
+{
+  /* Always start from "simple" profile for maximum compatibility */
+  encoder->profile = GST_VAAPI_PROFILE_VP8;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+/* Derives the profile supported by the underlying hardware */
+static gboolean
+ensure_hw_profile (GstVaapiEncoderVP8 * encoder)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_ENCODER_DISPLAY (encoder);
+  GstVaapiEntrypoint entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
+  GstVaapiProfile profile, profiles[2];
+  guint i, num_profiles = 0;
+
+  profiles[num_profiles++] = encoder->profile;
+
+  profile = GST_VAAPI_PROFILE_UNKNOWN;
+  for (i = 0; i < num_profiles; i++) {
+    if (gst_vaapi_display_has_encoder (display, profiles[i], entrypoint)) {
+      profile = profiles[i];
+      break;
+    }
+  }
+  if (profile == GST_VAAPI_PROFILE_UNKNOWN)
+    goto error_unsupported_profile;
+
+  GST_VAAPI_ENCODER_CAST (encoder)->profile = profile;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_profile:
+  {
+    GST_ERROR ("unsupported HW profile %s",
+        gst_vaapi_profile_get_va_name (encoder->profile));
+    return FALSE;
+  }
+}
+
+static gboolean
+ensure_bitrate (GstVaapiEncoderVP8 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  /* Default compression: 64 bits per macroblock  */
+  switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
+    case GST_VAAPI_RATECONTROL_CBR:
+    case GST_VAAPI_RATECONTROL_VBR:
+      if (!base_encoder->bitrate) {
+        base_encoder->bitrate =
+            gst_util_uint64_scale (GST_VAAPI_ENCODER_WIDTH (encoder) *
+            GST_VAAPI_ENCODER_HEIGHT (encoder),
+            GST_VAAPI_ENCODER_FPS_N (encoder),
+            GST_VAAPI_ENCODER_FPS_D (encoder)) / (4 * 1000);
+      }
+      break;
+    default:
+      base_encoder->bitrate = 0;
+      break;
+  }
+
+  return TRUE;
+}
+
+static GstVaapiEncoderStatus
+set_context_info (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderVP8 *encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
+  GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+
+  /* Maximum sizes for common headers (in bytes) */
+  enum
+  {
+    MAX_FRAME_TAG_SIZE = 10,
+    MAX_UPDATE_SEGMENTATION_SIZE = 13,
+    MAX_MB_LF_ADJUSTMENTS_SIZE = 9,
+    MAX_QUANT_INDICES_SIZE = 5,
+    MAX_TOKEN_PROB_UPDATE_SIZE = 1188,
+    MAX_MV_PROBE_UPDATE_SIZE = 38,
+    MAX_REST_OF_FRAME_HDR_SIZE = 15
+  };
+
+  if (!ensure_hw_profile (encoder))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  base_encoder->num_ref_frames = 3;
+
+  /* Only YUV 4:2:0 formats are supported for now. */
+  /* Assumig 4 times compression ratio */
+  base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) *
+      GST_ROUND_UP_16 (vip->height) * 12 / 4;
+
+  base_encoder->codedbuf_size +=
+      MAX_FRAME_TAG_SIZE + MAX_UPDATE_SEGMENTATION_SIZE +
+      MAX_MB_LF_ADJUSTMENTS_SIZE + MAX_QUANT_INDICES_SIZE +
+      MAX_TOKEN_PROB_UPDATE_SIZE + MAX_MV_PROBE_UPDATE_SIZE +
+      MAX_REST_OF_FRAME_HDR_SIZE;
+
+  base_encoder->context_info.profile = base_encoder->profile;
+  base_encoder->context_info.entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static void
+clear_ref (GstVaapiEncoderVP8 * encoder, GstVaapiSurfaceProxy ** ref)
+{
+  if (*ref) {
+    gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder), *ref);
+    *ref = NULL;
+  }
+}
+
+static void
+clear_references (GstVaapiEncoderVP8 * encoder)
+{
+  clear_ref (encoder, &encoder->last_ref);
+  clear_ref (encoder, &encoder->golden_ref);
+  clear_ref (encoder, &encoder->alt_ref);
+}
+
+static void
+push_reference (GstVaapiEncoderVP8 * encoder, GstVaapiSurfaceProxy * ref)
+{
+  if (encoder->last_ref == NULL) {
+    encoder->golden_ref = gst_vaapi_surface_proxy_ref (ref);
+    encoder->alt_ref = gst_vaapi_surface_proxy_ref (ref);
+  } else {
+    clear_ref (encoder, &encoder->alt_ref);
+    encoder->alt_ref = encoder->golden_ref;
+    encoder->golden_ref = encoder->last_ref;
+  }
+  encoder->last_ref = ref;
+}
+
+static gboolean
+fill_sequence (GstVaapiEncoderVP8 * encoder, GstVaapiEncSequence * sequence)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  VAEncSequenceParameterBufferVP8 *const seq_param = sequence->param;
+
+  memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferVP8));
+
+  seq_param->frame_width = GST_VAAPI_ENCODER_WIDTH (encoder);
+  seq_param->frame_height = GST_VAAPI_ENCODER_HEIGHT (encoder);
+
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CBR ||
+      GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_VBR)
+    seq_param->bits_per_second = base_encoder->bitrate * 1000;
+
+  seq_param->intra_period = base_encoder->keyframe_period;
+
+  return TRUE;
+}
+
+static gboolean
+ensure_sequence (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncSequence *sequence;
+
+  g_assert (picture);
+
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_I)
+    return TRUE;
+
+  sequence = GST_VAAPI_ENC_SEQUENCE_NEW (VP8, encoder);
+  if (!sequence)
+    goto error;
+
+  if (!fill_sequence (encoder, sequence))
+    goto error;
+
+  gst_vaapi_enc_picture_set_sequence (picture, sequence);
+  gst_vaapi_codec_object_replace (&sequence, NULL);
+  return TRUE;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+    return FALSE;
+  }
+}
+
+static gboolean
+ensure_control_rate_params (GstVaapiEncoderVP8 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
+    return TRUE;
+
+  /* RateControl params */
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).initial_qp = encoder->yac_qi;
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).min_qp = 1;
+
+  /* *INDENT-OFF* */
+  /* HRD params */
+  GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) {
+    .buffer_size = base_encoder->bitrate * 1000 * 2,
+    .initial_buffer_fullness = base_encoder->bitrate * 1000,
+  };
+  /* *INDENT-ON* */
+
+  return TRUE;
+}
+
+static gboolean
+ensure_misc_params (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture))
+    return FALSE;
+
+  if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+fill_picture (GstVaapiEncoderVP8 * encoder,
+    GstVaapiEncPicture * picture,
+    GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
+{
+  VAEncPictureParameterBufferVP8 *const pic_param = picture->param;
+  int i;
+
+  memset (pic_param, 0, sizeof (VAEncPictureParameterBufferVP8));
+
+  pic_param->reconstructed_frame = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
+  pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf);
+
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_P) {
+    pic_param->pic_flags.bits.frame_type = 1;
+    pic_param->ref_arf_frame =
+        GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->alt_ref);
+    pic_param->ref_gf_frame =
+        GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->golden_ref);
+    pic_param->ref_last_frame =
+        GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->last_ref);
+    pic_param->pic_flags.bits.refresh_last = 1;
+    pic_param->pic_flags.bits.refresh_golden_frame = 0;
+    pic_param->pic_flags.bits.copy_buffer_to_golden = 1;
+    pic_param->pic_flags.bits.refresh_alternate_frame = 0;
+    pic_param->pic_flags.bits.copy_buffer_to_alternate = 2;
+  } else {
+    pic_param->ref_last_frame = VA_INVALID_SURFACE;
+    pic_param->ref_gf_frame = VA_INVALID_SURFACE;
+    pic_param->ref_arf_frame = VA_INVALID_SURFACE;
+    pic_param->pic_flags.bits.refresh_last = 1;
+    pic_param->pic_flags.bits.refresh_golden_frame = 1;
+    pic_param->pic_flags.bits.refresh_alternate_frame = 1;
+  }
+
+  pic_param->pic_flags.bits.show_frame = 1;
+
+  if (encoder->loop_filter_level) {
+    pic_param->pic_flags.bits.version = 1;
+    pic_param->pic_flags.bits.loop_filter_type = 1;     /* Enable simple loop filter */
+    /* Disabled segmentation, so what matters is only loop_filter_level[0] */
+    for (i = 0; i < 4; i++)
+      pic_param->loop_filter_level[i] = encoder->loop_filter_level;
+  }
+
+  pic_param->sharpness_level = encoder->sharpness_level;
+
+  /* Used for CBR */
+  pic_param->clamp_qindex_low = 0;
+  pic_param->clamp_qindex_high = 127;
+
+  return TRUE;
+}
+
+static gboolean
+ensure_picture (GstVaapiEncoderVP8 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiCodedBuffer *const codedbuf =
+      GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
+
+  if (!fill_picture (encoder, picture, codedbuf, surface))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+fill_quantization_table (GstVaapiEncoderVP8 * encoder,
+    GstVaapiEncPicture * picture, GstVaapiEncQMatrix * q_matrix)
+{
+  VAQMatrixBufferVP8 *const qmatrix_param = q_matrix->param;
+  int i;
+
+  memset (qmatrix_param, 0, sizeof (VAQMatrixBufferVP8));
+
+  /* DefaultYacQantVal = 8 for I frame, which is ac_qlookup[4] and
+   * DefaultYacQantVAl = 44 for P frame, which is ac_qllookup[40] */
+  for (i = 0; i < 4; i++) {
+    if (encoder->yac_qi == DEFAULT_YAC_QI) {
+      if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
+        qmatrix_param->quantization_index[i] = 4;
+      else
+        qmatrix_param->quantization_index[i] = 40;
+    } else
+      qmatrix_param->quantization_index[i] = encoder->yac_qi;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+ensure_quantization_table (GstVaapiEncoderVP8 * encoder,
+    GstVaapiEncPicture * picture)
+{
+  g_assert (picture);
+
+  picture->q_matrix = GST_VAAPI_ENC_Q_MATRIX_NEW (VP8, encoder);
+  if (!picture->q_matrix) {
+    GST_ERROR ("failed to allocate quantiser table");
+    return GST_VAAPI_DECODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  if (!fill_quantization_table (encoder, picture, picture->q_matrix))
+    return FALSE;
+
+  return TRUE;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_vp8_encode (GstVaapiEncoder * base_encoder,
+    GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
+{
+  GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
+  GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  GstVaapiSurfaceProxy *reconstruct = NULL;
+
+  reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
+
+  g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
+
+  if (!ensure_sequence (encoder, picture))
+    goto error;
+  if (!ensure_misc_params (encoder, picture))
+    goto error;
+  if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
+    goto error;
+  if (!ensure_quantization_table (encoder, picture))
+    goto error;
+  if (!gst_vaapi_enc_picture_encode (picture))
+    goto error;
+  if (reconstruct) {
+    if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
+      clear_references (encoder);
+    push_reference (encoder, reconstruct);
+  }
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    if (reconstruct)
+      gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
+          reconstruct);
+    return ret;
+  }
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_vp8_flush (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
+
+  encoder->frame_num = 0;
+  clear_references (encoder);
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_vp8_reordering (GstVaapiEncoder * base_encoder,
+    GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
+{
+  GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
+  GstVaapiEncPicture *picture = NULL;
+  GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  if (!frame)
+    return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
+
+  picture = GST_VAAPI_ENC_PICTURE_NEW (VP8, encoder, frame);
+  if (!picture) {
+    GST_WARNING ("create VP8 picture failed, frame timestamp:%"
+        GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  if (encoder->frame_num >= base_encoder->keyframe_period) {
+    encoder->frame_num = 0;
+    clear_references (encoder);
+  }
+  if (encoder->frame_num == 0) {
+    picture->type = GST_VAAPI_PICTURE_TYPE_I;
+    GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
+  } else {
+    picture->type = GST_VAAPI_PICTURE_TYPE_P;
+  }
+
+  encoder->frame_num++;
+  *output = picture;
+  return status;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_vp8_reconfigure (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (base_encoder);
+  GstVaapiEncoderStatus status;
+
+  status = ensure_profile (encoder);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return status;
+
+  if (!ensure_bitrate (encoder))
+    goto error;
+
+  ensure_control_rate_params (encoder);
+  return set_context_info (base_encoder);
+
+  /* ERRORS */
+error:
+  {
+    return GST_VAAPI_ENCODER_STATUS_ERROR_OPERATION_FAILED;
+  }
+}
+
+struct _GstVaapiEncoderVP8Class
+{
+  GstVaapiEncoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiEncoderVP8, gst_vaapi_encoder_vp8,
+    GST_TYPE_VAAPI_ENCODER);
+
+static void
+gst_vaapi_encoder_vp8_init (GstVaapiEncoderVP8 * encoder)
+{
+  encoder->frame_num = 0;
+  encoder->last_ref = NULL;
+  encoder->golden_ref = NULL;
+  encoder->alt_ref = NULL;
+}
+
+static void
+gst_vaapi_encoder_vp8_finalize (GObject * object)
+{
+  GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (object);
+  clear_references (encoder);
+  G_OBJECT_CLASS (gst_vaapi_encoder_vp8_parent_class)->finalize (object);
+}
+
+/**
+ * @ENCODER_VP8_PROP_RATECONTROL: Rate control (#GstVaapiRateControl).
+ * @ENCODER_VP8_PROP_TUNE: The tuning options (#GstVaapiEncoderTune).
+ * @ENCODER_VP8_PROP_LOOP_FILTER_LEVEL: Loop Filter Level(uint).
+ * @ENCODER_VP8_PROP_LOOP_SHARPNESS_LEVEL: Sharpness Level(uint).
+ * @ENCODER_VP8_PROP_YAC_Q_INDEX: Quantization table index for luma AC(uint).
+ *
+ * The set of VP8 encoder specific configurable properties.
+ */
+enum
+{
+  ENCODER_VP8_PROP_RATECONTROL = 1,
+  ENCODER_VP8_PROP_TUNE,
+  ENCODER_VP8_PROP_LOOP_FILTER_LEVEL,
+  ENCODER_VP8_PROP_SHARPNESS_LEVEL,
+  ENCODER_VP8_PROP_YAC_Q_INDEX,
+  ENCODER_VP8_N_PROPERTIES
+};
+
+static GParamSpec *properties[ENCODER_VP8_N_PROPERTIES];
+
+static void
+gst_vaapi_encoder_vp8_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+  GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (object);
+
+  if (base_encoder->num_codedbuf_queued > 0) {
+    GST_ERROR_OBJECT (object,
+        "failed to set any property after encoding started");
+    return;
+  }
+
+  switch (prop_id) {
+    case ENCODER_VP8_PROP_RATECONTROL:
+      gst_vaapi_encoder_set_rate_control (base_encoder,
+          g_value_get_enum (value));
+      break;
+    case ENCODER_VP8_PROP_TUNE:
+      gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value));
+      break;
+    case ENCODER_VP8_PROP_LOOP_FILTER_LEVEL:
+      encoder->loop_filter_level = g_value_get_uint (value);
+      break;
+    case ENCODER_VP8_PROP_SHARPNESS_LEVEL:
+      encoder->sharpness_level = g_value_get_uint (value);
+      break;
+    case ENCODER_VP8_PROP_YAC_Q_INDEX:
+      encoder->yac_qi = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_encoder_vp8_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoderVP8 *const encoder = GST_VAAPI_ENCODER_VP8 (object);
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+
+  switch (prop_id) {
+    case ENCODER_VP8_PROP_RATECONTROL:
+      g_value_set_enum (value, base_encoder->rate_control);
+      break;
+    case ENCODER_VP8_PROP_TUNE:
+      g_value_set_enum (value, base_encoder->tune);
+      break;
+    case ENCODER_VP8_PROP_LOOP_FILTER_LEVEL:
+      g_value_set_uint (value, encoder->loop_filter_level);
+      break;
+    case ENCODER_VP8_PROP_SHARPNESS_LEVEL:
+      g_value_set_uint (value, encoder->sharpness_level);
+      break;
+    case ENCODER_VP8_PROP_YAC_Q_INDEX:
+      g_value_set_uint (value, encoder->yac_qi);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (VP8);
+
+static void
+gst_vaapi_encoder_vp8_class_init (GstVaapiEncoderVP8Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass);
+
+  encoder_class->class_data = &g_class_data;
+  encoder_class->reconfigure = gst_vaapi_encoder_vp8_reconfigure;
+  encoder_class->reordering = gst_vaapi_encoder_vp8_reordering;
+  encoder_class->encode = gst_vaapi_encoder_vp8_encode;
+  encoder_class->flush = gst_vaapi_encoder_vp8_flush;
+
+  object_class->set_property = gst_vaapi_encoder_vp8_set_property;
+  object_class->get_property = gst_vaapi_encoder_vp8_get_property;
+  object_class->finalize = gst_vaapi_encoder_vp8_finalize;
+
+  properties[ENCODER_VP8_PROP_RATECONTROL] =
+      g_param_spec_enum ("rate-control",
+      "Rate Control", "Rate control mode",
+      g_class_data.rate_control_get_type (),
+      g_class_data.default_rate_control,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_VP8_PROP_TUNE] =
+      g_param_spec_enum ("tune", "Encoder Tuning", "Encoder tuning option",
+      g_class_data.encoder_tune_get_type (),
+      g_class_data.default_encoder_tune,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_VP8_PROP_LOOP_FILTER_LEVEL] =
+      g_param_spec_uint ("loop-filter-level", "Loop Filter Level",
+      "Controls the deblocking filter strength", 0, 63,
+      DEFAULT_LOOP_FILTER_LEVEL,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_VP8_PROP_SHARPNESS_LEVEL] =
+      g_param_spec_uint ("sharpness-level", "Sharpness Level",
+      "Controls the deblocking filter sensitivity", 0, 7,
+      DEFAULT_SHARPNESS_LEVEL,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_VP8_PROP_YAC_Q_INDEX] =
+      g_param_spec_uint ("yac-qi",
+      "Luma AC Quant Table index",
+      "Quantization Table index for Luma AC Coefficients,"
+      " (in default case, yac_qi=4 for key frames and yac_qi=40"
+      " for P frames)",
+      0, 127, DEFAULT_YAC_QI,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  g_object_class_install_properties (object_class, ENCODER_VP8_N_PROPERTIES,
+      properties);
+
+  gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0);
+  gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0);
+}
+
+/**
+ * gst_vaapi_encoder_vp8_new:
+ * @display: a #GstVaapiDisplay
+ *
+ * Creates a new #GstVaapiEncoder for VP8 encoding.
+ *
+ * Return value: the newly allocated #GstVaapiEncoder object
+ */
+GstVaapiEncoder *
+gst_vaapi_encoder_vp8_new (GstVaapiDisplay * display)
+{
+  return g_object_new (GST_TYPE_VAAPI_ENCODER_VP8, "display", display, NULL);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp8.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp8.h
new file mode 100644 (file)
index 0000000..e17c616
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  gstvaapiencoder_vp8.h VP8G encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_VP8_H
+#define GST_VAAPI_ENCODER_VP8_H
+
+#include <gst/vaapi/gstvaapiencoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_ENCODER_VP8 \
+    (gst_vaapi_encoder_vp8_get_type ())
+#define GST_VAAPI_ENCODER_VP8(encoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_VP8, GstVaapiEncoderVP8))
+#define GST_IS_VAAPI_ENCODER_VP8(encoder) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_VP8))
+
+typedef struct _GstVaapiEncoderVP8 GstVaapiEncoderVP8;
+typedef struct _GstVaapiEncoderVP8Class GstVaapiEncoderVP8Class;
+
+GType
+gst_vaapi_encoder_vp8_get_type (void) G_GNUC_CONST;
+
+GstVaapiEncoder *
+gst_vaapi_encoder_vp8_new (GstVaapiDisplay * display);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderVP8, gst_object_unref)
+
+G_END_DECLS
+#endif /*GST_VAAPI_ENCODER_VP8_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp9.c
new file mode 100644 (file)
index 0000000..bd47c0d
--- /dev/null
@@ -0,0 +1,824 @@
+/*
+ *  gstvaapiencoder_vp9.c - VP9 encoder
+ *
+ *  Copyright (C) 2016 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <gst/base/gstbitwriter.h>
+#include <gst/codecparsers/gstvp9parser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiencoder_priv.h"
+#include "gstvaapiencoder_vp9.h"
+#include "gstvaapicodedbufferproxy_priv.h"
+#include "gstvaapisurface.h"
+#include "gstvaapiutils_vpx.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define MAX_TILE_WIDTH_B64 64
+
+/* Define default rate control mode ("constant-qp") */
+#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP
+
+/* Supported set of VA rate controls, within this implementation */
+#define SUPPORTED_RATECONTROLS                  \
+  (GST_VAAPI_RATECONTROL_MASK (CQP) |           \
+   GST_VAAPI_RATECONTROL_MASK (CBR) |           \
+   GST_VAAPI_RATECONTROL_MASK (VBR))
+
+/* Supported set of tuning options, within this implementation */
+#define SUPPORTED_TUNE_OPTIONS \
+  (GST_VAAPI_ENCODER_TUNE_MASK (NONE) |           \
+   GST_VAAPI_ENCODER_TUNE_MASK (LOW_POWER))
+
+/* Supported set of VA packed headers, within this implementation */
+#define SUPPORTED_PACKED_HEADERS                \
+  (VA_ENC_PACKED_HEADER_NONE)
+
+#define DEFAULT_LOOP_FILTER_LEVEL 10
+#define DEFAULT_SHARPNESS_LEVEL 0
+#define DEFAULT_YAC_QINDEX 60
+
+#define MAX_FRAME_WIDTH 4096
+#define MAX_FRAME_HEIGHT 4096
+
+/* Default CPB length (in milliseconds) */
+#define DEFAULT_CPB_LENGTH 1500
+
+typedef enum
+{
+  GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0 = 0,
+  GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1 = 1
+} GstVaapiEnoderVP9RefPicMode;
+
+static GType
+gst_vaapi_encoder_vp9_ref_pic_mode_type (void)
+{
+  static GType gtype = 0;
+
+  if (gtype == 0) {
+    static const GEnumValue values[] = {
+      {GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0,
+            "Use Keyframe(Alt & Gold) and Previousframe(Last) for prediction ",
+          "mode-0"},
+      {GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1,
+            "Use last three frames for prediction (n:Last n-1:Gold n-2:Alt)",
+          "mode-1"},
+      {0, NULL, NULL},
+    };
+
+    gtype = g_enum_register_static ("GstVaapiEncoderVP9RefPicMode", values);
+  }
+  return gtype;
+}
+
+
+/* ------------------------------------------------------------------------- */
+/* --- VP9 Encoder                                                      --- */
+/* ------------------------------------------------------------------------- */
+
+struct _GstVaapiEncoderVP9
+{
+  GstVaapiEncoder parent_instance;
+  GstVaapiProfile profile;
+  guint loop_filter_level;
+  guint sharpness_level;
+  guint yac_qi;
+  guint ref_pic_mode;
+  guint frame_num;
+  GstVaapiSurfaceProxy *ref_list[GST_VP9_REF_FRAMES];   /* reference list */
+  guint ref_list_idx;           /* next free slot in ref_list */
+  GstVaapiEntrypoint entrypoint;
+  GArray *allowed_profiles;
+
+  /* Bitrate contral parameters, CPB = Coded Picture Buffer */
+  guint bitrate_bits;           /* bitrate (bits) */
+  guint cpb_length;             /* length of CPB buffer (ms) */
+};
+
+/* Estimates a good enough bitrate if none was supplied */
+static void
+ensure_bitrate (GstVaapiEncoderVP9 * encoder)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  guint bitrate;
+
+  switch (GST_VAAPI_ENCODER_RATE_CONTROL (encoder)) {
+    case GST_VAAPI_RATECONTROL_CBR:
+    case GST_VAAPI_RATECONTROL_VBR:
+      if (!base_encoder->bitrate) {
+        /* FIXME: Provide better estimation */
+        /* Using a 1/6 compression ratio */
+        /* 12 bits per pixel fro yuv420 */
+        base_encoder->bitrate =
+            (GST_VAAPI_ENCODER_WIDTH (encoder) *
+            GST_VAAPI_ENCODER_HEIGHT (encoder) * 12 / 6) *
+            GST_VAAPI_ENCODER_FPS_N (encoder) /
+            GST_VAAPI_ENCODER_FPS_D (encoder) / 1000;
+        GST_INFO ("target bitrate computed to %u kbps", base_encoder->bitrate);
+      }
+
+      bitrate = (base_encoder->bitrate * 1000);
+      if (bitrate != encoder->bitrate_bits) {
+        GST_DEBUG ("HRD bitrate: %u bits/sec", bitrate);
+        encoder->bitrate_bits = bitrate;
+      }
+
+      break;
+    default:
+      base_encoder->bitrate = 0;
+      break;
+  }
+}
+
+static gboolean
+is_profile_allowed (GstVaapiEncoderVP9 * encoder, GstVaapiProfile profile)
+{
+  guint i;
+
+  if (encoder->allowed_profiles == NULL)
+    return TRUE;
+
+  for (i = 0; i < encoder->allowed_profiles->len; i++)
+    if (profile ==
+        g_array_index (encoder->allowed_profiles, GstVaapiProfile, i))
+      return TRUE;
+
+  return FALSE;
+}
+
+ /* Derives the profile that suits best to the configuration */
+static GstVaapiEncoderStatus
+ensure_profile (GstVaapiEncoderVP9 * encoder)
+{
+  const GstVideoFormat format =
+      GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder));
+  guint depth, chrome;
+
+  if (!GST_VIDEO_FORMAT_INFO_IS_YUV (gst_video_format_get_info (format)))
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+
+  depth = GST_VIDEO_FORMAT_INFO_DEPTH (gst_video_format_get_info (format), 0);
+  chrome = gst_vaapi_utils_vp9_get_chroma_format_idc
+      (gst_vaapi_video_format_get_chroma_type
+      (GST_VIDEO_INFO_FORMAT (GST_VAAPI_ENCODER_VIDEO_INFO (encoder))));
+
+  encoder->profile = GST_VAAPI_PROFILE_UNKNOWN;
+  /*
+     Profile Color | Depth Chroma | Subsampling
+     0             | 8 bit/sample | 4:2:0
+     1             | 8 bit        | 4:2:2, 4:4:4
+     2             | 10 or 12 bit | 4:2:0
+     3             | 10 or 12 bit | 4:2:2, 4:4:4     */
+  if (chrome == 3 || chrome == 2) {
+    /* 4:4:4 and 4:2:2 */
+    if (depth == 8) {
+      encoder->profile = GST_VAAPI_PROFILE_VP9_1;
+    } else if (depth == 10 || depth == 12) {
+      encoder->profile = GST_VAAPI_PROFILE_VP9_3;
+    }
+  } else if (chrome == 1) {
+    /* 4:2:0 */
+    if (depth == 8) {
+      encoder->profile = GST_VAAPI_PROFILE_VP9_0;
+    } else if (depth == 10 || depth == 12) {
+      encoder->profile = GST_VAAPI_PROFILE_VP9_2;
+    }
+  }
+
+  if (encoder->profile == GST_VAAPI_PROFILE_UNKNOWN) {
+    GST_WARNING ("Failed to decide VP9 profile");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  if (!is_profile_allowed (encoder, encoder->profile)) {
+    GST_WARNING ("Failed to find an allowed VP9 profile");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  /* Ensure bitrate if not set already */
+  ensure_bitrate (encoder);
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+set_context_info (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderVP9 *encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
+  GstVideoInfo *const vip = GST_VAAPI_ENCODER_VIDEO_INFO (encoder);
+  const guint DEFAULT_SURFACES_COUNT = 2;
+
+  /* FIXME: Maximum sizes for common headers (in bytes) */
+
+  GST_VAAPI_ENCODER_CAST (encoder)->profile = encoder->profile;
+
+  base_encoder->num_ref_frames = 3 + DEFAULT_SURFACES_COUNT;
+
+  /* Only YUV 4:2:0 formats are supported for now. */
+  base_encoder->codedbuf_size = GST_ROUND_UP_16 (vip->width) *
+      GST_ROUND_UP_16 (vip->height) * 3 / 2;
+
+  base_encoder->context_info.profile = base_encoder->profile;
+  base_encoder->context_info.entrypoint = encoder->entrypoint;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static gboolean
+fill_sequence (GstVaapiEncoderVP9 * encoder, GstVaapiEncSequence * sequence)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+  VAEncSequenceParameterBufferVP9 *const seq_param = sequence->param;
+
+  memset (seq_param, 0, sizeof (VAEncSequenceParameterBufferVP9));
+
+  seq_param->max_frame_width = MAX_FRAME_WIDTH;
+  seq_param->max_frame_height = MAX_FRAME_HEIGHT;
+
+  /* keyframe minimum interval */
+  seq_param->kf_min_dist = 1;
+  /* keyframe maximum interval */
+  seq_param->kf_max_dist = base_encoder->keyframe_period;
+  seq_param->intra_period = base_encoder->keyframe_period;
+  seq_param->bits_per_second = encoder->bitrate_bits;
+
+  return TRUE;
+}
+
+static gboolean
+ensure_sequence (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncSequence *sequence;
+
+  g_assert (picture);
+
+  if (picture->type != GST_VAAPI_PICTURE_TYPE_I)
+    return TRUE;
+
+  sequence = GST_VAAPI_ENC_SEQUENCE_NEW (VP9, encoder);
+  if (!sequence)
+    goto error;
+
+  if (!fill_sequence (encoder, sequence))
+    goto error;
+
+  gst_vaapi_enc_picture_set_sequence (picture, sequence);
+  gst_vaapi_codec_object_replace (&sequence, NULL);
+  return TRUE;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_codec_object_replace (&sequence, NULL);
+    return FALSE;
+  }
+}
+
+static gboolean
+ensure_control_rate_params (GstVaapiEncoderVP9 * encoder)
+{
+  if (GST_VAAPI_ENCODER_RATE_CONTROL (encoder) == GST_VAAPI_RATECONTROL_CQP)
+    return TRUE;
+
+  /* RateControl params */
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).bits_per_second =
+      encoder->bitrate_bits;
+  GST_VAAPI_ENCODER_VA_RATE_CONTROL (encoder).window_size = encoder->cpb_length;
+
+  /* *INDENT-OFF* */
+  /* HRD params */
+  GST_VAAPI_ENCODER_VA_HRD (encoder) = (VAEncMiscParameterHRD) {
+    .buffer_size = encoder->bitrate_bits * 2,
+    .initial_buffer_fullness = encoder->bitrate_bits,
+  };
+  /* *INDENT-ON* */
+
+  return TRUE;
+}
+
+static gboolean
+ensure_misc_params (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER_CAST (encoder);
+
+  if (!gst_vaapi_encoder_ensure_param_quality_level (base_encoder, picture))
+    return FALSE;
+  if (!gst_vaapi_encoder_ensure_param_control_rate (base_encoder, picture))
+    return FALSE;
+  return TRUE;
+}
+
+static void
+get_ref_indices (guint ref_pic_mode, guint ref_list_idx, guint * last_idx,
+    guint * gf_idx, guint * arf_idx, guint8 * refresh_frame_flags)
+{
+  if (ref_pic_mode == GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0) {
+    *last_idx = ref_list_idx - 1;
+    *gf_idx = 1;
+    *arf_idx = 2;
+    *refresh_frame_flags = 0x01;
+  } else if (ref_pic_mode == GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1) {
+    gint last_filled_idx = (ref_list_idx - 1) & (GST_VP9_REF_FRAMES - 1);
+
+    *last_idx = last_filled_idx;
+    *gf_idx = (last_filled_idx - 1) & (GST_VP9_REF_FRAMES - 1);
+    *arf_idx = (last_filled_idx - 2) & (GST_VP9_REF_FRAMES - 1);
+
+    *refresh_frame_flags = 1 << ((*last_idx + 1) % GST_VP9_REF_FRAMES);
+  }
+
+  GST_LOG
+      ("last_ref_idx:%d gold_ref_idx:%d alt_reff_idx:%d refesh_frame_flag:%x",
+      *last_idx, *gf_idx, *arf_idx, *refresh_frame_flags);
+}
+
+static gboolean
+fill_picture (GstVaapiEncoderVP9 * encoder,
+    GstVaapiEncPicture * picture,
+    GstVaapiCodedBuffer * codedbuf, GstVaapiSurfaceProxy * surface)
+{
+  VAEncPictureParameterBufferVP9 *const pic_param = picture->param;
+  guint i, last_idx = 0, gf_idx = 0, arf_idx = 0;
+  guint8 refresh_frame_flags = 0;
+  gint sb_cols = 0, min_log2_tile_columns = 0;
+
+  memset (pic_param, 0, sizeof (VAEncPictureParameterBufferVP9));
+
+  pic_param->reconstructed_frame = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (surface);
+  pic_param->coded_buf = GST_VAAPI_CODED_BUFFER_ID (codedbuf);
+
+  /* Update Reference Frame list */
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_I)
+    memset (pic_param->reference_frames, 0xFF,
+        sizeof (pic_param->reference_frames));
+  else {
+    for (i = 0; i < G_N_ELEMENTS (pic_param->reference_frames); i++) {
+      pic_param->reference_frames[i] =
+          GST_VAAPI_SURFACE_PROXY_SURFACE_ID (encoder->ref_list[i]);
+    }
+  }
+
+  /* It is possible to have dynamic scaling with gpu by providing
+   * src and destination resoltuion. For now we are just using
+   * default encoder width and height */
+  pic_param->frame_width_src = GST_VAAPI_ENCODER_WIDTH (encoder);
+  pic_param->frame_height_src = GST_VAAPI_ENCODER_HEIGHT (encoder);
+  pic_param->frame_width_dst = GST_VAAPI_ENCODER_WIDTH (encoder);
+  pic_param->frame_height_dst = GST_VAAPI_ENCODER_HEIGHT (encoder);
+
+  pic_param->pic_flags.bits.show_frame = 1;
+
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_P) {
+    pic_param->pic_flags.bits.frame_type = GST_VP9_INTER_FRAME;
+
+    /* use three of the reference frames (last, golden and altref)
+     * for prediction */
+    pic_param->ref_flags.bits.ref_frame_ctrl_l0 = 0x7;
+
+    get_ref_indices (encoder->ref_pic_mode, encoder->ref_list_idx, &last_idx,
+        &gf_idx, &arf_idx, &refresh_frame_flags);
+
+    pic_param->ref_flags.bits.ref_last_idx = last_idx;
+    pic_param->ref_flags.bits.ref_gf_idx = gf_idx;
+    pic_param->ref_flags.bits.ref_arf_idx = arf_idx;
+    pic_param->refresh_frame_flags = refresh_frame_flags;
+  }
+
+  /* Maximum width of a tile in units of superblocks is MAX_TILE_WIDTH_B64(64).
+   * When the width is enough to partition more than MAX_TILE_WIDTH_B64(64) superblocks,
+   * we need multi tiles to handle it.*/
+  sb_cols = (pic_param->frame_width_src + 63) / 64;
+  while ((MAX_TILE_WIDTH_B64 << min_log2_tile_columns) < sb_cols)
+    ++min_log2_tile_columns;
+  pic_param->log2_tile_columns = min_log2_tile_columns;
+
+  pic_param->luma_ac_qindex = encoder->yac_qi;
+  pic_param->luma_dc_qindex_delta = 1;
+  pic_param->chroma_ac_qindex_delta = 1;
+  pic_param->chroma_dc_qindex_delta = 1;
+  pic_param->filter_level = encoder->loop_filter_level;
+  pic_param->sharpness_level = encoder->sharpness_level;
+
+  return TRUE;
+}
+
+static gboolean
+ensure_picture (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiCodedBufferProxy * codedbuf_proxy, GstVaapiSurfaceProxy * surface)
+{
+  GstVaapiCodedBuffer *const codedbuf =
+      GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy);
+
+  if (!fill_picture (encoder, picture, codedbuf, surface))
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+update_ref_list (GstVaapiEncoderVP9 * encoder, GstVaapiEncPicture * picture,
+    GstVaapiSurfaceProxy * ref)
+{
+  guint i;
+
+  if (picture->type == GST_VAAPI_PICTURE_TYPE_I) {
+    for (i = 0; i < G_N_ELEMENTS (encoder->ref_list); i++)
+      gst_vaapi_surface_proxy_replace (&encoder->ref_list[i], ref);
+    gst_vaapi_surface_proxy_unref (ref);
+    /* set next free slot index */
+    encoder->ref_list_idx = 1;
+    return;
+  }
+
+  switch (encoder->ref_pic_mode) {
+    case GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0:
+      gst_vaapi_surface_proxy_replace (&encoder->ref_list[0], ref);
+      gst_vaapi_surface_proxy_unref (ref);
+      break;
+    case GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_1:
+      i = encoder->ref_list_idx;
+      gst_vaapi_surface_proxy_replace (&encoder->ref_list[i], ref);
+      gst_vaapi_surface_proxy_unref (ref);
+      encoder->ref_list_idx = (encoder->ref_list_idx + 1) % GST_VP9_REF_FRAMES;
+      break;
+    default:
+      g_assert ("Code shouldn't reach here");
+      break;
+  }
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_vp9_encode (GstVaapiEncoder * base_encoder,
+    GstVaapiEncPicture * picture, GstVaapiCodedBufferProxy * codedbuf)
+{
+  GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
+  GstVaapiEncoderStatus ret = GST_VAAPI_ENCODER_STATUS_ERROR_UNKNOWN;
+  GstVaapiSurfaceProxy *reconstruct = NULL;
+
+  reconstruct = gst_vaapi_encoder_create_surface (base_encoder);
+
+  g_assert (GST_VAAPI_SURFACE_PROXY_SURFACE (reconstruct));
+
+  if (!ensure_sequence (encoder, picture))
+    goto error;
+  if (!ensure_misc_params (encoder, picture))
+    goto error;
+  if (!ensure_picture (encoder, picture, codedbuf, reconstruct))
+    goto error;
+  if (!gst_vaapi_enc_picture_encode (picture))
+    goto error;
+
+  update_ref_list (encoder, picture, reconstruct);
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    if (reconstruct)
+      gst_vaapi_encoder_release_surface (GST_VAAPI_ENCODER (encoder),
+          reconstruct);
+    return ret;
+  }
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_vp9_flush (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
+
+  encoder->frame_num = 0;
+
+  return GST_VAAPI_ENCODER_STATUS_SUCCESS;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_vp9_reordering (GstVaapiEncoder * base_encoder,
+    GstVideoCodecFrame * frame, GstVaapiEncPicture ** output)
+{
+  GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
+  GstVaapiEncPicture *picture = NULL;
+  GstVaapiEncoderStatus status = GST_VAAPI_ENCODER_STATUS_SUCCESS;
+
+  if (!frame)
+    return GST_VAAPI_ENCODER_STATUS_NO_SURFACE;
+
+  picture = GST_VAAPI_ENC_PICTURE_NEW (VP9, encoder, frame);
+  if (!picture) {
+    GST_WARNING ("create VP9 picture failed, frame timestamp:%"
+        GST_TIME_FORMAT, GST_TIME_ARGS (frame->pts));
+    return GST_VAAPI_ENCODER_STATUS_ERROR_ALLOCATION_FAILED;
+  }
+
+  if (encoder->frame_num >= base_encoder->keyframe_period) {
+    encoder->frame_num = 0;
+  }
+  if (encoder->frame_num == 0) {
+    picture->type = GST_VAAPI_PICTURE_TYPE_I;
+    GST_VIDEO_CODEC_FRAME_SET_SYNC_POINT (frame);
+  } else {
+    picture->type = GST_VAAPI_PICTURE_TYPE_P;
+  }
+
+  encoder->frame_num++;
+  *output = picture;
+  return status;
+}
+
+static GstVaapiEncoderStatus
+gst_vaapi_encoder_vp9_reconfigure (GstVaapiEncoder * base_encoder)
+{
+  GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (base_encoder);
+  GstVaapiEncoderStatus status;
+
+  status = ensure_profile (encoder);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return status;
+
+  encoder->entrypoint =
+      gst_vaapi_encoder_get_entrypoint (base_encoder, encoder->profile);
+  if (encoder->entrypoint == GST_VAAPI_ENTRYPOINT_INVALID) {
+    GST_WARNING ("Cannot find valid profile/entrypoint pair");
+    return GST_VAAPI_ENCODER_STATUS_ERROR_UNSUPPORTED_PROFILE;
+  }
+
+  ensure_control_rate_params (encoder);
+  return set_context_info (base_encoder);
+}
+
+
+struct _GstVaapiEncoderVP9Class
+{
+  GstVaapiEncoderClass parent_class;
+};
+
+G_DEFINE_TYPE (GstVaapiEncoderVP9, gst_vaapi_encoder_vp9,
+    GST_TYPE_VAAPI_ENCODER);
+
+static void
+gst_vaapi_encoder_vp9_init (GstVaapiEncoderVP9 * encoder)
+{
+  encoder->frame_num = 0;
+  encoder->loop_filter_level = DEFAULT_LOOP_FILTER_LEVEL;
+  encoder->sharpness_level = DEFAULT_SHARPNESS_LEVEL;
+  encoder->yac_qi = DEFAULT_YAC_QINDEX;
+  encoder->cpb_length = DEFAULT_CPB_LENGTH;
+  encoder->entrypoint = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
+
+  memset (encoder->ref_list, 0,
+      G_N_ELEMENTS (encoder->ref_list) * sizeof (encoder->ref_list[0]));
+  encoder->ref_list_idx = 0;
+
+  encoder->allowed_profiles = NULL;
+}
+
+static void
+gst_vaapi_encoder_vp9_finalize (GObject * object)
+{
+  GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (object);
+
+  if (encoder->allowed_profiles)
+    g_array_unref (encoder->allowed_profiles);
+
+  G_OBJECT_CLASS (gst_vaapi_encoder_vp9_parent_class)->finalize (object);
+}
+
+/**
+ * @ENCODER_VP9_PROP_RATECONTROL: Rate control (#GstVaapiRateControl).
+ * @ENCODER_VP9_PROP_TUNE: The tuning options (#GstVaapiEncoderTune).
+ * @ENCODER_VP9_PROP_LOOP_FILTER_LEVEL: Loop Filter Level(uint).
+ * @ENCODER_VP9_PROP_LOOP_SHARPNESS_LEVEL: Sharpness Level(uint).
+ * @ENCODER_VP9_PROP_YAC_Q_INDEX: Quantization table index for luma AC
+ * @ENCODER_VP9_PROP_REF_PIC_MODE: Reference picute selection modes
+ * @ENCODER_VP9_PROP_CPB_LENGTH:Length of CPB buffer in milliseconds
+ *
+ * The set of VP9 encoder specific configurable properties.
+ */
+enum
+{
+  ENCODER_VP9_PROP_RATECONTROL = 1,
+  ENCODER_VP9_PROP_TUNE,
+  ENCODER_VP9_PROP_LOOP_FILTER_LEVEL,
+  ENCODER_VP9_PROP_SHARPNESS_LEVEL,
+  ENCODER_VP9_PROP_YAC_Q_INDEX,
+  ENCODER_VP9_PROP_REF_PIC_MODE,
+  ENCODER_VP9_PROP_CPB_LENGTH,
+  ENCODER_VP9_N_PROPERTIES
+};
+
+static GParamSpec *properties[ENCODER_VP9_N_PROPERTIES];
+
+static void
+gst_vaapi_encoder_vp9_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+  GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (object);
+
+  if (base_encoder->num_codedbuf_queued > 0) {
+    GST_ERROR_OBJECT (object,
+        "failed to set any property after encoding started");
+    return;
+  }
+
+  switch (prop_id) {
+    case ENCODER_VP9_PROP_RATECONTROL:
+      gst_vaapi_encoder_set_rate_control (base_encoder,
+          g_value_get_enum (value));
+      break;
+    case ENCODER_VP9_PROP_TUNE:
+      gst_vaapi_encoder_set_tuning (base_encoder, g_value_get_enum (value));
+      break;
+    case ENCODER_VP9_PROP_LOOP_FILTER_LEVEL:
+      encoder->loop_filter_level = g_value_get_uint (value);
+      break;
+    case ENCODER_VP9_PROP_SHARPNESS_LEVEL:
+      encoder->sharpness_level = g_value_get_uint (value);
+      break;
+    case ENCODER_VP9_PROP_YAC_Q_INDEX:
+      encoder->yac_qi = g_value_get_uint (value);
+      break;
+    case ENCODER_VP9_PROP_REF_PIC_MODE:
+      encoder->ref_pic_mode = g_value_get_enum (value);
+      break;
+    case ENCODER_VP9_PROP_CPB_LENGTH:
+      encoder->cpb_length = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_encoder_vp9_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncoderVP9 *const encoder = GST_VAAPI_ENCODER_VP9 (object);
+  GstVaapiEncoder *const base_encoder = GST_VAAPI_ENCODER (object);
+
+  switch (prop_id) {
+    case ENCODER_VP9_PROP_RATECONTROL:
+      g_value_set_enum (value, base_encoder->rate_control);
+      break;
+    case ENCODER_VP9_PROP_TUNE:
+      g_value_set_enum (value, base_encoder->tune);
+      break;
+    case ENCODER_VP9_PROP_LOOP_FILTER_LEVEL:
+      g_value_set_uint (value, encoder->loop_filter_level);
+      break;
+    case ENCODER_VP9_PROP_SHARPNESS_LEVEL:
+      g_value_set_uint (value, encoder->sharpness_level);
+      break;
+    case ENCODER_VP9_PROP_YAC_Q_INDEX:
+      g_value_set_uint (value, encoder->yac_qi);
+      break;
+    case ENCODER_VP9_PROP_REF_PIC_MODE:
+      g_value_set_enum (value, encoder->ref_pic_mode);
+      break;
+    case ENCODER_VP9_PROP_CPB_LENGTH:
+      g_value_set_uint (value, encoder->cpb_length);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+  }
+}
+
+GST_VAAPI_ENCODER_DEFINE_CLASS_DATA (VP9);
+
+static void
+gst_vaapi_encoder_vp9_class_init (GstVaapiEncoderVP9Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiEncoderClass *const encoder_class = GST_VAAPI_ENCODER_CLASS (klass);
+
+  encoder_class->class_data = &g_class_data;
+  encoder_class->reconfigure = gst_vaapi_encoder_vp9_reconfigure;
+  encoder_class->reordering = gst_vaapi_encoder_vp9_reordering;
+  encoder_class->encode = gst_vaapi_encoder_vp9_encode;
+  encoder_class->flush = gst_vaapi_encoder_vp9_flush;
+
+  object_class->set_property = gst_vaapi_encoder_vp9_set_property;
+  object_class->get_property = gst_vaapi_encoder_vp9_get_property;
+  object_class->finalize = gst_vaapi_encoder_vp9_finalize;
+
+  properties[ENCODER_VP9_PROP_RATECONTROL] =
+      g_param_spec_enum ("rate-control",
+      "Rate Control", "Rate control mode",
+      g_class_data.rate_control_get_type (),
+      g_class_data.default_rate_control,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_VP9_PROP_TUNE] =
+      g_param_spec_enum ("tune",
+      "Encoder Tuning",
+      "Encoder tuning option",
+      g_class_data.encoder_tune_get_type (),
+      g_class_data.default_encoder_tune,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_VP9_PROP_LOOP_FILTER_LEVEL] =
+      g_param_spec_uint ("loop-filter-level",
+      "Loop Filter Level",
+      "Controls the deblocking filter strength",
+      0, 63, DEFAULT_LOOP_FILTER_LEVEL,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_VP9_PROP_SHARPNESS_LEVEL] =
+      g_param_spec_uint ("sharpness-level",
+      "Sharpness Level",
+      "Controls the deblocking filter sensitivity",
+      0, 7, DEFAULT_SHARPNESS_LEVEL,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_VP9_PROP_YAC_Q_INDEX] =
+      g_param_spec_uint ("yac-qi",
+      "Luma AC Quant Table index",
+      "Quantization Table index for Luma AC Coefficients",
+      0, 255, DEFAULT_YAC_QINDEX,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  properties[ENCODER_VP9_PROP_REF_PIC_MODE] =
+      g_param_spec_enum ("ref-pic-mode",
+      "RefPic Selection",
+      "Reference Picture Selection Modes",
+      gst_vaapi_encoder_vp9_ref_pic_mode_type (),
+      GST_VAAPI_ENCODER_VP9_REF_PIC_MODE_0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  /**
+   * GstVaapiEncoderVP9:cpb-length:
+   *
+   * The size of the Coded Picture Buffer , which means
+   * the window size in milliseconds.
+   *
+   */
+  properties[ENCODER_VP9_PROP_CPB_LENGTH] =
+      g_param_spec_uint ("cpb-length",
+      "CPB Length", "Length of the CPB_buffer/window_size in milliseconds",
+      1, 10000, DEFAULT_CPB_LENGTH,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT |
+      GST_VAAPI_PARAM_ENCODER_EXPOSURE);
+
+  g_object_class_install_properties (object_class, ENCODER_VP9_N_PROPERTIES,
+      properties);
+
+  gst_type_mark_as_plugin_api (g_class_data.rate_control_get_type (), 0);
+  gst_type_mark_as_plugin_api (g_class_data.encoder_tune_get_type (), 0);
+}
+
+/**
+ * gst_vaapi_encoder_vp9_new:
+ * @display: a #GstVaapiDisplay
+ *
+ * Creates a new #GstVaapiEncoder for VP9 encoding.
+ *
+ * Return value: the newly allocated #GstVaapiEncoder object
+ */
+GstVaapiEncoder *
+gst_vaapi_encoder_vp9_new (GstVaapiDisplay * display)
+{
+  return g_object_new (GST_TYPE_VAAPI_ENCODER_VP9, "display", display, NULL);
+}
+
+/**
+ * gst_vaapi_encoder_vp9_set_allowed_profiles:
+ * @encoder: a #GstVaapiEncoderVP9
+ * @profiles: a #GArray of all allowed #GstVaapiProfile.
+ *
+ * Set the all allowed profiles for the encoder.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_encoder_vp9_set_allowed_profiles (GstVaapiEncoderVP9 * encoder,
+    GArray * profiles)
+{
+  g_return_val_if_fail (profiles != 0, FALSE);
+
+  encoder->allowed_profiles = g_array_ref (profiles);
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiencoder_vp9.h
new file mode 100644 (file)
index 0000000..6459c01
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *  gstvaapiencoder_vp9.h VP9 encoder
+ *
+ *  Copyright (C) 2016 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_ENCODER_VP9_H
+#define GST_VAAPI_ENCODER_VP9_H
+
+#include <gst/vaapi/gstvaapiencoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_ENCODER_VP9 \
+    (gst_vaapi_encoder_vp9_get_type ())
+#define GST_VAAPI_ENCODER_VP9(encoder) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((encoder), GST_TYPE_VAAPI_ENCODER_VP9, GstVaapiEncoderVP9))
+#define GST_IS_VAAPI_ENCODER_VP9(encoder) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((encoder), GST_TYPE_VAAPI_ENCODER_VP9))
+
+typedef struct _GstVaapiEncoderVP9 GstVaapiEncoderVP9;
+typedef struct _GstVaapiEncoderVP9Class GstVaapiEncoderVP9Class;
+
+GType
+gst_vaapi_encoder_vp9_get_type (void) G_GNUC_CONST;
+
+GstVaapiEncoder *
+gst_vaapi_encoder_vp9_new (GstVaapiDisplay * display);
+
+gboolean
+gst_vaapi_encoder_vp9_set_allowed_profiles (GstVaapiEncoderVP9 * encoder,
+    GArray * profiles);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiEncoderVP9, gst_object_unref)
+
+G_END_DECLS
+#endif /*GST_VAAPI_ENCODER_VP9_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapifilter.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapifilter.c
new file mode 100644 (file)
index 0000000..447c6de
--- /dev/null
@@ -0,0 +1,2554 @@
+/*
+ *  gstvaapifilter.c - Video processing abstraction
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "config.h"
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapifilter.h"
+#include "gstvaapiutils.h"
+#include "gstvaapivalue.h"
+#include "gstvaapiminiobject.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapisurface_priv.h"
+#include "gstvaapiutils_core.h"
+
+#define GST_VAAPI_FILTER_CAST(obj) \
+    ((GstVaapiFilter *)(obj))
+
+typedef struct _GstVaapiFilterOpData GstVaapiFilterOpData;
+struct _GstVaapiFilterOpData
+{
+  GstVaapiFilterOp op;
+  GParamSpec *pspec;
+  gint ref_count;
+  guint va_type;
+  guint va_subtype;
+  gpointer va_caps;
+  guint va_num_caps;
+  guint va_cap_size;
+  VABufferID va_buffer;
+  guint va_buffer_size;
+  guint is_enabled:1;
+};
+
+struct _GstVaapiFilter
+{
+  /*< private > */
+  GstObject parent_instance;
+
+  GstVaapiDisplay *display;
+  VADisplay va_display;
+  VAConfigID va_config;
+  VAContextID va_context;
+  GPtrArray *operations;
+  GstVideoFormat format;
+  GstVaapiScaleMethod scale_method;
+  GstVideoOrientationMethod video_direction;
+  GstVaapiConfigSurfaceAttributes *attribs;
+  GArray *forward_references;
+  GArray *backward_references;
+  GstVaapiRectangle crop_rect;
+  GstVaapiRectangle target_rect;
+  guint use_crop_rect:1;
+  guint use_target_rect:1;
+  guint32 mirror_flags;
+  guint32 rotation_flags;
+
+  GstVideoColorimetry input_colorimetry;
+  GstVideoColorimetry output_colorimetry;
+
+#if VA_CHECK_VERSION(1,4,0)
+  VAHdrMetaDataHDR10 hdr_meta;
+#endif
+};
+
+typedef struct _GstVaapiFilterClass GstVaapiFilterClass;
+struct _GstVaapiFilterClass
+{
+  /*< private > */
+  GstObjectClass parent_class;
+};
+
+/* Debug category for VaapiFilter */
+GST_DEBUG_CATEGORY (gst_debug_vaapi_filter);
+#define GST_CAT_DEFAULT gst_debug_vaapi_filter
+
+#define _do_init                                                       \
+    GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_filter, "vaapifilter", 0, \
+    "VA-API Filter");
+
+G_DEFINE_TYPE_WITH_CODE (GstVaapiFilter, gst_vaapi_filter, GST_TYPE_OBJECT,
+    _do_init);
+
+/* ------------------------------------------------------------------------- */
+/* --- VPP Types                                                         --- */
+/* ------------------------------------------------------------------------- */
+
+static GType
+gst_vaapi_scale_method_get_type (void)
+{
+  static gsize g_type = 0;
+
+  static const GEnumValue enum_values[] = {
+    {GST_VAAPI_SCALE_METHOD_DEFAULT,
+        "Default scaling mode", "default"},
+    {GST_VAAPI_SCALE_METHOD_FAST,
+        "Fast scaling mode", "fast"},
+    {GST_VAAPI_SCALE_METHOD_HQ,
+        "High quality scaling mode", "hq"},
+    {0, NULL, NULL},
+  };
+
+  if (g_once_init_enter (&g_type)) {
+    const GType type =
+        g_enum_register_static ("GstVaapiScaleMethod", enum_values);
+    g_once_init_leave (&g_type, type);
+
+    gst_type_mark_as_plugin_api (type, 0);
+  }
+  return g_type;
+}
+
+GType
+gst_vaapi_deinterlace_method_get_type (void)
+{
+  static gsize g_type = 0;
+
+  static const GEnumValue enum_values[] = {
+    {GST_VAAPI_DEINTERLACE_METHOD_NONE,
+        "Disable deinterlacing", "none"},
+    {GST_VAAPI_DEINTERLACE_METHOD_BOB,
+        "Bob deinterlacing", "bob"},
+    {GST_VAAPI_DEINTERLACE_METHOD_WEAVE,
+        "Weave deinterlacing", "weave"},
+    {GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE,
+        "Motion adaptive deinterlacing", "motion-adaptive"},
+    {GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED,
+        "Motion compensated deinterlacing", "motion-compensated"},
+    {0, NULL, NULL},
+  };
+
+  if (g_once_init_enter (&g_type)) {
+    const GType type =
+        g_enum_register_static ("GstVaapiDeinterlaceMethod", enum_values);
+    gst_type_mark_as_plugin_api (type, 0);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+GType
+gst_vaapi_deinterlace_flags_get_type (void)
+{
+  static gsize g_type = 0;
+
+  static const GEnumValue enum_values[] = {
+    {GST_VAAPI_DEINTERLACE_FLAG_TFF,
+        "Top-field first", "top-field-first"},
+    {GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD,
+        "One field", "one-field"},
+    {GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD,
+        "Top field", "top-field"},
+    {0, NULL, NULL}
+  };
+
+  if (g_once_init_enter (&g_type)) {
+    const GType type =
+        g_enum_register_static ("GstVaapiDeinterlaceFlags", enum_values);
+    gst_type_mark_as_plugin_api (type, 0);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- VPP Helpers                                                       --- */
+/* ------------------------------------------------------------------------- */
+
+static VAProcFilterType *
+vpp_get_filters_unlocked (GstVaapiFilter * filter, guint * num_filters_ptr)
+{
+  VAProcFilterType *filters = NULL;
+  guint num_filters = 0;
+  VAStatus va_status;
+
+  num_filters = VAProcFilterCount;
+  filters = g_malloc_n (num_filters, sizeof (*filters));
+  if (!filters)
+    goto error;
+
+  va_status = vaQueryVideoProcFilters (filter->va_display, filter->va_context,
+      filters, &num_filters);
+
+  // Try to reallocate to the expected number of filters
+  if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
+    VAProcFilterType *const new_filters =
+        g_try_realloc_n (filters, num_filters, sizeof (*new_filters));
+    if (!new_filters)
+      goto error;
+    filters = new_filters;
+
+    va_status = vaQueryVideoProcFilters (filter->va_display,
+        filter->va_context, filters, &num_filters);
+  }
+  if (!vaapi_check_status (va_status, "vaQueryVideoProcFilters()"))
+    goto error;
+
+  *num_filters_ptr = num_filters;
+  return filters;
+
+  /* ERRORS */
+error:
+  {
+    g_free (filters);
+    return NULL;
+  }
+}
+
+static VAProcFilterType *
+vpp_get_filters (GstVaapiFilter * filter, guint * num_filters_ptr)
+{
+  VAProcFilterType *filters;
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  filters = vpp_get_filters_unlocked (filter, num_filters_ptr);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+  return filters;
+}
+
+static gpointer
+vpp_get_filter_caps_unlocked (GstVaapiFilter * filter, VAProcFilterType type,
+    guint cap_size, guint * num_caps_ptr)
+{
+  gpointer caps;
+  guint num_caps = 1;
+  VAStatus va_status;
+
+  caps = g_malloc (cap_size);
+  if (!caps)
+    goto error;
+
+  va_status = vaQueryVideoProcFilterCaps (filter->va_display,
+      filter->va_context, type, caps, &num_caps);
+
+  // Try to reallocate to the expected number of filters
+  if (va_status == VA_STATUS_ERROR_MAX_NUM_EXCEEDED) {
+    gpointer const new_caps = g_try_realloc_n (caps, num_caps, cap_size);
+    if (!new_caps)
+      goto error;
+    caps = new_caps;
+
+    va_status = vaQueryVideoProcFilterCaps (filter->va_display,
+        filter->va_context, type, caps, &num_caps);
+  }
+  if (!vaapi_check_status (va_status, "vaQueryVideoProcFilterCaps()"))
+    goto error;
+
+  *num_caps_ptr = num_caps;
+  return caps;
+
+  /* ERRORS */
+error:
+  {
+    g_free (caps);
+    return NULL;
+  }
+}
+
+static gpointer
+vpp_get_filter_caps (GstVaapiFilter * filter, VAProcFilterType type,
+    guint cap_size, guint * num_caps_ptr)
+{
+  gpointer caps;
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  caps = vpp_get_filter_caps_unlocked (filter, type, cap_size, num_caps_ptr);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+  return caps;
+}
+
+static void
+vpp_get_pipeline_caps_unlocked (GstVaapiFilter * filter)
+{
+#if VA_CHECK_VERSION(1,1,0)
+  VAProcPipelineCaps pipeline_caps = { 0, };
+
+  VAStatus va_status = vaQueryVideoProcPipelineCaps (filter->va_display,
+      filter->va_context, NULL, 0, &pipeline_caps);
+
+  if (vaapi_check_status (va_status, "vaQueryVideoProcPipelineCaps()")) {
+    filter->mirror_flags = pipeline_caps.mirror_flags;
+    filter->rotation_flags = pipeline_caps.rotation_flags;
+    return;
+  }
+#endif
+
+  filter->mirror_flags = 0;
+  filter->rotation_flags = 0;
+}
+
+static void
+vpp_get_pipeline_caps (GstVaapiFilter * filter)
+{
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  vpp_get_pipeline_caps_unlocked (filter);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- VPP Operations                                                   --- */
+/* ------------------------------------------------------------------------- */
+
+#define DEFAULT_FORMAT  GST_VIDEO_FORMAT_UNKNOWN
+
+#define OP_DATA_DEFAULT_VALUE(type, op_data) \
+    g_value_get_##type (g_param_spec_get_default_value (op_data->pspec))
+
+#define OP_RET_DEFAULT_VALUE(type, filter, op) \
+    do { \
+      g_return_val_if_fail (filter != NULL, FALSE); \
+      return OP_DATA_DEFAULT_VALUE (type, find_operation (filter, op)); \
+    } while (0)
+
+enum
+{
+  PROP_DISPLAY = 1,
+};
+
+enum
+{
+  PROP_0,
+
+  PROP_FORMAT = GST_VAAPI_FILTER_OP_FORMAT,
+  PROP_CROP = GST_VAAPI_FILTER_OP_CROP,
+  PROP_DENOISE = GST_VAAPI_FILTER_OP_DENOISE,
+  PROP_SHARPEN = GST_VAAPI_FILTER_OP_SHARPEN,
+  PROP_HUE = GST_VAAPI_FILTER_OP_HUE,
+  PROP_SATURATION = GST_VAAPI_FILTER_OP_SATURATION,
+  PROP_BRIGHTNESS = GST_VAAPI_FILTER_OP_BRIGHTNESS,
+  PROP_CONTRAST = GST_VAAPI_FILTER_OP_CONTRAST,
+  PROP_DEINTERLACING = GST_VAAPI_FILTER_OP_DEINTERLACING,
+  PROP_SCALING = GST_VAAPI_FILTER_OP_SCALING,
+  PROP_VIDEO_DIRECTION = GST_VAAPI_FILTER_OP_VIDEO_DIRECTION,
+  PROP_HDR_TONE_MAP = GST_VAAPI_FILTER_OP_HDR_TONE_MAP,
+#ifndef GST_REMOVE_DEPRECATED
+  PROP_SKINTONE = GST_VAAPI_FILTER_OP_SKINTONE,
+#endif
+  PROP_SKINTONE_LEVEL = GST_VAAPI_FILTER_OP_SKINTONE_LEVEL,
+
+  N_PROPERTIES
+};
+
+static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
+
+static gsize g_properties_initialized = FALSE;
+
+static void
+init_properties (void)
+{
+  /**
+   * GstVaapiFilter:format:
+   *
+   * The forced output pixel format, expressed as a #GstVideoFormat.
+   */
+  g_properties[PROP_FORMAT] = g_param_spec_enum ("format",
+      "Format",
+      "The forced output pixel format",
+      GST_TYPE_VIDEO_FORMAT,
+      DEFAULT_FORMAT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:crop-rect:
+   *
+   * The cropping rectangle, expressed as a #GstVaapiRectangle.
+   */
+  g_properties[PROP_CROP] = g_param_spec_boxed ("crop-rect",
+      "Cropping Rectangle",
+      "The cropping rectangle",
+      GST_VAAPI_TYPE_RECTANGLE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:denoise:
+   *
+   * The level of noise reduction to apply.
+   */
+  g_properties[PROP_DENOISE] = g_param_spec_float ("denoise",
+      "Denoising Level",
+      "The level of denoising to apply",
+      0.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:sharpen:
+   *
+   * The level of sharpening to apply for positive values, or the
+   * level of blurring for negative values.
+   */
+  g_properties[PROP_SHARPEN] = g_param_spec_float ("sharpen",
+      "Sharpening Level",
+      "The level of sharpening/blurring to apply",
+      -1.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:hue:
+   *
+   * The color hue, expressed as a float value. Range is -180.0 to
+   * 180.0. Default value is 0.0 and represents no modification.
+   */
+  g_properties[PROP_HUE] = g_param_spec_float ("hue",
+      "Hue",
+      "The color hue value",
+      -180.0, 180.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:saturation:
+   *
+   * The color saturation, expressed as a float value. Range is 0.0 to
+   * 2.0. Default value is 1.0 and represents no modification.
+   */
+  g_properties[PROP_SATURATION] = g_param_spec_float ("saturation",
+      "Saturation",
+      "The color saturation value",
+      0.0, 2.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:brightness:
+   *
+   * The color brightness, expressed as a float value. Range is -1.0
+   * to 1.0. Default value is 0.0 and represents no modification.
+   */
+  g_properties[PROP_BRIGHTNESS] = g_param_spec_float ("brightness",
+      "Brightness",
+      "The color brightness value",
+      -1.0, 1.0, 0.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:contrast:
+   *
+   * The color contrast, expressed as a float value. Range is 0.0 to
+   * 2.0. Default value is 1.0 and represents no modification.
+   */
+  g_properties[PROP_CONTRAST] = g_param_spec_float ("contrast",
+      "Contrast",
+      "The color contrast value",
+      0.0, 2.0, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:deinterlace-method:
+   *
+   * The deinterlacing algorithm to apply, expressed a an enum
+   * value. See #GstVaapiDeinterlaceMethod.
+   */
+  g_properties[PROP_DEINTERLACING] = g_param_spec_enum ("deinterlace",
+      "Deinterlacing Method",
+      "Deinterlacing method to apply",
+      GST_VAAPI_TYPE_DEINTERLACE_METHOD,
+      GST_VAAPI_DEINTERLACE_METHOD_NONE,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:scale-method:
+   *
+   * The scaling method to use, expressed as an enum value. See
+   * #GstVaapiScaleMethod.
+   */
+  g_properties[PROP_SCALING] = g_param_spec_enum ("scale-method",
+      "Scaling Method",
+      "Scaling method to use",
+      GST_VAAPI_TYPE_SCALE_METHOD,
+      GST_VAAPI_SCALE_METHOD_DEFAULT,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:video-direction:
+   *
+   * The video-direction to use, expressed as an enum value. See
+   * #GstVideoOrientationMethod.
+   */
+  g_properties[PROP_VIDEO_DIRECTION] = g_param_spec_enum ("video-direction",
+      "Video Direction",
+      "Video direction: rotation and flipping",
+      GST_TYPE_VIDEO_ORIENTATION_METHOD,
+      GST_VIDEO_ORIENTATION_IDENTITY,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiFilter:tone-map:
+   *
+   * Apply HDR tone mapping
+   **/
+  g_properties[PROP_HDR_TONE_MAP] = g_param_spec_boolean ("hdr-tone-map",
+      "HDR Tone Mapping",
+      "Apply HDR tone mapping",
+      FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+#ifndef GST_REMOVE_DEPRECATED
+  /**
+   * GstVaapiFilter:skin-tone-enhancement:
+   *
+   * Apply the skin tone enhancement algorithm.
+   */
+  g_properties[PROP_SKINTONE] = g_param_spec_boolean ("skin-tone-enhancement",
+      "Skin tone enhancement",
+      "Apply the skin tone enhancement algorithm",
+      FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+#endif
+
+  /**
+   * GstVaapiFilter:skin-tone-enhancement-level:
+   *
+   * Apply the skin tone enhancement algorithm with specified value.
+   */
+  g_properties[PROP_SKINTONE_LEVEL] =
+      g_param_spec_uint ("skin-tone-enhancement-level",
+      "Skin tone enhancement level",
+      "Apply the skin tone enhancement algorithm with specified level", 0, 9, 3,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+}
+
+static void
+ensure_properties (void)
+{
+  if (g_once_init_enter (&g_properties_initialized)) {
+    init_properties ();
+    g_once_init_leave (&g_properties_initialized, TRUE);
+  }
+}
+
+static void
+op_data_free (GstVaapiFilterOpData * op_data)
+{
+  g_free (op_data->va_caps);
+  g_slice_free (GstVaapiFilterOpData, op_data);
+}
+
+static inline gpointer
+op_data_new (GstVaapiFilterOp op, GParamSpec * pspec)
+{
+  GstVaapiFilterOpData *op_data;
+
+  op_data = g_slice_new0 (GstVaapiFilterOpData);
+  if (!op_data)
+    return NULL;
+
+  op_data->op = op;
+  op_data->pspec = pspec;
+  g_atomic_int_set (&op_data->ref_count, 1);
+  op_data->va_buffer = VA_INVALID_ID;
+
+  switch (op) {
+    case GST_VAAPI_FILTER_OP_HDR_TONE_MAP:
+#if VA_CHECK_VERSION(1,4,0)
+      /* Only HDR10 tone mapping is supported */
+      op_data->va_type = VAProcFilterHighDynamicRangeToneMapping;
+      op_data->va_subtype = VAProcHighDynamicRangeMetadataHDR10;
+      op_data->va_cap_size = sizeof (VAProcFilterCapHighDynamicRange);
+      op_data->va_buffer_size =
+          sizeof (VAProcFilterParameterBufferHDRToneMapping);
+      break;
+#else
+      /* fall-through */
+#endif
+    case GST_VAAPI_FILTER_OP_FORMAT:
+    case GST_VAAPI_FILTER_OP_CROP:
+    case GST_VAAPI_FILTER_OP_SCALING:
+    case GST_VAAPI_FILTER_OP_VIDEO_DIRECTION:
+      op_data->va_type = VAProcFilterNone;
+      break;
+    case GST_VAAPI_FILTER_OP_DENOISE:
+      op_data->va_type = VAProcFilterNoiseReduction;
+      op_data->va_cap_size = sizeof (VAProcFilterCap);
+      op_data->va_buffer_size = sizeof (VAProcFilterParameterBuffer);
+      break;
+    case GST_VAAPI_FILTER_OP_SHARPEN:
+      op_data->va_type = VAProcFilterSharpening;
+      op_data->va_cap_size = sizeof (VAProcFilterCap);
+      op_data->va_buffer_size = sizeof (VAProcFilterParameterBuffer);
+      break;
+#ifndef GST_REMOVE_DEPRECATED
+    case GST_VAAPI_FILTER_OP_SKINTONE:
+#endif
+    case GST_VAAPI_FILTER_OP_SKINTONE_LEVEL:
+      op_data->va_type = VAProcFilterSkinToneEnhancement;
+      op_data->va_buffer_size = sizeof (VAProcFilterParameterBuffer);
+      break;
+    case GST_VAAPI_FILTER_OP_HUE:
+      op_data->va_subtype = VAProcColorBalanceHue;
+      goto op_colorbalance;
+    case GST_VAAPI_FILTER_OP_SATURATION:
+      op_data->va_subtype = VAProcColorBalanceSaturation;
+      goto op_colorbalance;
+    case GST_VAAPI_FILTER_OP_BRIGHTNESS:
+      op_data->va_subtype = VAProcColorBalanceBrightness;
+      goto op_colorbalance;
+    case GST_VAAPI_FILTER_OP_CONTRAST:
+      op_data->va_subtype = VAProcColorBalanceContrast;
+    op_colorbalance:
+      op_data->va_type = VAProcFilterColorBalance;
+      op_data->va_cap_size = sizeof (VAProcFilterCapColorBalance);
+      op_data->va_buffer_size =
+          sizeof (VAProcFilterParameterBufferColorBalance);
+      break;
+    case GST_VAAPI_FILTER_OP_DEINTERLACING:
+      op_data->va_type = VAProcFilterDeinterlacing;
+      op_data->va_cap_size = sizeof (VAProcFilterCapDeinterlacing);
+      op_data->va_buffer_size =
+          sizeof (VAProcFilterParameterBufferDeinterlacing);
+      break;
+    default:
+      g_assert (0 && "unsupported operation");
+      goto error;
+  }
+  return op_data;
+
+  /* ERRORS */
+error:
+  {
+    op_data_free (op_data);
+    return NULL;
+  }
+}
+
+static inline gpointer
+op_data_ref (gpointer data)
+{
+  GstVaapiFilterOpData *const op_data = data;
+
+  g_return_val_if_fail (op_data != NULL, NULL);
+
+  g_atomic_int_inc (&op_data->ref_count);
+  return op_data;
+}
+
+static void
+op_data_unref (gpointer data)
+{
+  GstVaapiFilterOpData *const op_data = data;
+
+  g_return_if_fail (op_data != NULL);
+  g_return_if_fail (op_data->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test (&op_data->ref_count))
+    op_data_free (op_data);
+}
+
+/* Ensure capability info is set up for the VA filter we are interested in */
+static gboolean
+op_data_ensure_caps (GstVaapiFilterOpData * op_data, gpointer filter_caps,
+    guint num_filter_caps)
+{
+  guchar *filter_cap = filter_caps;
+  guint i, va_num_caps = num_filter_caps;
+
+  // Find the VA filter cap matching the op info sub-type
+  if (op_data->va_subtype) {
+    for (i = 0; i < num_filter_caps; i++) {
+      /* XXX: sub-type shall always be the first field */
+      if (op_data->va_subtype == *(guint *) filter_cap) {
+        va_num_caps = 1;
+        break;
+      }
+      filter_cap += op_data->va_cap_size;
+    }
+    if (i == num_filter_caps)
+      return FALSE;
+  }
+
+  op_data->va_caps = g_memdup2 (filter_cap, op_data->va_cap_size * va_num_caps);
+  if (!op_data->va_caps)
+    return FALSE;
+
+  op_data->va_num_caps = va_num_caps;
+  return TRUE;
+}
+
+/* Scale the filter value wrt. library spec and VA driver spec */
+static gboolean
+op_data_get_value_float (GstVaapiFilterOpData * op_data,
+    const VAProcFilterValueRange * range, gfloat value, gfloat * out_value_ptr)
+{
+  GParamSpecFloat *const pspec = G_PARAM_SPEC_FLOAT (op_data->pspec);
+  gfloat out_value;
+
+  g_return_val_if_fail (range != NULL, FALSE);
+  g_return_val_if_fail (out_value_ptr != NULL, FALSE);
+
+  if (value < pspec->minimum || value > pspec->maximum)
+    return FALSE;
+
+  // Scale wrt. the medium ("default") value
+  out_value = range->default_value;
+  if (value > pspec->default_value)
+    out_value += ((value - pspec->default_value) /
+        (pspec->maximum - pspec->default_value) *
+        (range->max_value - range->default_value));
+  else if (value < pspec->default_value)
+    out_value -= ((pspec->default_value - value) /
+        (pspec->default_value - pspec->minimum) *
+        (range->default_value - range->min_value));
+
+  *out_value_ptr = out_value;
+  return TRUE;
+}
+
+/* Get default list of operations supported by the library */
+static GPtrArray *
+get_operations_default (void)
+{
+  GPtrArray *ops;
+  guint i;
+
+  ops = g_ptr_array_new_full (N_PROPERTIES, op_data_unref);
+  if (!ops)
+    return NULL;
+
+  ensure_properties ();
+
+  for (i = 0; i < N_PROPERTIES; i++) {
+    GstVaapiFilterOpData *op_data;
+    GParamSpec *const pspec = g_properties[i];
+    if (!pspec)
+      continue;
+
+    op_data = op_data_new (i, pspec);
+    if (!op_data)
+      goto error;
+    g_ptr_array_add (ops, op_data);
+  }
+  return ops;
+
+  /* ERRORS */
+error:
+  {
+    g_ptr_array_unref (ops);
+    return NULL;
+  }
+}
+
+/* Get the ordered list of operations, based on VA/VPP queries */
+static GPtrArray *
+get_operations_ordered (GstVaapiFilter * filter, GPtrArray * default_ops)
+{
+  GPtrArray *ops;
+  VAProcFilterType *filters;
+  gpointer filter_caps = NULL;
+  guint i, j, num_filters, num_filter_caps = 0;
+
+  ops = g_ptr_array_new_full (default_ops->len, op_data_unref);
+  if (!ops)
+    return NULL;
+
+  filters = vpp_get_filters (filter, &num_filters);
+  if (!filters)
+    goto error;
+
+  // Append virtual ops first, i.e. those without an associated VA filter
+  for (i = 0; i < default_ops->len; i++) {
+    GstVaapiFilterOpData *const op_data = g_ptr_array_index (default_ops, i);
+    if (op_data->va_type == VAProcFilterNone)
+      g_ptr_array_add (ops, op_data_ref (op_data));
+  }
+
+  // Append ops, while preserving the VA filters ordering
+  for (i = 0; i < num_filters; i++) {
+    const VAProcFilterType va_type = filters[i];
+    if (va_type == VAProcFilterNone)
+      continue;
+
+    for (j = 0; j < default_ops->len; j++) {
+      GstVaapiFilterOpData *const op_data = g_ptr_array_index (default_ops, j);
+      if (op_data->va_type != va_type)
+        continue;
+
+      if (op_data->va_cap_size == 0) {  /* no caps, like skintone */
+        g_ptr_array_add (ops, op_data_ref (op_data));
+        continue;
+      }
+
+      if (!filter_caps) {
+        filter_caps = vpp_get_filter_caps (filter, va_type,
+            op_data->va_cap_size, &num_filter_caps);
+        if (!filter_caps)
+          continue;
+      }
+
+      if (!op_data_ensure_caps (op_data, filter_caps, num_filter_caps))
+        continue;
+
+      g_ptr_array_add (ops, op_data_ref (op_data));
+    }
+    free (filter_caps);
+    filter_caps = NULL;
+  }
+
+  vpp_get_pipeline_caps (filter);
+
+  if (filter->operations)
+    g_ptr_array_unref (filter->operations);
+  filter->operations = g_ptr_array_ref (ops);
+
+  g_free (filters);
+  g_ptr_array_unref (default_ops);
+  return ops;
+
+  /* ERRORS */
+error:
+  {
+    g_free (filter_caps);
+    g_free (filters);
+    g_ptr_array_unref (ops);
+    g_ptr_array_unref (default_ops);
+    return NULL;
+  }
+}
+
+/* Determine the set of supported VPP operations by the specific
+   filter, or known to this library if filter is NULL */
+static GPtrArray *
+get_operations (GstVaapiFilter * filter)
+{
+  GPtrArray *ops;
+
+  if (filter && filter->operations)
+    return g_ptr_array_ref (filter->operations);
+
+  ops = get_operations_default ();
+  if (!ops)
+    return NULL;
+  return filter ? get_operations_ordered (filter, ops) : ops;
+}
+
+/* Ensure the set of supported VPP operations is cached into the
+   GstVaapiFilter::operations member */
+static inline gboolean
+ensure_operations (GstVaapiFilter * filter)
+{
+  GPtrArray *ops;
+
+  if (!filter)
+    return FALSE;
+
+  if (filter->operations)
+    return TRUE;
+
+  ops = get_operations (filter);
+  if (!ops)
+    return FALSE;
+
+  g_ptr_array_unref (ops);
+  return TRUE;
+}
+
+/* Find whether the VPP operation is supported or not */
+static GstVaapiFilterOpData *
+find_operation (GstVaapiFilter * filter, GstVaapiFilterOp op)
+{
+  guint i;
+
+  if (!ensure_operations (filter))
+    return NULL;
+
+  for (i = 0; i < filter->operations->len; i++) {
+    GstVaapiFilterOpData *const op_data =
+        g_ptr_array_index (filter->operations, i);
+    if (op_data->op == op)
+      return op_data;
+  }
+  return NULL;
+}
+
+/* Ensure the operation's VA buffer is allocated */
+static inline gboolean
+op_ensure_n_elements_buffer (GstVaapiFilter * filter,
+    GstVaapiFilterOpData * op_data, gint op_num)
+{
+  if (G_LIKELY (op_data->va_buffer != VA_INVALID_ID))
+    return TRUE;
+  return vaapi_create_n_elements_buffer (filter->va_display, filter->va_context,
+      VAProcFilterParameterBufferType, op_data->va_buffer_size, NULL,
+      &op_data->va_buffer, NULL, op_num);
+}
+
+static inline gboolean
+op_ensure_buffer (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data)
+{
+  return op_ensure_n_elements_buffer (filter, op_data, 1);
+}
+
+/* Update a generic filter (float value) */
+static gboolean
+op_set_generic_unlocked (GstVaapiFilter * filter,
+    GstVaapiFilterOpData * op_data, gfloat value)
+{
+  VAProcFilterParameterBuffer *buf;
+  VAProcFilterCap *filter_cap;
+  gfloat va_value;
+
+  if (!op_data || !op_ensure_buffer (filter, op_data))
+    return FALSE;
+
+  op_data->is_enabled = (value != OP_DATA_DEFAULT_VALUE (float, op_data));
+  if (!op_data->is_enabled)
+    return TRUE;
+
+  filter_cap = op_data->va_caps;
+  if (!op_data_get_value_float (op_data, &filter_cap->range, value, &va_value))
+    return FALSE;
+
+  buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer);
+  if (!buf)
+    return FALSE;
+
+  buf->type = op_data->va_type;
+  buf->value = va_value;
+  vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL);
+  return TRUE;
+}
+
+static inline gboolean
+op_set_generic (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data,
+    gfloat value)
+{
+  gboolean success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  success = op_set_generic_unlocked (filter, op_data, value);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+  return success;
+}
+
+/* Update the color balance filter */
+#define COLOR_BALANCE_NUM \
+    GST_VAAPI_FILTER_OP_CONTRAST - GST_VAAPI_FILTER_OP_HUE + 1
+
+static gboolean
+op_set_color_balance_unlocked (GstVaapiFilter * filter,
+    GstVaapiFilterOpData * op_data, gfloat value)
+{
+  VAProcFilterParameterBufferColorBalance *buf;
+  VAProcFilterCapColorBalance *filter_cap;
+  gfloat va_value;
+  gint i;
+  GstVaapiFilterOpData *color_data[COLOR_BALANCE_NUM];
+  GstVaapiFilterOpData *enabled_data = NULL;
+  gboolean ret = TRUE;
+
+  if (!op_data)
+    return FALSE;
+
+  /* collect all the Color Balance operators and find the first
+   * enabled one */
+  for (i = 0; i < COLOR_BALANCE_NUM; i++) {
+    color_data[i] = find_operation (filter, GST_VAAPI_FILTER_OP_HUE + i);
+    if (!color_data[i])
+      return FALSE;
+
+    if (!enabled_data && color_data[i]->is_enabled)
+      enabled_data = color_data[i];
+  }
+
+  /* If there's no enabled operators let's enable this one.
+   *
+   * HACK: This operator will be the only one with an allocated buffer
+   * which will store all the color balance operators.
+   */
+  if (!enabled_data) {
+    /* *INDENT-OFF* */
+    if (value == OP_DATA_DEFAULT_VALUE (float, op_data))
+      return TRUE;
+    /* *INDENT-ON* */
+
+    if (!op_ensure_n_elements_buffer (filter, op_data, COLOR_BALANCE_NUM))
+      return FALSE;
+
+    enabled_data = op_data;
+
+    buf = vaapi_map_buffer (filter->va_display, enabled_data->va_buffer);
+    if (!buf)
+      return FALSE;
+
+    /* Write all the color balance operator values in the buffer. --
+     * Use the default value for all the operators except the set
+     * one. */
+    for (i = 0; i < COLOR_BALANCE_NUM; i++) {
+      buf[i].type = color_data[i]->va_type;
+      buf[i].attrib = color_data[i]->va_subtype;
+
+      va_value = OP_DATA_DEFAULT_VALUE (float, color_data[i]);
+      if (color_data[i]->op == op_data->op) {
+        filter_cap = color_data[i]->va_caps;
+        /* fail but ignore current value and set default one */
+        if (!op_data_get_value_float (color_data[i], &filter_cap->range, value,
+                &va_value))
+          ret = FALSE;
+      }
+
+      buf[i].value = va_value;
+    }
+
+    enabled_data->is_enabled = 1;
+  } else {
+    /* There's already one operator enabled, *in theory* with a
+     * buffer associated. */
+    if (G_UNLIKELY (enabled_data->va_buffer == VA_INVALID_ID))
+      return FALSE;
+
+    filter_cap = op_data->va_caps;
+    if (!op_data_get_value_float (op_data, &filter_cap->range, value,
+            &va_value))
+      return FALSE;
+
+    buf = vaapi_map_buffer (filter->va_display, enabled_data->va_buffer);
+    if (!buf)
+      return FALSE;
+
+    buf[op_data->op - GST_VAAPI_FILTER_OP_HUE].value = va_value;
+  }
+
+  vaapi_unmap_buffer (filter->va_display, enabled_data->va_buffer, NULL);
+
+  return ret;
+}
+
+static inline gboolean
+op_set_color_balance (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data,
+    gfloat value)
+{
+  gboolean success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  success = op_set_color_balance_unlocked (filter, op_data, value);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+  return success;
+}
+
+/* Update deinterlace filter */
+static gboolean
+op_set_deinterlace_unlocked (GstVaapiFilter * filter,
+    GstVaapiFilterOpData * op_data, GstVaapiDeinterlaceMethod method,
+    guint flags)
+{
+  VAProcFilterParameterBufferDeinterlacing *buf;
+  const VAProcFilterCapDeinterlacing *filter_caps;
+  VAProcDeinterlacingType algorithm;
+  guint i;
+
+  if (!op_data || !op_ensure_buffer (filter, op_data))
+    return FALSE;
+
+  op_data->is_enabled = (method != GST_VAAPI_DEINTERLACE_METHOD_NONE);
+  if (!op_data->is_enabled)
+    return TRUE;
+
+  algorithm = from_GstVaapiDeinterlaceMethod (method);
+  for (i = 0, filter_caps = op_data->va_caps; i < op_data->va_num_caps; i++) {
+    if (filter_caps[i].type == algorithm)
+      break;
+  }
+  if (i == op_data->va_num_caps)
+    return FALSE;
+
+  buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer);
+  if (!buf)
+    return FALSE;
+
+  buf->type = op_data->va_type;
+  buf->algorithm = algorithm;
+  buf->flags = from_GstVaapiDeinterlaceFlags (flags);
+  vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL);
+  return TRUE;
+}
+
+static inline gboolean
+op_set_deinterlace (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data,
+    GstVaapiDeinterlaceMethod method, guint flags)
+{
+  gboolean success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  success = op_set_deinterlace_unlocked (filter, op_data, method, flags);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+  return success;
+}
+
+/* Update skin tone enhancement level */
+static gboolean
+op_set_skintone_level_unlocked (GstVaapiFilter * filter,
+    GstVaapiFilterOpData * op_data, guint value)
+{
+  VAProcFilterParameterBuffer *buf;
+
+  if (!op_data || !op_ensure_buffer (filter, op_data))
+    return FALSE;
+
+  op_data->is_enabled = 1;
+
+  buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer);
+  if (!buf)
+    return FALSE;
+  buf->type = op_data->va_type;
+  buf->value = value;
+  vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL);
+  return TRUE;
+}
+
+static inline gboolean
+op_set_skintone_level (GstVaapiFilter * filter,
+    GstVaapiFilterOpData * op_data, guint value)
+{
+  gboolean success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  success = op_set_skintone_level_unlocked (filter, op_data, value);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+  return success;
+}
+
+#ifndef GST_REMOVE_DEPRECATED
+/* Update skin tone enhancement */
+static gboolean
+op_set_skintone_unlocked (GstVaapiFilter * filter,
+    GstVaapiFilterOpData * op_data, gboolean value)
+{
+  if (!op_data)
+    return FALSE;
+
+  if (!value) {
+    op_data->is_enabled = 0;
+    return TRUE;
+  }
+
+  return op_set_skintone_level_unlocked (filter, op_data, 3);
+}
+
+static inline gboolean
+op_set_skintone (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data,
+    gboolean enhance)
+{
+  gboolean success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  success = op_set_skintone_unlocked (filter, op_data, enhance);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+  return success;
+}
+#endif
+
+static gboolean
+op_set_hdr_tone_map_unlocked (GstVaapiFilter * filter,
+    GstVaapiFilterOpData * op_data, gboolean value)
+{
+#if VA_CHECK_VERSION(1,4,0)
+  const VAProcFilterCapHighDynamicRange *filter_caps;
+  guint i;
+
+  if (!op_data)
+    return !value;
+
+  if (!value) {
+    op_data->is_enabled = 0;
+    return TRUE;
+  }
+
+  if (!op_ensure_buffer (filter, op_data))
+    return FALSE;
+
+  for (i = 0, filter_caps = op_data->va_caps; i < op_data->va_num_caps; i++) {
+    if (filter_caps[i].metadata_type == op_data->va_subtype &&
+        (filter_caps[i].caps_flag & VA_TONE_MAPPING_HDR_TO_SDR))
+      break;
+  }
+  if (i == op_data->va_num_caps)
+    return FALSE;
+
+  op_data->is_enabled = 1;
+
+  return TRUE;
+#else
+  return !value;
+#endif
+}
+
+static inline gboolean
+op_set_hdr_tone_map (GstVaapiFilter * filter, GstVaapiFilterOpData * op_data,
+    gboolean value)
+{
+  gboolean success = FALSE;
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  success = op_set_hdr_tone_map_unlocked (filter, op_data, value);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+
+  return success;
+}
+
+static gboolean
+deint_refs_set (GArray * refs, GstVaapiSurface ** surfaces, guint num_surfaces)
+{
+  guint i;
+
+  if (num_surfaces > 0 && !surfaces)
+    return FALSE;
+
+  for (i = 0; i < num_surfaces; i++)
+    g_array_append_val (refs, GST_VAAPI_SURFACE_ID (surfaces[i]));
+  return TRUE;
+}
+
+static void
+deint_refs_clear (GArray * refs)
+{
+  if (refs->len > 0)
+    g_array_remove_range (refs, 0, refs->len);
+}
+
+static inline void
+deint_refs_clear_all (GstVaapiFilter * filter)
+{
+  deint_refs_clear (filter->forward_references);
+  deint_refs_clear (filter->backward_references);
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Surface Attribs                                                   --- */
+/* ------------------------------------------------------------------------- */
+
+static gboolean
+ensure_attributes (GstVaapiFilter * filter)
+{
+  if (G_LIKELY (filter->attribs))
+    return TRUE;
+
+  filter->attribs = gst_vaapi_config_surface_attributes_get (filter->display,
+      filter->va_config);
+  return (filter->attribs != NULL);
+}
+
+static inline gboolean
+is_special_format (GstVideoFormat format)
+{
+  return format == GST_VIDEO_FORMAT_UNKNOWN ||
+      format == GST_VIDEO_FORMAT_ENCODED;
+}
+
+static gboolean
+find_format (GstVaapiFilter * filter, GstVideoFormat format)
+{
+  guint i;
+  GArray *formats;
+
+  formats = filter->attribs->formats;
+  if (is_special_format (format) || !formats)
+    return FALSE;
+
+  for (i = 0; i < formats->len; i++) {
+    if (g_array_index (formats, GstVideoFormat, i) == format)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+/* ------------------------------------------------------------------------- */
+/* --- Interface                                                         --- */
+/* ------------------------------------------------------------------------- */
+
+static void
+gst_vaapi_filter_init (GstVaapiFilter * filter)
+{
+  filter->va_config = VA_INVALID_ID;
+  filter->va_context = VA_INVALID_ID;
+  filter->format = DEFAULT_FORMAT;
+
+  filter->forward_references =
+      g_array_sized_new (FALSE, FALSE, sizeof (VASurfaceID), 4);
+
+  filter->backward_references =
+      g_array_sized_new (FALSE, FALSE, sizeof (VASurfaceID), 4);
+}
+
+static gboolean
+gst_vaapi_filter_initialize (GstVaapiFilter * filter)
+{
+  VAStatus va_status;
+
+  if (!filter->display)
+    return FALSE;
+
+  va_status = vaCreateConfig (filter->va_display, VAProfileNone,
+      VAEntrypointVideoProc, NULL, 0, &filter->va_config);
+  if (!vaapi_check_status (va_status, "vaCreateConfig() [VPP]"))
+    return FALSE;
+
+  va_status = vaCreateContext (filter->va_display, filter->va_config, 0, 0, 0,
+      NULL, 0, &filter->va_context);
+  if (!vaapi_check_status (va_status, "vaCreateContext() [VPP]"))
+    return FALSE;
+
+  gst_video_colorimetry_from_string (&filter->input_colorimetry, NULL);
+  gst_video_colorimetry_from_string (&filter->output_colorimetry, NULL);
+
+  return TRUE;
+}
+
+static void
+gst_vaapi_filter_finalize (GObject * object)
+{
+  GstVaapiFilter *const filter = GST_VAAPI_FILTER (object);
+  guint i;
+
+  if (!filter->display)
+    goto bail;
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  if (filter->operations) {
+    for (i = 0; i < filter->operations->len; i++) {
+      GstVaapiFilterOpData *const op_data =
+          g_ptr_array_index (filter->operations, i);
+      vaapi_destroy_buffer (filter->va_display, &op_data->va_buffer);
+    }
+    g_ptr_array_unref (filter->operations);
+    filter->operations = NULL;
+  }
+
+  if (filter->va_context != VA_INVALID_ID) {
+    vaDestroyContext (filter->va_display, filter->va_context);
+    filter->va_context = VA_INVALID_ID;
+  }
+
+  if (filter->va_config != VA_INVALID_ID) {
+    vaDestroyConfig (filter->va_display, filter->va_config);
+    filter->va_config = VA_INVALID_ID;
+  }
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+  gst_vaapi_display_replace (&filter->display, NULL);
+
+bail:
+  if (filter->forward_references) {
+    g_array_unref (filter->forward_references);
+    filter->forward_references = NULL;
+  }
+
+  if (filter->backward_references) {
+    g_array_unref (filter->backward_references);
+    filter->backward_references = NULL;
+  }
+
+  if (filter->attribs) {
+    gst_vaapi_config_surface_attributes_free (filter->attribs);
+    filter->attribs = NULL;
+  }
+
+  G_OBJECT_CLASS (gst_vaapi_filter_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_filter_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiFilter *const filter = GST_VAAPI_FILTER (object);
+
+  switch (property_id) {
+    case PROP_DISPLAY:{
+      GstVaapiDisplay *display = g_value_get_object (value);;
+
+      if (display) {
+        if (GST_VAAPI_DISPLAY_HAS_VPP (display)) {
+          filter->display = gst_object_ref (display);
+          filter->va_display = GST_VAAPI_DISPLAY_VADISPLAY (filter->display);
+        } else {
+          GST_WARNING_OBJECT (filter, "VA display doesn't support VPP");
+        }
+      }
+      break;
+    }
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_filter_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiFilter *const filter = GST_VAAPI_FILTER (object);
+
+  switch (property_id) {
+    case PROP_DISPLAY:
+      g_value_set_object (value, filter->display);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+  }
+}
+
+static void
+gst_vaapi_filter_class_init (GstVaapiFilterClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = gst_vaapi_filter_set_property;
+  object_class->get_property = gst_vaapi_filter_get_property;
+  object_class->finalize = gst_vaapi_filter_finalize;
+
+  /**
+   * GstVaapiFilter:display:
+   *
+   * #GstVaapiDisplay to be used.
+   */
+  g_object_class_install_property (object_class, PROP_DISPLAY,
+      g_param_spec_object ("display", "Gst VA-API Display",
+          "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY,
+          G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME));
+}
+
+/**
+ * gst_vaapi_filter_new:
+ * @display: a #GstVaapiDisplay
+ *
+ * Creates a new #GstVaapiFilter set up to operate in "identity"
+ * mode. This means that no other operation than scaling is performed.
+ *
+ * Return value: the newly created #GstVaapiFilter object
+ */
+GstVaapiFilter *
+gst_vaapi_filter_new (GstVaapiDisplay * display)
+{
+  GstVaapiFilter *filter;
+
+  filter = g_object_new (GST_TYPE_VAAPI_FILTER, "display", display, NULL);
+  if (!gst_vaapi_filter_initialize (filter))
+    goto error;
+  return filter;
+
+  /* ERRORS */
+error:
+  {
+    gst_object_unref (filter);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_filter_replace:
+ * @old_filter_ptr: a pointer to a #GstVaapiFilter
+ * @new_filter: a #GstVaapiFilter
+ *
+ * Atomically replaces the filter held in @old_filter_ptr with
+ * @new_filter. This means that @old_filter_ptr shall reference a
+ * valid filter. However, @new_filter can be NULL.
+ */
+void
+gst_vaapi_filter_replace (GstVaapiFilter ** old_filter_ptr,
+    GstVaapiFilter * new_filter)
+{
+  g_return_if_fail (old_filter_ptr != NULL);
+
+  gst_object_replace ((GstObject **) old_filter_ptr, GST_OBJECT (new_filter));
+}
+
+/**
+ * gst_vaapi_filter_get_operations:
+ * @filter: a #GstVaapiFilter, or %NULL
+ *
+ * Determines the set of supported operations for video processing.
+ * The caller owns an extra reference to the resulting array of
+ * #GstVaapiFilterOpInfo elements, so it shall be released with
+ * g_ptr_array_unref() after usage.
+ *
+ * If @filter is %NULL, then this function returns the video
+ * processing operations supported by this library.
+ *
+ * Return value: the set of supported operations, or %NULL if an error
+ *   occurred.
+ */
+GPtrArray *
+gst_vaapi_filter_get_operations (GstVaapiFilter * filter)
+{
+  return get_operations (filter);
+}
+
+/**
+ * gst_vaapi_filter_has_operation:
+ * @filter: a #GstVaapiFilter
+ * @op: a #GstVaapiFilterOp
+ *
+ * Determines whether the underlying VA driver advertises support for
+ * the supplied operation @op.
+ *
+ * Return value: %TRUE if the specified operation may be supported by
+ *   the underlying hardware, %FALSE otherwise
+ */
+gboolean
+gst_vaapi_filter_has_operation (GstVaapiFilter * filter, GstVaapiFilterOp op)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return find_operation (filter, op) != NULL;
+}
+
+/**
+ * gst_vaapi_filter_use_operation:
+ * @filter: a #GstVaapiFilter
+ * @op: a #GstVaapiFilterOp
+ *
+ * Determines whether the supplied operation @op was already enabled
+ * through a prior call to gst_vaapi_filter_set_operation() or any
+ * other operation-specific function.
+ *
+ * Note: should an operation be set to its default value, this means
+ * that it is actually not enabled.
+ *
+ * Return value: %TRUE if the specified operation was already enabled,
+ *   %FALSE otherwise
+ */
+gboolean
+gst_vaapi_filter_use_operation (GstVaapiFilter * filter, GstVaapiFilterOp op)
+{
+  GstVaapiFilterOpData *op_data;
+
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  op_data = find_operation (filter, op);
+  if (!op_data)
+    return FALSE;
+  return op_data->is_enabled;
+}
+
+/**
+ * gst_vaapi_filter_set_operation:
+ * @filter: a #GstVaapiFilter
+ * @op: a #GstVaapiFilterOp
+ * @value: the @op settings
+ *
+ * Enable the specified operation @op to be performed during video
+ * processing, i.e. in gst_vaapi_filter_process(). The @value argument
+ * specifies the operation settings. e.g. deinterlacing method for
+ * deinterlacing, denoising level for noise reduction, etc.
+ *
+ * If @value is %NULL, then this function resets the operation
+ * settings to their default values.
+ *
+ * Return value: %TRUE if the specified operation may be supported,
+ *   %FALSE otherwise
+ */
+gboolean
+gst_vaapi_filter_set_operation (GstVaapiFilter * filter, GstVaapiFilterOp op,
+    const GValue * value)
+{
+  GstVaapiFilterOpData *op_data;
+
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  op_data = find_operation (filter, op);
+  if (!op_data)
+    return FALSE;
+
+  if (value && !G_VALUE_HOLDS (value, G_PARAM_SPEC_VALUE_TYPE (op_data->pspec)))
+    return FALSE;
+
+  switch (op) {
+    case GST_VAAPI_FILTER_OP_FORMAT:
+      return gst_vaapi_filter_set_format (filter, value ?
+          g_value_get_enum (value) : DEFAULT_FORMAT);
+    case GST_VAAPI_FILTER_OP_CROP:
+      return gst_vaapi_filter_set_cropping_rectangle (filter, value ?
+          g_value_get_boxed (value) : NULL);
+    case GST_VAAPI_FILTER_OP_DENOISE:
+    case GST_VAAPI_FILTER_OP_SHARPEN:
+      return op_set_generic (filter, op_data,
+          (value ? g_value_get_float (value) :
+              OP_DATA_DEFAULT_VALUE (float, op_data)));
+    case GST_VAAPI_FILTER_OP_HUE:
+    case GST_VAAPI_FILTER_OP_SATURATION:
+    case GST_VAAPI_FILTER_OP_BRIGHTNESS:
+    case GST_VAAPI_FILTER_OP_CONTRAST:
+      return op_set_color_balance (filter, op_data,
+          (value ? g_value_get_float (value) :
+              OP_DATA_DEFAULT_VALUE (float, op_data)));
+    case GST_VAAPI_FILTER_OP_DEINTERLACING:
+      return op_set_deinterlace (filter, op_data,
+          (value ? g_value_get_enum (value) :
+              OP_DATA_DEFAULT_VALUE (enum, op_data)), 0);
+      break;
+    case GST_VAAPI_FILTER_OP_SCALING:
+      return gst_vaapi_filter_set_scaling (filter,
+          (value ? g_value_get_enum (value) :
+              OP_DATA_DEFAULT_VALUE (enum, op_data)));
+#ifndef GST_REMOVE_DEPRECATED
+    case GST_VAAPI_FILTER_OP_SKINTONE:
+      return op_set_skintone (filter, op_data,
+          (value ? g_value_get_boolean (value) :
+              OP_DATA_DEFAULT_VALUE (boolean, op_data)));
+#endif
+    case GST_VAAPI_FILTER_OP_SKINTONE_LEVEL:
+      return op_set_skintone_level (filter, op_data,
+          (value ? g_value_get_uint (value) :
+              OP_DATA_DEFAULT_VALUE (uint, op_data)));
+    case GST_VAAPI_FILTER_OP_VIDEO_DIRECTION:
+      return gst_vaapi_filter_set_video_direction (filter,
+          (value ? g_value_get_enum (value) :
+              OP_DATA_DEFAULT_VALUE (enum, op_data)));
+    case GST_VAAPI_FILTER_OP_HDR_TONE_MAP:
+      return op_set_hdr_tone_map (filter, op_data,
+          (value ? g_value_get_boolean (value) :
+              OP_DATA_DEFAULT_VALUE (boolean, op_data)));
+    default:
+      break;
+  }
+  return FALSE;
+}
+
+#if VA_CHECK_VERSION(1,2,0)
+static void
+fill_color_standard (GstVideoColorimetry * colorimetry,
+    VAProcColorStandardType * type, VAProcColorProperties * properties)
+{
+  *type = from_GstVideoColorimetry (colorimetry);
+
+  properties->colour_primaries =
+      gst_video_color_primaries_to_iso (colorimetry->primaries);
+  properties->transfer_characteristics =
+      gst_video_transfer_function_to_iso (colorimetry->transfer);
+  properties->matrix_coefficients =
+      gst_video_color_matrix_to_iso (colorimetry->matrix);
+
+  properties->color_range = from_GstVideoColorRange (colorimetry->range);
+}
+#endif
+
+static void
+gst_vaapi_filter_fill_color_standards (GstVaapiFilter * filter,
+    VAProcPipelineParameterBuffer * pipeline_param)
+{
+#if VA_CHECK_VERSION(1,2,0)
+  fill_color_standard (&filter->input_colorimetry,
+      &pipeline_param->surface_color_standard,
+      &pipeline_param->input_color_properties);
+
+  fill_color_standard (&filter->output_colorimetry,
+      &pipeline_param->output_color_standard,
+      &pipeline_param->output_color_properties);
+#else
+  pipeline_param->surface_color_standard = VAProcColorStandardNone;
+  pipeline_param->output_color_standard = VAProcColorStandardNone;
+#endif
+}
+
+/**
+ * gst_vaapi_filter_process:
+ * @filter: a #GstVaapiFilter
+ * @src_surface: the source @GstVaapiSurface
+ * @dst_surface: the destination @GstVaapiSurface
+ * @flags: #GstVaapiSurfaceRenderFlags that apply to @src_surface
+ *
+ * Applies the operations currently defined in the @filter to
+ * @src_surface and return the output in @dst_surface. The order of
+ * operations is determined in a way that suits best the underlying
+ * hardware. i.e. the only guarantee held is the generated outcome,
+ * not any specific order of operations.
+ *
+ * Return value: a #GstVaapiFilterStatus
+ */
+static GstVaapiFilterStatus
+gst_vaapi_filter_process_unlocked (GstVaapiFilter * filter,
+    GstVaapiSurface * src_surface, GstVaapiSurface * dst_surface, guint flags)
+{
+  VAProcPipelineParameterBuffer *pipeline_param = NULL;
+  VABufferID pipeline_param_buf_id = VA_INVALID_ID;
+  VABufferID filters[N_PROPERTIES];
+  VAProcPipelineCaps pipeline_caps;
+  guint i, num_filters = 0;
+  VAStatus va_status;
+  VARectangle src_rect, dst_rect;
+  guint va_mirror = 0, va_rotation = 0;
+
+  if (!ensure_operations (filter))
+    return GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED;
+
+  /* Build surface region (source) */
+  if (filter->use_crop_rect) {
+    const GstVaapiRectangle *const crop_rect = &filter->crop_rect;
+
+    if ((crop_rect->x + crop_rect->width >
+            GST_VAAPI_SURFACE_WIDTH (src_surface)) ||
+        (crop_rect->y + crop_rect->height >
+            GST_VAAPI_SURFACE_HEIGHT (src_surface)))
+      goto error;
+
+    src_rect.x = crop_rect->x;
+    src_rect.y = crop_rect->y;
+    src_rect.width = crop_rect->width;
+    src_rect.height = crop_rect->height;
+  } else {
+    src_rect.x = 0;
+    src_rect.y = 0;
+    src_rect.width = GST_VAAPI_SURFACE_WIDTH (src_surface);
+    src_rect.height = GST_VAAPI_SURFACE_HEIGHT (src_surface);
+  }
+
+  /* Build output region (target) */
+  if (filter->use_target_rect) {
+    const GstVaapiRectangle *const target_rect = &filter->target_rect;
+
+    if ((target_rect->x + target_rect->width >
+            GST_VAAPI_SURFACE_WIDTH (dst_surface)) ||
+        (target_rect->y + target_rect->height >
+            GST_VAAPI_SURFACE_HEIGHT (dst_surface)))
+      goto error;
+
+    dst_rect.x = target_rect->x;
+    dst_rect.y = target_rect->y;
+    dst_rect.width = target_rect->width;
+    dst_rect.height = target_rect->height;
+  } else {
+    dst_rect.x = 0;
+    dst_rect.y = 0;
+    dst_rect.width = GST_VAAPI_SURFACE_WIDTH (dst_surface);
+    dst_rect.height = GST_VAAPI_SURFACE_HEIGHT (dst_surface);
+  }
+
+  for (i = 0, num_filters = 0; i < filter->operations->len; i++) {
+    GstVaapiFilterOpData *const op_data =
+        g_ptr_array_index (filter->operations, i);
+    if (!op_data->is_enabled)
+      continue;
+    if (op_data->va_buffer == VA_INVALID_ID) {
+      GST_ERROR ("invalid VA buffer for operation %s",
+          g_param_spec_get_name (op_data->pspec));
+      goto error;
+    }
+    filters[num_filters++] = op_data->va_buffer;
+  }
+
+  /* Validate pipeline caps */
+  va_status = vaQueryVideoProcPipelineCaps (filter->va_display,
+      filter->va_context, filters, num_filters, &pipeline_caps);
+  if (!vaapi_check_status (va_status, "vaQueryVideoProcPipelineCaps()"))
+    goto error;
+
+  if (!vaapi_create_buffer (filter->va_display, filter->va_context,
+          VAProcPipelineParameterBufferType, sizeof (*pipeline_param),
+          NULL, &pipeline_param_buf_id, (gpointer *) & pipeline_param))
+    goto error;
+
+  memset (pipeline_param, 0, sizeof (*pipeline_param));
+  pipeline_param->surface = GST_VAAPI_SURFACE_ID (src_surface);
+  pipeline_param->surface_region = &src_rect;
+
+  gst_vaapi_filter_fill_color_standards (filter, pipeline_param);
+
+  pipeline_param->output_region = &dst_rect;
+  pipeline_param->output_background_color = 0xff000000;
+  pipeline_param->filter_flags = from_GstVaapiSurfaceRenderFlags (flags) |
+      from_GstVaapiScaleMethod (filter->scale_method);
+  pipeline_param->filters = filters;
+  pipeline_param->num_filters = num_filters;
+
+  from_GstVideoOrientationMethod (filter->video_direction, &va_mirror,
+      &va_rotation);
+
+#if VA_CHECK_VERSION(1,1,0)
+  pipeline_param->mirror_state = va_mirror;
+  pipeline_param->rotation_state = va_rotation;
+#endif
+
+  // Reference frames for advanced deinterlacing
+  if (filter->forward_references->len > 0) {
+    pipeline_param->forward_references = (VASurfaceID *)
+        filter->forward_references->data;
+    pipeline_param->num_forward_references =
+        MIN (filter->forward_references->len,
+        pipeline_caps.num_forward_references);
+  } else {
+    pipeline_param->forward_references = NULL;
+    pipeline_param->num_forward_references = 0;
+  }
+
+  if (filter->backward_references->len > 0) {
+    pipeline_param->backward_references = (VASurfaceID *)
+        filter->backward_references->data;
+    pipeline_param->num_backward_references =
+        MIN (filter->backward_references->len,
+        pipeline_caps.num_backward_references);
+  } else {
+    pipeline_param->backward_references = NULL;
+    pipeline_param->num_backward_references = 0;
+  }
+
+  vaapi_unmap_buffer (filter->va_display, pipeline_param_buf_id, NULL);
+
+  va_status = vaBeginPicture (filter->va_display, filter->va_context,
+      GST_VAAPI_SURFACE_ID (dst_surface));
+  if (!vaapi_check_status (va_status, "vaBeginPicture()"))
+    goto error;
+
+  va_status = vaRenderPicture (filter->va_display, filter->va_context,
+      &pipeline_param_buf_id, 1);
+  if (!vaapi_check_status (va_status, "vaRenderPicture()"))
+    goto error;
+
+  va_status = vaEndPicture (filter->va_display, filter->va_context);
+  if (!vaapi_check_status (va_status, "vaEndPicture()"))
+    goto error;
+
+  deint_refs_clear_all (filter);
+  vaapi_destroy_buffer (filter->va_display, &pipeline_param_buf_id);
+  return GST_VAAPI_FILTER_STATUS_SUCCESS;
+
+  /* ERRORS */
+error:
+  {
+    deint_refs_clear_all (filter);
+    vaapi_destroy_buffer (filter->va_display, &pipeline_param_buf_id);
+    return GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED;
+  }
+}
+
+GstVaapiFilterStatus
+gst_vaapi_filter_process (GstVaapiFilter * filter,
+    GstVaapiSurface * src_surface, GstVaapiSurface * dst_surface, guint flags)
+{
+  GstVaapiFilterStatus status;
+
+  g_return_val_if_fail (filter != NULL,
+      GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (src_surface != NULL,
+      GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
+  g_return_val_if_fail (dst_surface != NULL,
+      GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER);
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  status = gst_vaapi_filter_process_unlocked (filter,
+      src_surface, dst_surface, flags);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+  return status;
+}
+
+/**
+ * gst_vaapi_filter_get_formats:
+ * @filter: a #GstVaapiFilter
+ * @min_width: the min width can be supported.
+ * @min_height: the min height can be supported.
+ * @max_width: the max width can be supported.
+ * @max_height: the max height can be supported.
+ *
+ * Determines the set of supported source or target formats for video
+ * processing.  The caller owns an extra reference to the resulting
+ * array of #GstVideoFormat elements, so it shall be released with
+ * g_array_unref() after usage.
+ *
+ * Return value: the set of supported target formats for video processing.
+ */
+GArray *
+gst_vaapi_filter_get_formats (GstVaapiFilter * filter, gint * min_width,
+    gint * min_height, gint * max_width, gint * max_height)
+{
+  GstVaapiConfigSurfaceAttributes *attribs;
+
+  g_return_val_if_fail (filter != NULL, NULL);
+
+  if (!ensure_attributes (filter))
+    return NULL;
+
+  attribs = filter->attribs;
+
+  if (attribs->min_width >= attribs->max_width ||
+      attribs->min_height >= attribs->max_height)
+    return NULL;
+
+  if (min_width)
+    *min_width = attribs->min_width;
+  if (min_height)
+    *min_height = attribs->min_height;
+  if (max_width)
+    *max_width = attribs->max_width;
+  if (max_height)
+    *max_height = attribs->max_height;
+
+  if (filter->attribs->formats)
+    return g_array_ref (filter->attribs->formats);
+  return NULL;
+}
+
+/**
+ * gst_vaapi_filter_set_format:
+ * @filter: a #GstVaapiFilter
+ * @format: the target surface format
+ *
+ * Sets the desired pixel format of the resulting video processing
+ * operations.
+ *
+ * If @format is #GST_VIDEO_FORMAT_UNKNOWN, the filter will assume iso
+ * format conversion, i.e. no color conversion at all and the target
+ * surface format shall match the source surface format.
+ *
+ * If @format is #GST_VIDEO_FORMAT_ENCODED, the filter will use the pixel
+ * format of the target surface passed to gst_vaapi_filter_process().
+ *
+ * Return value: %TRUE if the color conversion to the specified @format
+ *   may be supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_format (GstVaapiFilter * filter, GstVideoFormat format)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  if (!ensure_attributes (filter))
+    return FALSE;
+
+  if (!is_special_format (format) && !find_format (filter, format))
+    return FALSE;
+
+  filter->format = format;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_filter_append_caps:
+ * @filter: a #GstVaapiFilter
+ * @structure: a #GstStructure from #GstCaps
+ *
+ * Extracts the config's surface attributes, from @filter's context,
+ * and transforms it into a caps formats and appended them into
+ * @structure.
+ *
+ * Returns: %TRUE if the capabilities could be extracted and appended
+ * into @structure; otherwise %FALSE
+ **/
+gboolean
+gst_vaapi_filter_append_caps (GstVaapiFilter * filter, GstStructure * structure)
+{
+  GstVaapiConfigSurfaceAttributes *attribs;
+
+  g_return_val_if_fail (filter != NULL, FALSE);
+  g_return_val_if_fail (structure != NULL, FALSE);
+
+  if (!ensure_attributes (filter))
+    return FALSE;
+
+  attribs = filter->attribs;
+
+  if (attribs->min_width >= attribs->max_width ||
+      attribs->min_height >= attribs->max_height)
+    return FALSE;
+
+  gst_structure_set (structure, "width", GST_TYPE_INT_RANGE, attribs->min_width,
+      attribs->max_width, "height", GST_TYPE_INT_RANGE, attribs->min_height,
+      attribs->max_height, NULL);
+
+  return TRUE;
+
+}
+
+/**
+ * gst_vaapi_filter_get_memory_types:
+ * @filter: a #GstVaapiFilter
+ *
+ * Gets the surface's memory types available in @filter's context.
+ *
+ * Returns: surface's memory types available in @filter context.
+ **/
+guint
+gst_vaapi_filter_get_memory_types (GstVaapiFilter * filter)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  if (!ensure_attributes (filter))
+    return 0;
+  return filter->attribs->mem_types;
+}
+
+/**
+ * gst_vaapi_filter_set_cropping_rectangle:
+ * @filter: a #GstVaapiFilter
+ * @rect: the cropping region
+ *
+ * Sets the source surface cropping rectangle to use during the video
+ * processing. If @rect is %NULL, the whole source surface will be used.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_cropping_rectangle (GstVaapiFilter * filter,
+    const GstVaapiRectangle * rect)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  filter->use_crop_rect = rect != NULL;
+  if (filter->use_crop_rect)
+    filter->crop_rect = *rect;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_filter_set_target_rectangle:
+ * @filter: a #GstVaapiFilter
+ * @rect: the target render region
+ *
+ * Sets the region within the target surface where the source surface
+ * would be rendered. i.e. where the hardware accelerator would emit
+ * the outcome of video processing. If @rect is %NULL, the whole
+ * source surface will be used.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_target_rectangle (GstVaapiFilter * filter,
+    const GstVaapiRectangle * rect)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  filter->use_target_rect = rect != NULL;
+  if (filter->use_target_rect)
+    filter->target_rect = *rect;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_filter_set_denoising_level:
+ * @filter: a #GstVaapiFilter
+ * @level: the level of noise reduction to apply
+ *
+ * Sets the noise reduction level to apply. If @level is 0.0f, this
+ * corresponds to disabling the noise reduction algorithm.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_denoising_level (GstVaapiFilter * filter, gfloat level)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_generic (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_DENOISE), level);
+}
+
+/**
+ * gst_vaapi_filter_set_sharpening_level:
+ * @filter: a #GstVaapiFilter
+ * @level: the sharpening factor
+ *
+ * Enables noise reduction with the specified factor.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_sharpening_level (GstVaapiFilter * filter, gfloat level)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_generic (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_SHARPEN), level);
+}
+
+/**
+ * gst_vaapi_filter_set_hue:
+ * @filter: a #GstVaapiFilter
+ * @value: the color hue value
+ *
+ * Enables color hue adjustment to the specified value.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_hue (GstVaapiFilter * filter, gfloat value)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_color_balance (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_HUE), value);
+}
+
+/**
+ * gst_vaapi_filter_set_saturation:
+ * @filter: a #GstVaapiFilter
+ * @value: the color saturation value
+ *
+ * Enables color saturation adjustment to the specified value.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_saturation (GstVaapiFilter * filter, gfloat value)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_color_balance (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_SATURATION), value);
+}
+
+/**
+ * gst_vaapi_filter_set_brightness:
+ * @filter: a #GstVaapiFilter
+ * @value: the color brightness value
+ *
+ * Enables color brightness adjustment to the specified value.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_brightness (GstVaapiFilter * filter, gfloat value)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_color_balance (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_BRIGHTNESS), value);
+}
+
+/**
+ * gst_vaapi_filter_set_contrast:
+ * @filter: a #GstVaapiFilter
+ * @value: the color contrast value
+ *
+ * Enables color contrast adjustment to the specified value.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_contrast (GstVaapiFilter * filter, gfloat value)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_color_balance (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_CONTRAST), value);
+}
+
+/**
+ * gst_vaapi_filter_set_deinterlacing:
+ * @filter: a #GstVaapiFilter
+ * @method: the deinterlacing algorithm (see #GstVaapiDeinterlaceMethod)
+ * @flags: the additional flags
+ *
+ * Applies deinterlacing to the video processing pipeline. If @method
+ * is not @GST_VAAPI_DEINTERLACE_METHOD_NONE, then @flags could
+ * represent the initial picture structure of the source frame.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_deinterlacing (GstVaapiFilter * filter,
+    GstVaapiDeinterlaceMethod method, guint flags)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_deinterlace (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_DEINTERLACING), method,
+      flags);
+}
+
+/**
+ * gst_vaapi_filter_set_deinterlacing_references:
+ * @filter: a #GstVaapiFilter
+ * @forward_references: the set of #GstVaapiSurface objects used as
+ *   forward references
+ * @num_forward_references: the number of elements in the
+ *   @forward_references array
+ * @backward_references: the set of #GstVaapiSurface objects used as
+ *   backward references
+ * @num_backward_references: the number of elements in the
+ *   @backward_references array
+ *
+ * Specifies the list of surfaces used for forward or backward reference in
+ * advanced deinterlacing mode. The caller is responsible for maintaining
+ * the associated surfaces live until gst_vaapi_filter_process() completes.
+ * e.g. by holding an extra reference to the associated #GstVaapiSurfaceProxy.
+ *
+ * Temporal ordering is maintained as follows: the shorter index in
+ * either array is, the closest the matching surface is relatively to
+ * the current source surface to process. e.g. surface in
+ * @forward_references array index 0 represents the immediately
+ * preceding surface in display order, surface at index 1 is the one
+ * preceding surface at index 0, etc.
+ *
+ * The video processing filter will only use the recommended number of
+ * surfaces for backward and forward references.
+ *
+ * Note: the supplied lists of reference surfaces are not sticky. This
+ * means that they are only valid for the next gst_vaapi_filter_process()
+ * call, and thus needs to be submitted again for subsequent calls.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_deinterlacing_references (GstVaapiFilter * filter,
+    GstVaapiSurface ** forward_references, guint num_forward_references,
+    GstVaapiSurface ** backward_references, guint num_backward_references)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  deint_refs_clear_all (filter);
+
+  if (!deint_refs_set (filter->forward_references, forward_references,
+          num_forward_references))
+    return FALSE;
+
+  if (!deint_refs_set (filter->backward_references, backward_references,
+          num_backward_references))
+    return FALSE;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_filter_set_scaling:
+ * @filter: a #GstVaapiFilter
+ * @method: the scaling algorithm (see #GstVaapiScaleMethod)
+ *
+ * Applies scaling algorithm to the video processing pipeline.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_scaling (GstVaapiFilter * filter,
+    GstVaapiScaleMethod method)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  filter->scale_method = method;
+  return TRUE;
+}
+
+#ifndef GST_REMOVE_DEPRECATED
+/**
+ * gst_vaapi_filter_set_skintone:
+ * @filter: a #GstVaapiFilter
+ * @enhance: %TRUE if enable the skin tone enhancement algorithm
+ *
+ * Applies the skin tone enhancement algorithm.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE
+ * otherwise.
+  **/
+gboolean
+gst_vaapi_filter_set_skintone (GstVaapiFilter * filter, gboolean enhance)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_skintone (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_SKINTONE), enhance);
+}
+#endif
+
+/**
+ * gst_vaapi_filter_set_skintone_level:
+ * @filter: a #GstVaapiFilter
+ * @value: the value if enable the skin tone enhancement algorithm
+ *
+ * Applies the skin tone enhancement algorithm with specifled value.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE
+ * otherwise.
+  **/
+gboolean
+gst_vaapi_filter_set_skintone_level (GstVaapiFilter * filter, guint value)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_skintone_level (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL), value);
+}
+
+/**
+ * gst_vaapi_filter_set_video_direction:
+ * @filter: a #GstVaapiFilter
+ * @method: the video direction (see #GstVideoOrientationMethod)
+ *
+ * Applies mirror/rotation to the video processing pipeline.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_video_direction (GstVaapiFilter * filter,
+    GstVideoOrientationMethod method)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+#if VA_CHECK_VERSION(1,1,0)
+  {
+    guint32 va_mirror = VA_MIRROR_NONE;
+    guint32 va_rotation = VA_ROTATION_NONE;
+
+    from_GstVideoOrientationMethod (method, &va_mirror, &va_rotation);
+
+    if (va_mirror != VA_MIRROR_NONE && !(filter->mirror_flags & va_mirror))
+      return FALSE;
+
+    if (va_rotation != VA_ROTATION_NONE
+        && !(filter->rotation_flags & (1 << va_rotation)))
+      return FALSE;
+  }
+#else
+  return FALSE;
+#endif
+
+  filter->video_direction = method;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_filter_get_video_direction:
+ * @filter: a #GstVaapiFilter
+ *
+ * Return value: the currently applied video direction (see #GstVideoOrientationMethod)
+ */
+GstVideoOrientationMethod
+gst_vaapi_filter_get_video_direction (GstVaapiFilter * filter)
+{
+  g_return_val_if_fail (filter != NULL, GST_VIDEO_ORIENTATION_IDENTITY);
+  return filter->video_direction;
+}
+
+gfloat
+gst_vaapi_filter_get_denoising_level_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_DENOISE);
+}
+
+gfloat
+gst_vaapi_filter_get_sharpening_level_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_SHARPEN);
+}
+
+gfloat
+gst_vaapi_filter_get_hue_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_HUE);
+}
+
+gfloat
+gst_vaapi_filter_get_saturation_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_SATURATION);
+}
+
+gfloat
+gst_vaapi_filter_get_brightness_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_BRIGHTNESS);
+}
+
+gfloat
+gst_vaapi_filter_get_contrast_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (float, filter, GST_VAAPI_FILTER_OP_CONTRAST);
+}
+
+GstVaapiScaleMethod
+gst_vaapi_filter_get_scaling_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (enum, filter, GST_VAAPI_FILTER_OP_SCALING);
+}
+
+#ifndef GST_REMOVE_DEPRECATED
+gboolean
+gst_vaapi_filter_get_skintone_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (boolean, filter, GST_VAAPI_FILTER_OP_SKINTONE);
+}
+#endif
+
+guint
+gst_vaapi_filter_get_skintone_level_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (uint, filter, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL);
+}
+
+GstVideoOrientationMethod
+gst_vaapi_filter_get_video_direction_default (GstVaapiFilter * filter)
+{
+  OP_RET_DEFAULT_VALUE (enum, filter, GST_VAAPI_FILTER_OP_VIDEO_DIRECTION);
+}
+
+static gboolean
+gst_vaapi_filter_set_colorimetry_unlocked (GstVaapiFilter * filter,
+    GstVideoColorimetry * input, GstVideoColorimetry * output)
+{
+  gchar *in_color, *out_color;
+
+  if (input)
+    filter->input_colorimetry = *input;
+  else
+    gst_video_colorimetry_from_string (&filter->input_colorimetry, NULL);
+
+  if (output)
+    filter->output_colorimetry = *output;
+  else
+    gst_video_colorimetry_from_string (&filter->output_colorimetry, NULL);
+
+  in_color = gst_video_colorimetry_to_string (&filter->input_colorimetry);
+  GST_DEBUG_OBJECT (filter, " input colorimetry '%s'", in_color);
+
+  out_color = gst_video_colorimetry_to_string (&filter->output_colorimetry);
+  GST_DEBUG_OBJECT (filter, "output colorimetry '%s'", out_color);
+
+  if (!gst_vaapi_display_has_driver_quirks (filter->display,
+          GST_VAAPI_DRIVER_QUIRK_NO_CHECK_VPP_COLOR_STD)) {
+    VAProcPipelineCaps pipeline_caps = { 0, };
+    VAProcColorStandardType type;
+    guint32 i;
+
+    VAStatus va_status = vaQueryVideoProcPipelineCaps (filter->va_display,
+        filter->va_context, NULL, 0, &pipeline_caps);
+
+    if (!vaapi_check_status (va_status, "vaQueryVideoProcPipelineCaps()"))
+      return FALSE;
+
+    type = from_GstVideoColorimetry (&filter->input_colorimetry);
+    for (i = 0; i < pipeline_caps.num_input_color_standards; i++)
+      if (type == pipeline_caps.input_color_standards[i])
+        break;
+    if ((i == pipeline_caps.num_input_color_standards)
+        && (type != VAProcColorStandardNone))
+      GST_WARNING_OBJECT (filter,
+          "driver does not support '%s' input colorimetry."
+          " vpp may fail or produce unexpected results.", in_color);
+
+    type = from_GstVideoColorimetry (&filter->output_colorimetry);
+    for (i = 0; i < pipeline_caps.num_output_color_standards; i++)
+      if (type == pipeline_caps.output_color_standards[i])
+        break;
+    if ((i == pipeline_caps.num_output_color_standards)
+        && (type != VAProcColorStandardNone))
+      GST_WARNING_OBJECT (filter,
+          "driver does not support '%s' output colorimetry."
+          " vpp may fail or produce unexpected results.", out_color);
+  } else {
+    GST_WARNING_OBJECT (filter,
+        "driver does not report the supported input/output colorimetry."
+        " vpp may fail or produce unexpected results.");
+  }
+
+  g_free (in_color);
+  g_free (out_color);
+
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_filter_set_colorimetry (GstVaapiFilter * filter,
+    GstVideoColorimetry * input, GstVideoColorimetry * output)
+{
+  gboolean result;
+
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  result = gst_vaapi_filter_set_colorimetry_unlocked (filter, input, output);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+
+  return result;
+}
+
+/**
+ * gst_vaapi_filter_set_hdr_tone_map:
+ * @filter: a #GstVaapiFilter
+ * @value: %TRUE to enable hdr tone map algorithm
+ *
+ * Applies HDR tone mapping algorithm.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_hdr_tone_map (GstVaapiFilter * filter, gboolean value)
+{
+  g_return_val_if_fail (filter != NULL, FALSE);
+
+  return op_set_hdr_tone_map (filter,
+      find_operation (filter, GST_VAAPI_FILTER_OP_HDR_TONE_MAP), value);
+}
+
+static gboolean
+gst_vaapi_filter_set_hdr_tone_map_meta_unlocked (GstVaapiFilter * filter,
+    GstVideoMasteringDisplayInfo * minfo, GstVideoContentLightLevel * linfo)
+{
+#if VA_CHECK_VERSION(1,4,0)
+  GstVaapiFilterOpData *op_data;
+  VAProcFilterParameterBufferHDRToneMapping *buf;
+  VAHdrMetaDataHDR10 *meta = &filter->hdr_meta;
+
+  op_data = find_operation (filter, GST_VAAPI_FILTER_OP_HDR_TONE_MAP);
+
+  if (!op_data)
+    return FALSE;
+
+  meta->display_primaries_x[0] = minfo->display_primaries[1].x;
+  meta->display_primaries_x[1] = minfo->display_primaries[2].x;
+  meta->display_primaries_x[2] = minfo->display_primaries[0].x;
+
+  meta->display_primaries_y[0] = minfo->display_primaries[1].y;
+  meta->display_primaries_y[1] = minfo->display_primaries[2].y;
+  meta->display_primaries_y[2] = minfo->display_primaries[0].y;
+
+  meta->white_point_x = minfo->white_point.x;
+  meta->white_point_y = minfo->white_point.y;
+
+  meta->max_display_mastering_luminance =
+      minfo->max_display_mastering_luminance;
+  meta->min_display_mastering_luminance =
+      minfo->min_display_mastering_luminance;
+
+  meta->max_content_light_level = linfo->max_content_light_level;
+  meta->max_pic_average_light_level = linfo->max_frame_average_light_level;
+
+  buf = vaapi_map_buffer (filter->va_display, op_data->va_buffer);
+  if (!buf)
+    return FALSE;
+
+  buf->type = op_data->va_type;
+  buf->data.metadata_type = op_data->va_subtype;
+  buf->data.metadata = meta;
+  buf->data.metadata_size = sizeof (meta);
+
+  vaapi_unmap_buffer (filter->va_display, op_data->va_buffer, NULL);
+
+  return TRUE;
+#else
+  return FALSE;
+#endif
+}
+
+/**
+ * gst_vaapi_filter_set_hdr_tone_map_meta:
+ * @filter: a #GstVaapiFilter
+ * @minfo: a #GstVideoMasteringDisplayInfo
+ * @linfo: a #GstVideoContentLightLevel
+ *
+ * Sets the input HDR meta data used for tone mapping.
+ *
+ * Return value: %TRUE if the operation is supported, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_filter_set_hdr_tone_map_meta (GstVaapiFilter * filter,
+    GstVideoMasteringDisplayInfo * minfo, GstVideoContentLightLevel * linfo)
+{
+  gboolean status = FALSE;
+
+  g_return_val_if_fail (filter != NULL, FALSE);
+  g_return_val_if_fail (minfo != NULL, FALSE);
+  g_return_val_if_fail (linfo != NULL, FALSE);
+
+  GST_VAAPI_DISPLAY_LOCK (filter->display);
+  status =
+      gst_vaapi_filter_set_hdr_tone_map_meta_unlocked (filter, minfo, linfo);
+  GST_VAAPI_DISPLAY_UNLOCK (filter->display);
+
+  return status;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapifilter.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapifilter.h
new file mode 100644 (file)
index 0000000..e236b7d
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ *  gstvaapifilter.h - Video processing abstraction
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_FILTER_H
+#define GST_VAAPI_FILTER_H
+
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/video-format.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_FILTER \
+    (gst_vaapi_filter_get_type ())
+#define GST_VAAPI_FILTER(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_FILTER, GstVaapiFilter))
+#define GST_VAAPI_IS_FILTER(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_FILTER))
+
+typedef struct _GstVaapiFilter                  GstVaapiFilter;
+typedef struct _GstVaapiFilterOpInfo            GstVaapiFilterOpInfo;
+
+/**
+ * @GST_VAAPI_FILTER_OP_FORMAT: Force output pixel format (#GstVideoFormat).
+ * @GST_VAAPI_FILTER_OP_CROP: Crop source surface (#GstVaapiRectangle).
+ * @GST_VAAPI_FILTER_OP_DENOISE: Noise reduction (float).
+ * @GST_VAAPI_FILTER_OP_SHARPEN: Sharpening (float).
+ * @GST_VAAPI_FILTER_OP_HUE: Change color hue (float).
+ * @GST_VAAPI_FILTER_OP_SATURATION: Change saturation (float).
+ * @GST_VAAPI_FILTER_OP_BRIGHTNESS: Change brightness (float).
+ * @GST_VAAPI_FILTER_OP_CONTRAST: Change contrast (float).
+ * @GST_VAAPI_FILTER_OP_SCALING: Change scaling method (#GstVaapiScaleMethod).
+ * @GST_VAAPI_FILTER_OP_VIDEO_DIRECTION: Change video direction
+ *   (#GstVideoOrientationMethod).
+ * @GST_VAAPI_FILTER_OP_HDR_TONE_MAP: HDR tone mapping (bool).
+ * @GST_VAAPI_FILTER_OP_SKINTONE: Skin tone enhancement (bool).
+ * @GST_VAAPI_FILTER_OP_SKINTONE_LEVEL: Skin tone enhancement (uint).
+ *
+ * The set of operations that could be applied to the filter.
+ */
+typedef enum {
+  GST_VAAPI_FILTER_OP_FORMAT = 1,
+  GST_VAAPI_FILTER_OP_CROP,
+  GST_VAAPI_FILTER_OP_DENOISE,
+  GST_VAAPI_FILTER_OP_SHARPEN,
+  GST_VAAPI_FILTER_OP_HUE,
+  GST_VAAPI_FILTER_OP_SATURATION,
+  GST_VAAPI_FILTER_OP_BRIGHTNESS,
+  GST_VAAPI_FILTER_OP_CONTRAST,
+  GST_VAAPI_FILTER_OP_DEINTERLACING,
+  GST_VAAPI_FILTER_OP_SCALING,
+  GST_VAAPI_FILTER_OP_VIDEO_DIRECTION,
+  GST_VAAPI_FILTER_OP_HDR_TONE_MAP,
+#ifndef GST_REMOVE_DEPRECATED
+  GST_VAAPI_FILTER_OP_SKINTONE,
+#endif
+  GST_VAAPI_FILTER_OP_SKINTONE_LEVEL,
+} GstVaapiFilterOp;
+
+/**
+ * GstVaapiFilterOpInfo:
+ * @operation: the #GstVaapiFilterOp
+ * @pspec: the #GParamSpec describing the associated configurable value
+ *
+ * A #GstVaapiFilterOp descriptor.
+ */
+struct _GstVaapiFilterOpInfo
+{
+  const GstVaapiFilterOp op;
+  GParamSpec *const pspec;
+};
+
+/**
+ * GstVaapiFilterStatus:
+ * @GST_VAAPI_FILTER_STATUS_SUCCESS: Success.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED: No memory left.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED: Operation failed.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER: Invalid parameter.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_OPERATION: Unsupported operation.
+ * @GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_FORMAT: Unsupported target format.
+ *
+ * Video processing status for gst_vaapi_filter_process().
+ */
+typedef enum {
+  GST_VAAPI_FILTER_STATUS_SUCCESS = 0,
+  GST_VAAPI_FILTER_STATUS_ERROR_ALLOCATION_FAILED,
+  GST_VAAPI_FILTER_STATUS_ERROR_OPERATION_FAILED,
+  GST_VAAPI_FILTER_STATUS_ERROR_INVALID_PARAMETER,
+  GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_OPERATION,
+  GST_VAAPI_FILTER_STATUS_ERROR_UNSUPPORTED_FORMAT,
+} GstVaapiFilterStatus;
+
+/**
+ * GstVaapiScaleMethod:
+ * @GST_VAAPI_SCALE_METHOD_DEFAULT: Default scaling mode.
+ * @GST_VAAPI_SCALE_METHOD_FAST: Fast scaling mode, at the expense of quality.
+ * @GST_VAAPI_SCALE_METHOD_HQ: High quality scaling mode, at the
+ *   expense of speed.
+ *
+ * Scaling algorithms.
+ */
+typedef enum {
+  GST_VAAPI_SCALE_METHOD_DEFAULT,
+  GST_VAAPI_SCALE_METHOD_FAST,
+  GST_VAAPI_SCALE_METHOD_HQ,
+} GstVaapiScaleMethod;
+
+/**
+ * GstVaapiDeinterlaceMethod:
+ * @GST_VAAPI_DEINTERLACE_METHOD_NONE: No deinterlacing.
+ * @GST_VAAPI_DEINTERLACE_METHOD_BOB: Basic bob deinterlacing algorithm.
+ * @GST_VAAPI_DEINTERLACE_METHOD_WEAVE: Weave deinterlacing algorithm.
+ * @GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE: Motion adaptive
+ *   deinterlacing algorithm.
+ * @GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED: Motion compensated
+ *   deinterlacing algorithm.
+ *
+ * Deinterlacing algorithms.
+ */
+typedef enum {
+  GST_VAAPI_DEINTERLACE_METHOD_NONE,
+  GST_VAAPI_DEINTERLACE_METHOD_BOB,
+  GST_VAAPI_DEINTERLACE_METHOD_WEAVE,
+  GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE,
+  GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED,
+} GstVaapiDeinterlaceMethod;
+
+/**
+ * GstVaapiDeinterlaceFlags:
+ * @GST_VAAPI_DEINTERLACE_FLAG_TFF: Top-field first. If this flag is
+ *   not set, then bottom-field first order is assumed. Note: this
+ *   only affects the way reference frames are organized for advanced
+ *   deinterlacing modes.
+ * @GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD: The input frame represents a
+ *   single field. If this flag is not set, then the whole frame holds
+ *   two interleaved fields.
+ * @GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD: The top field of the input
+ *   frame is to be used for deinterlacing. Otherwise, if this flag is
+ *   not set, then the bottom field of the input frame will be used
+ *   for deinterlacing.
+ *
+ * The set of gst_vaapi_filter_set_deinterlacing() flags.
+ */
+typedef enum {
+  GST_VAAPI_DEINTERLACE_FLAG_TFF = 1 << 31,
+  GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD = 1 << 30,
+  GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD = 1 << 29,
+} GstVaapiDeinterlaceFlags;
+
+#define GST_VAAPI_TYPE_SCALE_METHOD \
+    gst_vaapi_scale_method_get_type()
+
+#define GST_VAAPI_TYPE_DEINTERLACE_METHOD \
+    gst_vaapi_deinterlace_method_get_type()
+
+#define GST_VAAPI_TYPE_DEINTERLACE_FLAGS \
+    gst_vaapi_deinterlace_flags_get_type()
+
+GType
+gst_vaapiscale_method_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapi_deinterlace_method_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapi_deinterlace_flags_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapi_filter_get_type (void) G_GNUC_CONST;
+
+GstVaapiFilter *
+gst_vaapi_filter_new (GstVaapiDisplay * display);
+
+void
+gst_vaapi_filter_replace (GstVaapiFilter ** old_filter_ptr,
+    GstVaapiFilter * new_filter);
+
+GPtrArray *
+gst_vaapi_filter_get_operations (GstVaapiFilter * filter);
+
+gboolean
+gst_vaapi_filter_has_operation (GstVaapiFilter * filter, GstVaapiFilterOp op);
+
+gboolean
+gst_vaapi_filter_use_operation (GstVaapiFilter * filter, GstVaapiFilterOp op);
+
+gboolean
+gst_vaapi_filter_set_operation (GstVaapiFilter * filter, GstVaapiFilterOp op,
+    const GValue * value);
+
+GstVaapiFilterStatus
+gst_vaapi_filter_process (GstVaapiFilter * filter,
+    GstVaapiSurface * src_surface, GstVaapiSurface * dst_surface, guint flags);
+
+GArray *
+gst_vaapi_filter_get_formats (GstVaapiFilter * filter, gint * min_width,
+    gint * min_height, gint * max_width, gint * max_height);
+
+gboolean
+gst_vaapi_filter_set_format (GstVaapiFilter * filter, GstVideoFormat format);
+
+gboolean
+gst_vaapi_filter_append_caps (GstVaapiFilter * filter, GstStructure * structure);
+
+guint
+gst_vaapi_filter_get_memory_types (GstVaapiFilter * filter);
+
+gboolean
+gst_vaapi_filter_set_cropping_rectangle (GstVaapiFilter * filter,
+    const GstVaapiRectangle * rect);
+
+gboolean
+gst_vaapi_filter_set_target_rectangle (GstVaapiFilter * filter,
+    const GstVaapiRectangle * rect);
+
+gboolean
+gst_vaapi_filter_set_denoising_level (GstVaapiFilter * filter, gfloat level);
+
+gboolean
+gst_vaapi_filter_set_sharpening_level (GstVaapiFilter * filter, gfloat level);
+
+gboolean
+gst_vaapi_filter_set_hue (GstVaapiFilter * filter, gfloat value);
+
+gboolean
+gst_vaapi_filter_set_saturation (GstVaapiFilter * filter, gfloat value);
+
+gboolean
+gst_vaapi_filter_set_brightness (GstVaapiFilter * filter, gfloat value);
+
+gboolean
+gst_vaapi_filter_set_contrast (GstVaapiFilter * filter, gfloat value);
+
+gboolean
+gst_vaapi_filter_set_deinterlacing (GstVaapiFilter * filter,
+    GstVaapiDeinterlaceMethod method, guint flags);
+
+gboolean
+gst_vaapi_filter_set_deinterlacing_references (GstVaapiFilter * filter,
+    GstVaapiSurface ** forward_references, guint num_forward_references,
+    GstVaapiSurface ** backward_references, guint num_backward_references);
+
+gboolean
+gst_vaapi_filter_set_scaling (GstVaapiFilter * filter,
+    GstVaapiScaleMethod method);
+
+gboolean
+gst_vaapi_filter_set_video_direction (GstVaapiFilter * filter,
+    GstVideoOrientationMethod method);
+
+GstVideoOrientationMethod
+gst_vaapi_filter_get_video_direction (GstVaapiFilter * filter);
+
+gboolean
+gst_vaapi_filter_set_hdr_tone_map (GstVaapiFilter * filter, gboolean value);
+
+gboolean
+gst_vaapi_filter_set_hdr_tone_map_meta (GstVaapiFilter * filter,
+    GstVideoMasteringDisplayInfo * minfo, GstVideoContentLightLevel * linfo);
+
+#ifndef GST_REMOVE_DEPRECATED
+gboolean
+gst_vaapi_filter_set_skintone (GstVaapiFilter * filter,
+    gboolean enhance);
+#endif
+
+gboolean
+gst_vaapi_filter_set_skintone_level (GstVaapiFilter * filter, guint value);
+
+gfloat
+gst_vaapi_filter_get_denoising_level_default (GstVaapiFilter * filter);
+
+gfloat
+gst_vaapi_filter_get_sharpening_level_default (GstVaapiFilter * filter);
+
+gfloat
+gst_vaapi_filter_get_hue_default (GstVaapiFilter * filter);
+
+gfloat
+gst_vaapi_filter_get_saturation_default (GstVaapiFilter * filter);
+
+gfloat
+gst_vaapi_filter_get_brightness_default (GstVaapiFilter * filter);
+
+gfloat
+gst_vaapi_filter_get_contrast_default (GstVaapiFilter * filter);
+
+GstVaapiScaleMethod
+gst_vaapi_filter_get_scaling_default (GstVaapiFilter * filter);
+
+GstVideoOrientationMethod
+gst_vaapi_filter_get_video_direction_default (GstVaapiFilter * filter);
+
+#ifndef GST_REMOVE_DEPRECATED
+gboolean
+gst_vaapi_filter_get_skintone_default (GstVaapiFilter * filter);
+#endif
+
+guint
+gst_vaapi_filter_get_skintone_level_default (GstVaapiFilter * filter);
+
+gboolean
+gst_vaapi_filter_set_colorimetry (GstVaapiFilter * filter,
+    GstVideoColorimetry * input, GstVideoColorimetry * output);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiFilter, gst_object_unref)
+
+#endif /* GST_VAAPI_FILTER_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimage.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimage.c
new file mode 100644 (file)
index 0000000..18389ad
--- /dev/null
@@ -0,0 +1,1072 @@
+/*
+ *  gstvaapiimage.c - VA image abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiimage
+ * @short_description: VA image abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiimage.h"
+#include "gstvaapiimage_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define SWAP_UINT(a, b) do { \
+        guint v = a;         \
+        a = b;               \
+        b = v;               \
+    } while (0)
+
+static gboolean
+_gst_vaapi_image_map (GstVaapiImage * image, GstVaapiImageRaw * raw_image);
+
+static gboolean _gst_vaapi_image_unmap (GstVaapiImage * image);
+
+static gboolean
+_gst_vaapi_image_set_image (GstVaapiImage * image, const VAImage * va_image);
+
+/*
+ * VAImage wrapper
+ */
+
+static gboolean
+vaapi_image_is_linear (const VAImage * va_image)
+{
+  guint i, width, height, width2, height2, data_size;
+
+  for (i = 1; i < va_image->num_planes; i++)
+    if (va_image->offsets[i] < va_image->offsets[i - 1])
+      return FALSE;
+
+  width = va_image->width;
+  height = va_image->height;
+  width2 = (width + 1) / 2;
+  height2 = (height + 1) / 2;
+
+  switch (va_image->format.fourcc) {
+    case VA_FOURCC ('N', 'V', '1', '2'):
+    case VA_FOURCC ('Y', 'V', '1', '2'):
+    case VA_FOURCC ('I', '4', '2', '0'):
+      data_size = width * height + 2 * width2 * height2;
+      break;
+    case VA_FOURCC ('Y', 'U', 'Y', '2'):
+    case VA_FOURCC ('U', 'Y', 'V', 'Y'):
+    case VA_FOURCC ('R', 'G', '1', '6'):
+      data_size = 2 * width * height;
+      break;
+    case VA_FOURCC ('Y', '8', '0', '0'):
+      data_size = width * height;
+      break;
+    case VA_FOURCC ('A', 'Y', 'U', 'V'):
+    case VA_FOURCC ('A', 'R', 'G', 'B'):
+    case VA_FOURCC ('R', 'G', 'B', 'A'):
+    case VA_FOURCC ('A', 'B', 'G', 'R'):
+    case VA_FOURCC ('B', 'G', 'R', 'A'):
+    case VA_FOURCC ('X', 'R', 'G', 'B'):
+    case VA_FOURCC ('R', 'G', 'B', 'X'):
+    case VA_FOURCC ('X', 'B', 'G', 'R'):
+    case VA_FOURCC ('B', 'G', 'R', 'X'):
+    case VA_FOURCC ('Y', '2', '1', '0'):
+    case VA_FOURCC ('Y', '4', '1', '0'):
+    case VA_FOURCC ('A', 'R', '3', '0'):
+    case VA_FOURCC ('Y', '2', '1', '2'):
+      data_size = 4 * width * height;
+      break;
+    case VA_FOURCC ('P', '0', '1', '0'):
+    case VA_FOURCC ('P', '0', '1', '2'):
+      data_size = 2 * (width * height + 2 * width2 * height2);
+      break;
+    case VA_FOURCC ('R', 'G', '2', '4'):
+    case VA_FOURCC ('4', '4', '4', 'P'):
+      data_size = 3 * width * height;
+      break;
+    case VA_FOURCC ('Y', '4', '1', '2'):
+      data_size = 8 * width * height;
+      break;
+    default:
+      GST_ERROR ("FIXME: incomplete formats %" GST_FOURCC_FORMAT,
+          GST_FOURCC_ARGS (va_image->format.fourcc));
+      data_size = G_MAXUINT;
+      break;
+  }
+  return va_image->data_size == data_size;
+}
+
+static void
+gst_vaapi_image_free (GstVaapiImage * image)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_IMAGE_DISPLAY (image);
+  VAImageID image_id;
+  VAStatus status;
+
+  _gst_vaapi_image_unmap (image);
+
+  image_id = GST_VAAPI_IMAGE_ID (image);
+  GST_DEBUG ("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (image_id));
+
+  if (image_id != VA_INVALID_ID) {
+    GST_VAAPI_DISPLAY_LOCK (display);
+    status = vaDestroyImage (GST_VAAPI_DISPLAY_VADISPLAY (display), image_id);
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+    if (!vaapi_check_status (status, "vaDestroyImage()"))
+      GST_WARNING ("failed to destroy image %" GST_VAAPI_ID_FORMAT,
+          GST_VAAPI_ID_ARGS (image_id));
+    GST_VAAPI_IMAGE_ID (image) = VA_INVALID_ID;
+  }
+
+  gst_vaapi_display_replace (&GST_VAAPI_IMAGE_DISPLAY (image), NULL);
+
+  g_slice_free1 (sizeof (GstVaapiImage), image);
+}
+
+static gboolean
+_gst_vaapi_image_create (GstVaapiImage * image, GstVideoFormat format)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_IMAGE_DISPLAY (image);
+  const VAImageFormat *va_format;
+  VAStatus status;
+
+  if (!gst_vaapi_display_has_image_format (display, format))
+    return FALSE;
+
+  va_format = gst_vaapi_video_format_to_va_format (format);
+  if (!va_format)
+    return FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaCreateImage (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      (VAImageFormat *) va_format,
+      image->width, image->height, &image->internal_image);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (status != VA_STATUS_SUCCESS ||
+      image->internal_image.format.fourcc != va_format->fourcc)
+    return FALSE;
+
+  image->internal_format = format;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_image_create (GstVaapiImage * image, GstVideoFormat format,
+    guint width, guint height)
+{
+  const VAImageFormat *va_format;
+  VAImageID image_id;
+
+  image->format = format;
+  image->width = width;
+  image->height = height;
+
+  if (!_gst_vaapi_image_create (image, format)) {
+    switch (format) {
+      case GST_VIDEO_FORMAT_I420:
+        format = GST_VIDEO_FORMAT_YV12;
+        break;
+      case GST_VIDEO_FORMAT_YV12:
+        format = GST_VIDEO_FORMAT_I420;
+        break;
+      default:
+        format = 0;
+        break;
+    }
+    if (!format || !_gst_vaapi_image_create (image, format))
+      return FALSE;
+  }
+  image->image = image->internal_image;
+  image_id = image->image.image_id;
+
+  if (image->format != image->internal_format) {
+    switch (image->format) {
+      case GST_VIDEO_FORMAT_YV12:
+      case GST_VIDEO_FORMAT_I420:
+        va_format = gst_vaapi_video_format_to_va_format (image->format);
+        if (!va_format)
+          return FALSE;
+        image->image.format = *va_format;
+        SWAP_UINT (image->image.offsets[1], image->image.offsets[2]);
+        SWAP_UINT (image->image.pitches[1], image->image.pitches[2]);
+        break;
+      default:
+        break;
+    }
+  }
+  image->is_linear = vaapi_image_is_linear (&image->image);
+
+  GST_DEBUG ("image %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (image_id));
+  GST_VAAPI_IMAGE_ID (image) = image_id;
+  return TRUE;
+}
+
+static void
+gst_vaapi_image_init (GstVaapiImage * image, GstVaapiDisplay * display)
+{
+  /* TODO(victor): implement image copy mechanism, it's almost
+   * there */
+  gst_mini_object_init (GST_MINI_OBJECT_CAST (image), 0,
+      GST_TYPE_VAAPI_IMAGE, NULL, NULL,
+      (GstMiniObjectFreeFunction) gst_vaapi_image_free);
+
+  GST_VAAPI_IMAGE_DISPLAY (image) = gst_object_ref (display);
+  GST_VAAPI_IMAGE_ID (image) = VA_INVALID_ID;
+  image->internal_image.image_id = VA_INVALID_ID;
+  image->internal_image.buf = VA_INVALID_ID;
+  image->image.image_id = VA_INVALID_ID;
+  image->image.buf = VA_INVALID_ID;
+  image->image_data = NULL;
+  image->internal_format = image->format = GST_VIDEO_FORMAT_UNKNOWN;
+  image->width = image->height = 0;
+  image->is_linear = FALSE;
+}
+
+GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiImage, gst_vaapi_image);
+
+/**
+ * gst_vaapi_image_get_display:
+ * @image: a #GstVaapiImage
+ *
+ * Returns the #GstVaapiDisplay this @image is bound to.
+ *
+ * Return value: the parent #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_image_get_display (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, NULL);
+  return GST_VAAPI_IMAGE_DISPLAY (image);
+}
+
+/**
+ * gst_vaapi_image_new:
+ * @display: a #GstVaapiDisplay
+ * @format: a #GstVideoFormat
+ * @width: the requested image width
+ * @height: the requested image height
+ *
+ * Creates a new #GstVaapiImage with the specified format and
+ * dimensions.
+ *
+ * Return value: the newly allocated #GstVaapiImage object
+ */
+GstVaapiImage *
+gst_vaapi_image_new (GstVaapiDisplay * display,
+    GstVideoFormat format, guint width, guint height)
+{
+  GstVaapiImage *image;
+
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+
+  GST_DEBUG ("format %s, size %ux%u", gst_vaapi_video_format_to_string (format),
+      width, height);
+
+  image = g_slice_new (GstVaapiImage);
+  if (!image)
+    return NULL;
+
+  gst_vaapi_image_init (image, display);
+
+  if (!gst_vaapi_image_create (image, format, width, height))
+    goto error;
+  return image;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_image_unref (image);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_image_new_with_image:
+ * @display: a #GstVaapiDisplay
+ * @va_image: a VA image
+ *
+ * Creates a new #GstVaapiImage from a foreign VA image. The image
+ * format and dimensions will be extracted from @va_image. This
+ * function is mainly used by gst_vaapi_surface_derive_image() to bind
+ * a VA image to a #GstVaapiImage object.
+ *
+ * Return value: the newly allocated #GstVaapiImage object
+ */
+GstVaapiImage *
+gst_vaapi_image_new_with_image (GstVaapiDisplay * display, VAImage * va_image)
+{
+  GstVaapiImage *image;
+
+  g_return_val_if_fail (va_image, NULL);
+  g_return_val_if_fail (va_image->image_id != VA_INVALID_ID, NULL);
+  g_return_val_if_fail (va_image->buf != VA_INVALID_ID, NULL);
+
+  GST_DEBUG ("VA image 0x%08x, format %" GST_FOURCC_FORMAT ", size %ux%u",
+      va_image->image_id,
+      GST_FOURCC_ARGS (va_image->format.fourcc),
+      va_image->width, va_image->height);
+
+  image = g_slice_new (GstVaapiImage);
+  if (!image)
+    return NULL;
+
+  gst_vaapi_image_init (image, display);
+
+  if (!_gst_vaapi_image_set_image (image, va_image))
+    goto error;
+  return image;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_image_unref (image);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_image_get_id:
+ * @image: a #GstVaapiImage
+ *
+ * Returns the underlying VAImageID of the @image.
+ *
+ * Return value: the underlying VA image id
+ */
+GstVaapiID
+gst_vaapi_image_get_id (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, VA_INVALID_ID);
+
+  return GST_VAAPI_IMAGE_ID (image);
+}
+
+/**
+ * gst_vaapi_image_get_image:
+ * @image: a #GstVaapiImage
+ * @va_image: a VA image
+ *
+ * Fills @va_image with the VA image used internally.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_image_get_image (GstVaapiImage * image, VAImage * va_image)
+{
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  if (va_image)
+    *va_image = image->image;
+
+  return TRUE;
+}
+
+/*
+ * _gst_vaapi_image_set_image:
+ * @image: a #GstVaapiImage
+ * @va_image: a VA image
+ *
+ * Initializes #GstVaapiImage with a foreign VA image. This function
+ * will try to "linearize" the VA image. i.e. making sure that the VA
+ * image offsets into the data buffer are in increasing order with the
+ * number of planes available in the image.
+ *
+ * This is an internal function used by gst_vaapi_image_new_with_image().
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+_gst_vaapi_image_set_image (GstVaapiImage * image, const VAImage * va_image)
+{
+  GstVideoFormat format;
+  VAImage alt_va_image;
+  const VAImageFormat *alt_va_format;
+
+  format = gst_vaapi_video_format_from_va_format (&va_image->format);
+  if (format == GST_VIDEO_FORMAT_UNKNOWN)
+    return FALSE;
+
+  image->internal_image = *va_image;
+  image->internal_format = format;
+  image->is_linear = vaapi_image_is_linear (va_image);
+  image->image = *va_image;
+  image->format = format;
+  image->width = va_image->width;
+  image->height = va_image->height;
+
+  GST_VAAPI_IMAGE_ID (image) = va_image->image_id;
+
+  /* Try to linearize image */
+  if (!image->is_linear) {
+    switch (format) {
+      case GST_VIDEO_FORMAT_I420:
+        format = GST_VIDEO_FORMAT_YV12;
+        break;
+      case GST_VIDEO_FORMAT_YV12:
+        format = GST_VIDEO_FORMAT_I420;
+        break;
+      default:
+        format = 0;
+        break;
+    }
+    if (format &&
+        (alt_va_format = gst_vaapi_video_format_to_va_format (format))) {
+      alt_va_image = *va_image;
+      alt_va_image.format = *alt_va_format;
+      SWAP_UINT (alt_va_image.offsets[1], alt_va_image.offsets[2]);
+      SWAP_UINT (alt_va_image.pitches[1], alt_va_image.pitches[2]);
+      if (vaapi_image_is_linear (&alt_va_image)) {
+        image->image = alt_va_image;
+        image->format = format;
+        image->is_linear = TRUE;
+        GST_DEBUG ("linearized image to %s format",
+            gst_vaapi_video_format_to_string (format));
+      }
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_image_get_format:
+ * @image: a #GstVaapiImage
+ *
+ * Returns the #GstVideoFormat the @image was created with.
+ *
+ * Return value: the #GstVideoFormat
+ */
+GstVideoFormat
+gst_vaapi_image_get_format (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, 0);
+
+  return image->format;
+}
+
+/**
+ * gst_vaapi_image_get_width:
+ * @image: a #GstVaapiImage
+ *
+ * Returns the @image width.
+ *
+ * Return value: the image width, in pixels
+ */
+guint
+gst_vaapi_image_get_width (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, 0);
+
+  return image->width;
+}
+
+/**
+ * gst_vaapi_image_get_height:
+ * @image: a #GstVaapiImage
+ *
+ * Returns the @image height.
+ *
+ * Return value: the image height, in pixels.
+ */
+guint
+gst_vaapi_image_get_height (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, 0);
+
+  return image->height;
+}
+
+/**
+ * gst_vaapi_image_get_size:
+ * @image: a #GstVaapiImage
+ * @pwidth: return location for the width, or %NULL
+ * @pheight: return location for the height, or %NULL
+ *
+ * Retrieves the dimensions of a #GstVaapiImage.
+ */
+void
+gst_vaapi_image_get_size (GstVaapiImage * image, guint * pwidth,
+    guint * pheight)
+{
+  g_return_if_fail (image != NULL);
+
+  if (pwidth)
+    *pwidth = image->width;
+
+  if (pheight)
+    *pheight = image->height;
+}
+
+/**
+ * gst_vaapi_image_is_linear:
+ * @image: a #GstVaapiImage
+ *
+ * Checks whether the @image has data planes allocated from a single
+ * buffer and offsets into that buffer are in increasing order with
+ * the number of planes.
+ *
+ * Return value: %TRUE if image data planes are allocated from a single buffer
+ */
+gboolean
+gst_vaapi_image_is_linear (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  return image->is_linear;
+}
+
+/**
+ * gst_vaapi_image_is_mapped:
+ * @image: a #GstVaapiImage
+ *
+ * Checks whether the @image is currently mapped or not.
+ *
+ * Return value: %TRUE if the @image is mapped
+ */
+static inline gboolean
+_gst_vaapi_image_is_mapped (GstVaapiImage * image)
+{
+  return image->image_data != NULL;
+}
+
+gboolean
+gst_vaapi_image_is_mapped (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  return _gst_vaapi_image_is_mapped (image);
+}
+
+/**
+ * gst_vaapi_image_map:
+ * @image: a #GstVaapiImage
+ *
+ * Maps the image data buffer. The actual pixels are returned by the
+ * gst_vaapi_image_get_plane() function.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_image_map (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  return _gst_vaapi_image_map (image, NULL);
+}
+
+gboolean
+_gst_vaapi_image_map (GstVaapiImage * image, GstVaapiImageRaw * raw_image)
+{
+  GstVaapiDisplay *display;
+  VAStatus status;
+  guint i;
+
+  if (_gst_vaapi_image_is_mapped (image))
+    goto map_success;
+
+  display = GST_VAAPI_IMAGE_DISPLAY (image);
+  if (!display)
+    return FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaMapBuffer (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      image->image.buf, (void **) &image->image_data);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaMapBuffer()"))
+    return FALSE;
+
+map_success:
+  if (raw_image) {
+    const VAImage *const va_image = &image->image;
+    raw_image->format = image->format;
+    raw_image->width = va_image->width;
+    raw_image->height = va_image->height;
+    raw_image->num_planes = va_image->num_planes;
+    for (i = 0; i < raw_image->num_planes; i++) {
+      raw_image->pixels[i] = (guchar *) image->image_data +
+          va_image->offsets[i];
+      raw_image->stride[i] = va_image->pitches[i];
+    }
+  }
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_image_unmap:
+ * @image: a #GstVaapiImage
+ *
+ * Unmaps the image data buffer. Pointers to pixels returned by
+ * gst_vaapi_image_get_plane() are then no longer valid.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_image_unmap (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  return _gst_vaapi_image_unmap (image);
+}
+
+gboolean
+_gst_vaapi_image_unmap (GstVaapiImage * image)
+{
+  GstVaapiDisplay *display;
+  VAStatus status;
+
+  if (!_gst_vaapi_image_is_mapped (image))
+    return TRUE;
+
+  display = GST_VAAPI_IMAGE_DISPLAY (image);
+  if (!display)
+    return FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaUnmapBuffer (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      image->image.buf);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaUnmapBuffer()"))
+    return FALSE;
+
+  image->image_data = NULL;
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_image_get_plane_count:
+ * @image: a #GstVaapiImage
+ *
+ * Retrieves the number of planes available in the @image. The @image
+ * must be mapped for this function to work properly.
+ *
+ * Return value: the number of planes available in the @image
+ */
+guint
+gst_vaapi_image_get_plane_count (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, 0);
+  g_return_val_if_fail (_gst_vaapi_image_is_mapped (image), 0);
+
+  return image->image.num_planes;
+}
+
+/**
+ * gst_vaapi_image_get_plane:
+ * @image: a #GstVaapiImage
+ * @plane: the requested plane number
+ *
+ * Retrieves the pixels data to the specified @plane. The @image must
+ * be mapped for this function to work properly.
+ *
+ * Return value: the pixels data of the specified @plane
+ */
+guchar *
+gst_vaapi_image_get_plane (GstVaapiImage * image, guint plane)
+{
+  g_return_val_if_fail (image != NULL, NULL);
+  g_return_val_if_fail (_gst_vaapi_image_is_mapped (image), NULL);
+  g_return_val_if_fail (plane < image->image.num_planes, NULL);
+
+  return image->image_data + image->image.offsets[plane];
+}
+
+/**
+ * gst_vaapi_image_get_pitch:
+ * @image: a #GstVaapiImage
+ * @plane: the requested plane number
+ *
+ * Retrieves the line size (stride) of the specified @plane. The
+ * @image must be mapped for this function to work properly.
+ *
+ * Return value: the line size (stride) of the specified plane
+ */
+guint
+gst_vaapi_image_get_pitch (GstVaapiImage * image, guint plane)
+{
+  g_return_val_if_fail (image != NULL, 0);
+  g_return_val_if_fail (_gst_vaapi_image_is_mapped (image), 0);
+  g_return_val_if_fail (plane < image->image.num_planes, 0);
+
+  return image->image.pitches[plane];
+}
+
+/**
+ * gst_vaapi_image_get_data_size:
+ * @image: a #GstVaapiImage
+ *
+ * Retrieves the underlying image data size. This function could be
+ * used to determine whether the image has a compatible layout with
+ * another image structure.
+ *
+ * Return value: the whole image data size of the @image
+ */
+guint
+gst_vaapi_image_get_data_size (GstVaapiImage * image)
+{
+  g_return_val_if_fail (image != NULL, 0);
+
+  return image->image.data_size;
+}
+
+#include <gst/video/gstvideometa.h>
+
+static gboolean
+init_image_from_video_meta (GstVaapiImageRaw * raw_image, GstVideoMeta * vmeta)
+{
+  GST_FIXME ("map from GstVideoMeta + add fini_image_from_buffer()");
+  return FALSE;
+}
+
+static gboolean
+init_image_from_buffer (GstVaapiImageRaw * raw_image, GstBuffer * buffer)
+{
+  GstVideoMeta *const vmeta = gst_buffer_get_video_meta (buffer);
+
+  return vmeta ? init_image_from_video_meta (raw_image, vmeta) : FALSE;
+}
+
+/* Copy N lines of an image */
+static inline void
+memcpy_pic (guchar * dst,
+    guint dst_stride,
+    const guchar * src, guint src_stride, guint len, guint height)
+{
+  guint i;
+
+  for (i = 0; i < height; i++) {
+    memcpy (dst, src, len);
+    dst += dst_stride;
+    src += src_stride;
+  }
+}
+
+/* Copy NV12 images */
+static void
+copy_image_NV12 (GstVaapiImageRaw * dst_image,
+    GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect)
+{
+  guchar *dst, *src;
+  guint dst_stride, src_stride;
+
+  /* Y plane */
+  dst_stride = dst_image->stride[0];
+  dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
+  src_stride = src_image->stride[0];
+  src = src_image->pixels[0] + rect->y * src_stride + rect->x;
+  memcpy_pic (dst, dst_stride, src, src_stride, rect->width, rect->height);
+
+  /* UV plane */
+  dst_stride = dst_image->stride[1];
+  dst = dst_image->pixels[1] + (rect->y / 2) * dst_stride + (rect->x & -2);
+  src_stride = src_image->stride[1];
+  src = src_image->pixels[1] + (rect->y / 2) * src_stride + (rect->x & -2);
+  memcpy_pic (dst, dst_stride, src, src_stride, rect->width, rect->height / 2);
+}
+
+/* Copy YV12 images */
+static void
+copy_image_YV12 (GstVaapiImageRaw * dst_image,
+    GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect)
+{
+  guchar *dst, *src;
+  guint dst_stride, src_stride;
+  guint i, x, y, w, h;
+
+  /* Y plane */
+  dst_stride = dst_image->stride[0];
+  dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
+  src_stride = src_image->stride[0];
+  src = src_image->pixels[0] + rect->y * src_stride + rect->x;
+  memcpy_pic (dst, dst_stride, src, src_stride, rect->width, rect->height);
+
+  /* U/V planes */
+  x = rect->x / 2;
+  y = rect->y / 2;
+  w = rect->width / 2;
+  h = rect->height / 2;
+  for (i = 1; i < dst_image->num_planes; i++) {
+    dst_stride = dst_image->stride[i];
+    dst = dst_image->pixels[i] + y * dst_stride + x;
+    src_stride = src_image->stride[i];
+    src = src_image->pixels[i] + y * src_stride + x;
+    memcpy_pic (dst, dst_stride, src, src_stride, w, h);
+  }
+}
+
+/* Copy YUY2 images */
+static void
+copy_image_YUY2 (GstVaapiImageRaw * dst_image,
+    GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect)
+{
+  guchar *dst, *src;
+  guint dst_stride, src_stride;
+
+  /* YUV 4:2:2, full vertical resolution */
+  dst_stride = dst_image->stride[0];
+  dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x * 2;
+  src_stride = src_image->stride[0];
+  src = src_image->pixels[0] + rect->y * src_stride + rect->x * 2;
+  memcpy_pic (dst, dst_stride, src, src_stride, rect->width * 2, rect->height);
+}
+
+/* Copy RGBA images */
+static void
+copy_image_RGBA (GstVaapiImageRaw * dst_image,
+    GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect)
+{
+  guchar *dst, *src;
+  guint dst_stride, src_stride;
+
+  dst_stride = dst_image->stride[0];
+  dst = dst_image->pixels[0] + rect->y * dst_stride + rect->x;
+  src_stride = src_image->stride[0];
+  src = src_image->pixels[0] + rect->y * src_stride + rect->x;
+  memcpy_pic (dst, dst_stride, src, src_stride, 4 * rect->width, rect->height);
+}
+
+static gboolean
+copy_image (GstVaapiImageRaw * dst_image,
+    GstVaapiImageRaw * src_image, const GstVaapiRectangle * rect)
+{
+  GstVaapiRectangle default_rect;
+
+  if (dst_image->format != src_image->format ||
+      dst_image->width != src_image->width ||
+      dst_image->height != src_image->height)
+    return FALSE;
+
+  if (rect) {
+    if (rect->x >= src_image->width ||
+        rect->x + rect->width > src_image->width ||
+        rect->y >= src_image->height ||
+        rect->y + rect->height > src_image->height)
+      return FALSE;
+  } else {
+    default_rect.x = 0;
+    default_rect.y = 0;
+    default_rect.width = src_image->width;
+    default_rect.height = src_image->height;
+    rect = &default_rect;
+  }
+
+  switch (dst_image->format) {
+    case GST_VIDEO_FORMAT_NV12:
+      copy_image_NV12 (dst_image, src_image, rect);
+      break;
+    case GST_VIDEO_FORMAT_YV12:
+    case GST_VIDEO_FORMAT_I420:
+      copy_image_YV12 (dst_image, src_image, rect);
+      break;
+    case GST_VIDEO_FORMAT_YUY2:
+    case GST_VIDEO_FORMAT_UYVY:
+      copy_image_YUY2 (dst_image, src_image, rect);
+      break;
+    case GST_VIDEO_FORMAT_ARGB:
+    case GST_VIDEO_FORMAT_RGBA:
+    case GST_VIDEO_FORMAT_ABGR:
+    case GST_VIDEO_FORMAT_BGRA:
+      copy_image_RGBA (dst_image, src_image, rect);
+      break;
+    default:
+      GST_ERROR ("unsupported image format for copy");
+      return FALSE;
+  }
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_image_get_buffer:
+ * @image: a #GstVaapiImage
+ * @buffer: a #GstBuffer
+ * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
+ *   whole image
+ *
+ * Transfers pixels data contained in the @image into the #GstBuffer.
+ * Both image structures shall have the same format.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_image_get_buffer (GstVaapiImage * image,
+    GstBuffer * buffer, GstVaapiRectangle * rect)
+{
+  GstVaapiImageRaw dst_image, src_image;
+  gboolean success;
+
+  g_return_val_if_fail (image != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+
+  if (!init_image_from_buffer (&dst_image, buffer))
+    return FALSE;
+  if (dst_image.format != image->format)
+    return FALSE;
+  if (dst_image.width != image->width || dst_image.height != image->height)
+    return FALSE;
+
+  if (!_gst_vaapi_image_map (image, &src_image))
+    return FALSE;
+
+  success = copy_image (&dst_image, &src_image, rect);
+
+  if (!_gst_vaapi_image_unmap (image))
+    return FALSE;
+
+  return success;
+}
+
+/**
+ * gst_vaapi_image_get_raw:
+ * @image: a #GstVaapiImage
+ * @dst_image: a #GstVaapiImageRaw
+ * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
+ *   whole image
+ *
+ * Transfers pixels data contained in the @image into the #GstVaapiImageRaw.
+ * Both image structures shall have the same format.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_image_get_raw (GstVaapiImage * image,
+    GstVaapiImageRaw * dst_image, GstVaapiRectangle * rect)
+{
+  GstVaapiImageRaw src_image;
+  gboolean success;
+
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  if (!_gst_vaapi_image_map (image, &src_image))
+    return FALSE;
+
+  success = copy_image (dst_image, &src_image, rect);
+
+  if (!_gst_vaapi_image_unmap (image))
+    return FALSE;
+
+  return success;
+}
+
+/**
+ * gst_vaapi_image_update_from_buffer:
+ * @image: a #GstVaapiImage
+ * @buffer: a #GstBuffer
+ * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
+ *   whole image
+ *
+ * Transfers pixels data contained in the #GstBuffer into the
+ * @image. Both image structures shall have the same format.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_image_update_from_buffer (GstVaapiImage * image,
+    GstBuffer * buffer, GstVaapiRectangle * rect)
+{
+  GstVaapiImageRaw dst_image, src_image;
+  gboolean success;
+
+  g_return_val_if_fail (image != NULL, FALSE);
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), FALSE);
+
+  if (!init_image_from_buffer (&src_image, buffer))
+    return FALSE;
+  if (src_image.format != image->format)
+    return FALSE;
+  if (src_image.width != image->width || src_image.height != image->height)
+    return FALSE;
+
+  if (!_gst_vaapi_image_map (image, &dst_image))
+    return FALSE;
+
+  success = copy_image (&dst_image, &src_image, rect);
+
+  if (!_gst_vaapi_image_unmap (image))
+    return FALSE;
+
+  return success;
+}
+
+/**
+ * gst_vaapi_image_update_from_raw:
+ * @image: a #GstVaapiImage
+ * @src_image: a #GstVaapiImageRaw
+ * @buffer: a #GstBuffer
+ * @rect: a #GstVaapiRectangle expressing a region, or %NULL for the
+ *   whole image
+ *
+ * Transfers pixels data contained in the #GstVaapiImageRaw into the
+ * @image. Both image structures shall have the same format.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_image_update_from_raw (GstVaapiImage * image,
+    GstVaapiImageRaw * src_image, GstVaapiRectangle * rect)
+{
+  GstVaapiImageRaw dst_image;
+  gboolean success;
+
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  if (!_gst_vaapi_image_map (image, &dst_image))
+    return FALSE;
+
+  success = copy_image (&dst_image, src_image, rect);
+
+  if (!_gst_vaapi_image_unmap (image))
+    return FALSE;
+
+  return success;
+}
+
+/**
+ * gst_vaapi_image_copy:
+ * @dst_image: the target #GstVaapiImage
+ * @src_image: the source #GstVaapiImage
+ *
+ * Copies pixels data from @src_image to @dst_image. Both images shall
+ * have the same format and size.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_image_copy (GstVaapiImage * dst_image, GstVaapiImage * src_image)
+{
+  GstVaapiImageRaw dst_image_raw, src_image_raw;
+  gboolean success = FALSE;
+
+  g_return_val_if_fail (dst_image != NULL, FALSE);
+  g_return_val_if_fail (src_image != NULL, FALSE);
+
+  if (!_gst_vaapi_image_map (dst_image, &dst_image_raw))
+    goto end;
+  if (!_gst_vaapi_image_map (src_image, &src_image_raw))
+    goto end;
+
+  success = copy_image (&dst_image_raw, &src_image_raw, NULL);
+
+end:
+  _gst_vaapi_image_unmap (src_image);
+  _gst_vaapi_image_unmap (dst_image);
+  return success;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimage.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimage.h
new file mode 100644 (file)
index 0000000..12ac9f4
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  gstvaapiimage.h - VA image abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_IMAGE_H
+#define GST_VAAPI_IMAGE_H
+
+#include <gst/gstbuffer.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/video-format.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_IMAGE(obj) \
+    ((GstVaapiImage *)(obj))
+
+/**
+ * GST_VAAPI_IMAGE_FORMAT:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the #GstVideoFormat of @image.
+ */
+#define GST_VAAPI_IMAGE_FORMAT(image)   gst_vaapi_image_get_format(image)
+
+/**
+ * GST_VAAPI_IMAGE_WIDTH:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the width of @image.
+ */
+#define GST_VAAPI_IMAGE_WIDTH(image)    gst_vaapi_image_get_width(image)
+
+/**
+ * GST_VAAPI_IMAGE_HEIGHT:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the height of @image.
+ */
+#define GST_VAAPI_IMAGE_HEIGHT(image)   gst_vaapi_image_get_height(image)
+
+/**
+ * GST_VAAPI_IMAGE_DISPLAY:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the display of @image
+ */
+#define GST_VAAPI_IMAGE_DISPLAY(image)  gst_vaapi_image_get_display(image)
+
+/**
+ * GST_VAAPI_IMAGE_ID:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the ID of @image
+ */
+#define GST_VAAPI_IMAGE_ID(image)       gst_vaapi_image_get_id(image)
+
+#define GST_TYPE_VAAPI_IMAGE            (gst_vaapi_image_get_type ())
+
+typedef struct _GstVaapiImage                   GstVaapiImage;
+
+GType
+gst_vaapi_image_get_type (void) G_GNUC_CONST;
+
+GstVaapiDisplay *
+gst_vaapi_image_get_display (GstVaapiImage * image);
+
+GstVaapiImage *
+gst_vaapi_image_new(
+    GstVaapiDisplay    *display,
+    GstVideoFormat      format,
+    guint               width,
+    guint               height
+);
+
+GstVaapiImage *
+gst_vaapi_image_new_with_image(GstVaapiDisplay *display, VAImage *va_image);
+
+/**
+ * gst_vaapi_image_unref: (skip)
+ * @image: (transfer full): a #GstVaapiImage.
+ *
+ * Decreases the refcount of the image. If the refcount reaches 0, the
+ * image will be freed.
+ */
+static inline void
+gst_vaapi_image_unref (GstVaapiImage * image)
+{
+  gst_mini_object_unref (GST_MINI_OBJECT_CAST (image));
+}
+
+GstVaapiID
+gst_vaapi_image_get_id(GstVaapiImage *image);
+
+gboolean
+gst_vaapi_image_get_image(GstVaapiImage *image, VAImage *va_image);
+
+GstVideoFormat
+gst_vaapi_image_get_format(GstVaapiImage *image);
+
+guint
+gst_vaapi_image_get_width(GstVaapiImage *image);
+
+guint
+gst_vaapi_image_get_height(GstVaapiImage *image);
+
+void
+gst_vaapi_image_get_size(GstVaapiImage *image, guint *pwidth, guint *pheight);
+
+gboolean
+gst_vaapi_image_is_linear(GstVaapiImage *image);
+
+gboolean
+gst_vaapi_image_is_mapped(GstVaapiImage *image);
+
+gboolean
+gst_vaapi_image_map(GstVaapiImage *image);
+
+gboolean
+gst_vaapi_image_unmap(GstVaapiImage *image);
+
+guint
+gst_vaapi_image_get_plane_count(GstVaapiImage *image);
+
+guchar *
+gst_vaapi_image_get_plane(GstVaapiImage *image, guint plane);
+
+guint
+gst_vaapi_image_get_pitch(GstVaapiImage *image, guint plane);
+
+guint
+gst_vaapi_image_get_data_size(GstVaapiImage *image);
+
+gboolean
+gst_vaapi_image_get_buffer(
+    GstVaapiImage     *image,
+    GstBuffer         *buffer,
+    GstVaapiRectangle *rect
+);
+
+gboolean
+gst_vaapi_image_update_from_buffer(
+    GstVaapiImage     *image,
+    GstBuffer         *buffer,
+    GstVaapiRectangle *rect
+);
+
+gboolean
+gst_vaapi_image_copy(GstVaapiImage *dst_image, GstVaapiImage *src_image);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiImage, gst_vaapi_image_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_IMAGE_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimage_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimage_priv.h
new file mode 100644 (file)
index 0000000..584de56
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ *  gstvaapiimage_priv.h - VA image abstraction (private definitions)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_IMAGE_PRIV_H
+#define GST_VAAPI_IMAGE_PRIV_H
+
+#include <gst/vaapi/gstvaapiimage.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiImageRaw                GstVaapiImageRaw;
+
+/**
+ * GstVaapiImage:
+ *
+ * A VA image wrapper
+ */
+struct _GstVaapiImage {
+    /*< private >*/
+    GstMiniObject       mini_object;
+    GstVaapiDisplay    *display;
+    GstVaapiID          object_id;
+
+    VAImage             internal_image;
+    VAImage             image;
+    guchar             *image_data;
+    GstVideoFormat      internal_format;
+    GstVideoFormat      format;
+    guint               width;
+    guint               height;
+    guint               is_linear       : 1;
+};
+
+/**
+ * GstVaapiImageRaw:
+ *
+ * A raw image wrapper. The caller is responsible for initializing all
+ * the fields with sensible values.
+ */
+struct _GstVaapiImageRaw {
+    GstVideoFormat      format;
+    guint               width;
+    guint               height;
+    guint               num_planes;
+    guchar             *pixels[3];
+    guint               stride[3];
+};
+
+/**
+ * GST_VAAPI_IMAGE_FORMAT:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the #GstVideoFormat of @image.
+ */
+#undef  GST_VAAPI_IMAGE_FORMAT
+#define GST_VAAPI_IMAGE_FORMAT(image) \
+    (GST_VAAPI_IMAGE(image)->format)
+
+/**
+ * GST_VAAPI_IMAGE_WIDTH:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the width of @image.
+ */
+#undef  GST_VAAPI_IMAGE_WIDTH
+#define GST_VAAPI_IMAGE_WIDTH(image) \
+    (GST_VAAPI_IMAGE(image)->width)
+
+/**
+ * GST_VAAPI_IMAGE_HEIGHT:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the height of @image.
+ */
+#undef  GST_VAAPI_IMAGE_HEIGHT
+#define GST_VAAPI_IMAGE_HEIGHT(image) \
+    (GST_VAAPI_IMAGE(image)->height)
+
+/**
+ * GST_VAAPI_IMAGE_DISPLAY:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the @image's display
+ */
+#undef  GST_VAAPI_IMAGE_DISPLAY
+#define GST_VAAPI_IMAGE_DISPLAY(image) \
+    (GST_VAAPI_IMAGE(image)->display)
+
+/**
+ * GST_VAAPI_IMAGE_ID:
+ * @image: a #GstVaapiImage
+ *
+ * Macro that evaluates to the @image's object ID
+ */
+#undef  GST_VAAPI_IMAGE_ID
+#define GST_VAAPI_IMAGE_ID(image) \
+    (GST_VAAPI_IMAGE(image)->object_id)
+
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_image_get_raw(
+    GstVaapiImage     *image,
+    GstVaapiImageRaw  *dst_image,
+    GstVaapiRectangle *rect
+);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_image_update_from_raw(
+    GstVaapiImage     *image,
+    GstVaapiImageRaw  *src_image,
+    GstVaapiRectangle *rect
+);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_IMAGE_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimagepool.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimagepool.c
new file mode 100644 (file)
index 0000000..f64a367
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ *  gstvaapiimagepool.c - Gst VA image pool
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiimagepool
+ * @short_description: VA image pool
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiimagepool.h"
+#include "gstvaapivideopool_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/**
+ * GstVaapiImagePool:
+ *
+ * A pool of lazily allocated #GstVaapiImage objects.
+ */
+struct _GstVaapiImagePool
+{
+  /*< private > */
+  GstVaapiVideoPool parent_instance;
+
+  GstVideoFormat format;
+  guint width;
+  guint height;
+};
+
+static gboolean
+image_pool_init (GstVaapiVideoPool * base_pool, const GstVideoInfo * vip)
+{
+  GstVaapiImagePool *const pool = GST_VAAPI_IMAGE_POOL (base_pool);
+
+  pool->format = GST_VIDEO_INFO_FORMAT (vip);
+  pool->width = GST_VIDEO_INFO_WIDTH (vip);
+  pool->height = GST_VIDEO_INFO_HEIGHT (vip);
+  return gst_vaapi_display_has_image_format (base_pool->display, pool->format);
+}
+
+static gpointer
+gst_vaapi_image_pool_alloc_object (GstVaapiVideoPool * base_pool)
+{
+  GstVaapiImagePool *const pool = GST_VAAPI_IMAGE_POOL (base_pool);
+
+  return gst_vaapi_image_new (base_pool->display, pool->format,
+      pool->width, pool->height);
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_image_pool_class (void)
+{
+  static const GstVaapiVideoPoolClass GstVaapiImagePoolClass = {
+    {sizeof (GstVaapiImagePool),
+        (GDestroyNotify) gst_vaapi_video_pool_finalize}
+    ,
+    .alloc_object = gst_vaapi_image_pool_alloc_object
+  };
+  return GST_VAAPI_MINI_OBJECT_CLASS (&GstVaapiImagePoolClass);
+}
+
+/**
+ * gst_vaapi_image_pool_new:
+ * @display: a #GstVaapiDisplay
+ * @vip: the #GstVideoInfo
+ *
+ * Creates a new #GstVaapiVideoPool of #GstVaapiImage with the
+ * specified format and dimensions in @vip.
+ *
+ * Return value: the newly allocated #GstVaapiVideoPool
+ */
+GstVaapiVideoPool *
+gst_vaapi_image_pool_new (GstVaapiDisplay * display, const GstVideoInfo * vip)
+{
+  GstVaapiVideoPool *pool;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (vip != NULL, NULL);
+
+  pool = (GstVaapiVideoPool *)
+      gst_vaapi_mini_object_new (gst_vaapi_image_pool_class ());
+  if (!pool)
+    return NULL;
+
+  gst_vaapi_video_pool_init (pool, display,
+      GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE);
+
+  if (!image_pool_init (pool, vip))
+    goto error;
+  return pool;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (pool));
+    return NULL;
+  }
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimagepool.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiimagepool.h
new file mode 100644 (file)
index 0000000..7222bd9
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  gstvaapiimagepool.h - Gst VA image pool
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_IMAGE_POOL_H
+#define GST_VAAPI_IMAGE_POOL_H
+
+#include <gst/vaapi/gstvaapiimage.h>
+#include <gst/vaapi/gstvaapivideopool.h>
+#include <gst/vaapi/video-format.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_IMAGE_POOL(obj) \
+  ((GstVaapiImagePool *)(obj))
+
+typedef struct _GstVaapiImagePool GstVaapiImagePool;
+
+GstVaapiVideoPool *
+gst_vaapi_image_pool_new (GstVaapiDisplay * display, const GstVideoInfo * vip);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_IMAGE_POOL_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiminiobject.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiminiobject.c
new file mode 100644 (file)
index 0000000..30586b0
--- /dev/null
@@ -0,0 +1,201 @@
+/*
+ *  gstvaapiminiobject.c - A lightweight reference counted object
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include <string.h>
+#include "gstvaapiminiobject.h"
+
+static void
+gst_vaapi_mini_object_free (GstVaapiMiniObject * object)
+{
+  const GstVaapiMiniObjectClass *const klass = object->object_class;
+
+  g_atomic_int_inc (&object->ref_count);
+
+  if (klass->finalize)
+    klass->finalize (object);
+
+  if (G_LIKELY (g_atomic_int_dec_and_test (&object->ref_count)))
+    g_slice_free1 (klass->size, object);
+}
+
+/**
+ * gst_vaapi_mini_object_new:
+ * @object_class: (optional): The object class
+ *
+ * Creates a new #GstVaapiMiniObject. If @object_class is NULL, then the
+ * size of the allocated object is the same as sizeof(GstVaapiMiniObject).
+ * If @object_class is not NULL, typically when a sub-class is implemented,
+ * that pointer shall reference a statically allocated descriptor.
+ *
+ * This function does *not* zero-initialize the derived object data,
+ * use gst_vaapi_mini_object_new0() to fill this purpose.
+ *
+ * Returns: The newly allocated #GstVaapiMiniObject
+ */
+GstVaapiMiniObject *
+gst_vaapi_mini_object_new (const GstVaapiMiniObjectClass * object_class)
+{
+  GstVaapiMiniObject *object;
+
+  static const GstVaapiMiniObjectClass default_object_class = {
+    .size = sizeof (GstVaapiMiniObject),
+  };
+
+  if (G_UNLIKELY (!object_class))
+    object_class = &default_object_class;
+
+  g_return_val_if_fail (object_class->size >= sizeof (*object), NULL);
+
+  object = g_slice_alloc (object_class->size);
+  if (!object)
+    return NULL;
+
+  object->object_class = object_class;
+  g_atomic_int_set (&object->ref_count, 1);
+  object->flags = 0;
+  return object;
+}
+
+/**
+ * gst_vaapi_mini_object_new0:
+ * @object_class: (optional): The object class
+ *
+ * Creates a new #GstVaapiMiniObject. This function is similar to
+ * gst_vaapi_mini_object_new() but derived object data is initialized
+ * to zeroes.
+ *
+ * Returns: The newly allocated #GstVaapiMiniObject
+ */
+GstVaapiMiniObject *
+gst_vaapi_mini_object_new0 (const GstVaapiMiniObjectClass * object_class)
+{
+  GstVaapiMiniObject *object;
+  guint sub_size;
+
+  object = gst_vaapi_mini_object_new (object_class);
+  if (!object)
+    return NULL;
+
+  object_class = object->object_class;
+
+  sub_size = object_class->size - sizeof (*object);
+  if (sub_size > 0)
+    memset (((guchar *) object) + sizeof (*object), 0, sub_size);
+  return object;
+}
+
+/**
+ * gst_vaapi_mini_object_ref_internal:
+ * @object: a #GstVaapiMiniObject
+ *
+ * Atomically increases the reference count of the given @object by one.
+ * This is an internal function that does not do any run-time type check.
+ *
+ * Returns: The same @object argument
+ */
+static inline GstVaapiMiniObject *
+gst_vaapi_mini_object_ref_internal (GstVaapiMiniObject * object)
+{
+  g_atomic_int_inc (&object->ref_count);
+  return object;
+}
+
+/**
+ * gst_vaapi_mini_object_ref:
+ * @object: a #GstVaapiMiniObject
+ *
+ * Atomically increases the reference count of the given @object by one.
+ *
+ * Returns: The same @object argument
+ */
+GstVaapiMiniObject *
+gst_vaapi_mini_object_ref (GstVaapiMiniObject * object)
+{
+  g_return_val_if_fail (object != NULL, NULL);
+
+  return gst_vaapi_mini_object_ref_internal (object);
+}
+
+/**
+ * gst_vaapi_mini_object_unref_internal:
+ * @object: a #GstVaapiMiniObject
+ *
+ * Atomically decreases the reference count of the @object by one. If
+ * the reference count reaches zero, the object will be free'd.
+ *
+ * This is an internal function that does not do any run-time type check.
+ */
+static inline void
+gst_vaapi_mini_object_unref_internal (GstVaapiMiniObject * object)
+{
+  if (g_atomic_int_dec_and_test (&object->ref_count))
+    gst_vaapi_mini_object_free (object);
+}
+
+/**
+ * gst_vaapi_mini_object_unref:
+ * @object: a #GstVaapiMiniObject
+ *
+ * Atomically decreases the reference count of the @object by one. If
+ * the reference count reaches zero, the object will be free'd.
+ */
+void
+gst_vaapi_mini_object_unref (GstVaapiMiniObject * object)
+{
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (object->ref_count > 0);
+
+  gst_vaapi_mini_object_unref_internal (object);
+}
+
+/**
+ * gst_vaapi_mini_object_replace:
+ * @old_object_ptr: a pointer to a #GstVaapiMiniObject
+ * @new_object: a #GstVaapiMiniObject
+ *
+ * Atomically replaces the object held in @old_object_ptr with
+ * @new_object. This means that @old_object_ptr shall reference a
+ * valid object. However, @new_object can be NULL.
+ */
+void
+gst_vaapi_mini_object_replace (GstVaapiMiniObject ** old_object_ptr,
+    GstVaapiMiniObject * new_object)
+{
+  GstVaapiMiniObject *old_object;
+
+  g_return_if_fail (old_object_ptr != NULL);
+
+  old_object = g_atomic_pointer_get ((gpointer *) old_object_ptr);
+
+  if (old_object == new_object)
+    return;
+
+  if (new_object)
+    gst_vaapi_mini_object_ref_internal (new_object);
+
+  while (!g_atomic_pointer_compare_and_exchange ((gpointer *) old_object_ptr,
+          (gpointer) old_object, new_object))
+    old_object = g_atomic_pointer_get ((gpointer *) old_object_ptr);
+
+  if (old_object)
+    gst_vaapi_mini_object_unref_internal (old_object);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiminiobject.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiminiobject.h
new file mode 100644 (file)
index 0000000..52f2863
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ *  gstvaapiminiobject.h - A lightweight reference counted object
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_MINI_OBJECT_H
+#define GST_VAAPI_MINI_OBJECT_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiMiniObject              GstVaapiMiniObject;
+typedef struct _GstVaapiMiniObjectClass         GstVaapiMiniObjectClass;
+
+/**
+ * GST_VAAPI_MINI_OBJECT:
+ * @object: a #GstVaapiMiniObject
+ *
+ * Casts the @object to a #GstVaapiMiniObject
+ */
+#define GST_VAAPI_MINI_OBJECT(object) \
+  ((GstVaapiMiniObject *) (object))
+
+/**
+ * GST_VAAPI_MINI_OBJECT_PTR:
+ * @object_ptr: a pointer #GstVaapiMiniObject
+ *
+ * Casts the @object_ptr to a pointer to #GstVaapiMiniObject
+ */
+#define GST_VAAPI_MINI_OBJECT_PTR(object_ptr) \
+  ((GstVaapiMiniObject **) (object_ptr))
+
+/**
+ * GST_VAAPI_MINI_OBJECT_CLASS:
+ * @klass: a #GstVaapiMiniObjectClass
+ *
+ * Casts the @klass to a #GstVaapiMiniObjectClass
+ */
+#define GST_VAAPI_MINI_OBJECT_CLASS(klass) \
+  ((GstVaapiMiniObjectClass *) (klass))
+
+/**
+ * GST_VAAPI_MINI_OBJECT_GET_CLASS:
+ * @object: a #GstVaapiMiniObject
+ *
+ * Retrieves the #GstVaapiMiniObjectClass associated with the @object
+ */
+#define GST_VAAPI_MINI_OBJECT_GET_CLASS(object) \
+  (GST_VAAPI_MINI_OBJECT (object)->object_class)
+
+/**
+ * GST_VAAPI_MINI_OBJECT_FLAGS:
+ * @object: a #GstVaapiMiniObject
+ *
+ * The entire set of flags for the @object
+ */
+#define GST_VAAPI_MINI_OBJECT_FLAGS(object) \
+  (GST_VAAPI_MINI_OBJECT (object)->flags)
+
+/**
+ * GST_VAAPI_MINI_OBJECT_FLAG_IS_SET:
+ * @object: a #GstVaapiMiniObject
+ * @flag: a flag to check for
+ *
+ * Checks whether the given @flag is set
+ */
+#define GST_VAAPI_MINI_OBJECT_FLAG_IS_SET(object, flag) \
+  ((GST_VAAPI_MINI_OBJECT_FLAGS (object) & (flag)) != 0)
+
+/**
+ * GST_VAAPI_MINI_OBJECT_FLAG_SET:
+ * @object: a #GstVaapiMiniObject
+ * @flags: flags to set
+ *
+ * This macro sets the given bits
+ */
+#define GST_VAAPI_MINI_OBJECT_FLAG_SET(object, flags) \
+  (GST_VAAPI_MINI_OBJECT_FLAGS (object) |= (flags))
+
+/**
+ * GST_VAAPI_MINI_OBJECT_FLAG_UNSET:
+ * @object: a #GstVaapiMiniObject
+ * @flags: flags to unset
+ *
+ * This macro unsets the given bits.
+ */
+#define GST_VAAPI_MINI_OBJECT_FLAG_UNSET(object, flags) \
+  (GST_VAAPI_MINI_OBJECT_FLAGS (object) &= ~(flags))
+
+/**
+ * GstVaapiMiniObject:
+ * @object_class: the #GstVaapiMiniObjectClass
+ * @ref_count: the object reference count that should be manipulated
+ *   through gst_vaapi_mini_object_ref() et al. helpers
+ * @flags: set of flags that should be manipulated through
+ *   GST_VAAPI_MINI_OBJECT_FLAG_*() functions
+ *
+ * A #GstVaapiMiniObject represents a minimal reference counted data
+ * structure that can hold a set of flags and user-provided data.
+ */
+struct _GstVaapiMiniObject
+{
+  /*< private >*/
+  gconstpointer object_class;
+  gint ref_count;
+  guint flags;
+};
+
+/**
+ * GstVaapiMiniObjectClass:
+ * @size: size in bytes of the #GstVaapiMiniObject, plus any
+ *   additional data for derived classes
+ * @finalize: function called to destroy data in derived classes
+ *
+ * A #GstVaapiMiniObjectClass represents the base object class that
+ * defines the size of the #GstVaapiMiniObject and utility function to
+ * dispose child objects
+ */
+struct _GstVaapiMiniObjectClass
+{
+  /*< protected >*/
+  guint size;
+  GDestroyNotify finalize;
+};
+
+GstVaapiMiniObject *
+gst_vaapi_mini_object_new (const GstVaapiMiniObjectClass * object_class);
+
+GstVaapiMiniObject *
+gst_vaapi_mini_object_new0 (const GstVaapiMiniObjectClass * object_class);
+
+GstVaapiMiniObject *
+gst_vaapi_mini_object_ref (GstVaapiMiniObject * object);
+
+void
+gst_vaapi_mini_object_unref (GstVaapiMiniObject * object);
+
+void
+gst_vaapi_mini_object_replace (GstVaapiMiniObject ** old_object_ptr,
+    GstVaapiMiniObject * new_object);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_MINI_OBJECT_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiparser_frame.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiparser_frame.c
new file mode 100644 (file)
index 0000000..66da510
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ *  gstvaapiparser_frame.c - VA parser frame
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiparser_frame
+ * @short_description: VA decoder frame
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiparser_frame.h"
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_parser_frame_class (void)
+{
+  static const GstVaapiMiniObjectClass GstVaapiParserFrameClass = {
+    sizeof (GstVaapiParserFrame),
+    (GDestroyNotify) gst_vaapi_parser_frame_free
+  };
+  return &GstVaapiParserFrameClass;
+}
+
+static inline gboolean
+alloc_units (GArray ** units_ptr, guint size)
+{
+  GArray *units;
+
+  units = g_array_sized_new (FALSE, FALSE, sizeof (GstVaapiDecoderUnit), size);
+  *units_ptr = units;
+  return units != NULL;
+}
+
+static inline void
+free_units (GArray ** units_ptr)
+{
+  GArray *const units = *units_ptr;
+  guint i;
+
+  if (units) {
+    for (i = 0; i < units->len; i++) {
+      GstVaapiDecoderUnit *const unit =
+          &g_array_index (units, GstVaapiDecoderUnit, i);
+      gst_vaapi_decoder_unit_clear (unit);
+    }
+    g_array_unref (units);
+    *units_ptr = NULL;
+  }
+}
+
+/**
+ * gst_vaapi_parser_frame_new:
+ * @width: frame width in pixels
+ * @height: frame height in pixels
+ *
+ * Creates a new #GstVaapiParserFrame object.
+ *
+ * Returns: The newly allocated #GstVaapiParserFrame
+ */
+GstVaapiParserFrame *
+gst_vaapi_parser_frame_new (guint width, guint height)
+{
+  GstVaapiParserFrame *frame;
+  guint num_slices;
+
+  frame = (GstVaapiParserFrame *)
+      gst_vaapi_mini_object_new (gst_vaapi_parser_frame_class ());
+  if (!frame)
+    return NULL;
+
+  if (!height)
+    height = 1088;
+  num_slices = (height + 15) / 16;
+
+  if (!alloc_units (&frame->pre_units, 16))
+    goto error;
+  if (!alloc_units (&frame->units, num_slices))
+    goto error;
+  if (!alloc_units (&frame->post_units, 1))
+    goto error;
+  frame->output_offset = 0;
+  return frame;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_parser_frame_unref (frame);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_parser_frame_free:
+ * @frame: a #GstVaapiParserFrame
+ *
+ * Deallocates any internal resources bound to the supplied decoder
+ * @frame.
+ *
+ * @note This is an internal function used to implement lightweight
+ * sub-classes.
+ */
+void
+gst_vaapi_parser_frame_free (GstVaapiParserFrame * frame)
+{
+  free_units (&frame->units);
+  free_units (&frame->pre_units);
+  free_units (&frame->post_units);
+}
+
+/**
+ * gst_vaapi_parser_frame_append_unit:
+ * @frame: a #GstVaapiParserFrame
+ * @unit: a #GstVaapiDecoderUnit
+ *
+ * Appends unit to the @frame.
+ */
+void
+gst_vaapi_parser_frame_append_unit (GstVaapiParserFrame * frame,
+    GstVaapiDecoderUnit * unit)
+{
+  GArray **unit_array_ptr;
+
+  unit->offset = frame->output_offset;
+  frame->output_offset += unit->size;
+
+  if (GST_VAAPI_DECODER_UNIT_IS_SLICE (unit))
+    unit_array_ptr = &frame->units;
+  else if (GST_VAAPI_DECODER_UNIT_IS_FRAME_END (unit))
+    unit_array_ptr = &frame->post_units;
+  else
+    unit_array_ptr = &frame->pre_units;
+  g_array_append_val (*unit_array_ptr, *unit);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiparser_frame.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiparser_frame.h
new file mode 100644 (file)
index 0000000..5d20429
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ *  gstvaapiparser_frame.h - VA parser frame
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_PARSER_FRAME_H
+#define GST_VAAPI_PARSER_FRAME_H
+
+#include <gst/vaapi/gstvaapiminiobject.h>
+#include <gst/vaapi/gstvaapidecoder_unit.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiParserFrame             GstVaapiParserFrame;
+
+#define GST_VAAPI_PARSER_FRAME(frame) \
+    ((GstVaapiParserFrame *)(frame))
+
+#define GST_VAAPI_IS_PARSER_FRAME(frame) \
+    (GST_VAAPI_PARSER_FRAME(frame) != NULL)
+
+/**
+ * GstVaapiParserFrame:
+ * @output_offset: current offset to the reconstructed #GstBuffer for
+ *    this #GstVideoCodecFrame. This is used to initialize the decoder
+ *    unit offset
+ * @units: list of #GstVaapiDecoderUnit objects (slice data)
+ * @pre_units: list of units to decode before GstVaapiDecoder:start_frame()
+ * @post_units: list of units to decode after GstVaapiDecoder:end_frame()
+ *
+ * An extension to #GstVideoCodecFrame with #GstVaapiDecoder specific
+ * information. Decoder frames are usually attached to codec frames as
+ * the user_data anchor point.
+ */
+struct _GstVaapiParserFrame {
+    /*< private >*/
+    GstVaapiMiniObject  parent_instance;
+
+    guint               output_offset;
+    GArray             *units;
+    GArray             *pre_units;
+    GArray             *post_units;
+};
+
+G_GNUC_INTERNAL
+GstVaapiParserFrame *
+gst_vaapi_parser_frame_new(guint width, guint height);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_parser_frame_free(GstVaapiParserFrame *frame);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_parser_frame_append_unit(GstVaapiParserFrame *frame,
+    GstVaapiDecoderUnit *unit);
+
+static inline GstVaapiParserFrame *
+gst_vaapi_parser_frame_ref (GstVaapiParserFrame * frame)
+{
+  return (GstVaapiParserFrame *)
+      gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (frame));
+}
+
+static inline void
+gst_vaapi_parser_frame_unref (GstVaapiParserFrame * frame)
+{
+  gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (frame));
+}
+
+static inline void
+gst_vaapi_parser_frame_replace(GstVaapiParserFrame * old_frame_p,
+    GstVaapiParserFrame * new_frame)
+{
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) old_frame_p,
+      (GstVaapiMiniObject *) new_frame);
+}
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_PARSER_FRAME_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofile.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofile.c
new file mode 100644 (file)
index 0000000..63793c9
--- /dev/null
@@ -0,0 +1,646 @@
+/*
+ *  gstvaapiprofile.c - VA profile abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiprofile
+ * @short_description: VA profile abstraction
+ */
+
+#include "sysdeps.h"
+#include <gst/gstbuffer.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiprofile.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiworkarounds.h"
+
+typedef struct _GstVaapiCodecMap GstVaapiCodecMap;
+typedef struct _GstVaapiProfileMap GstVaapiProfileMap;
+typedef struct _GstVaapiEntrypointMap GstVaapiEntrypointMap;
+
+struct _GstVaapiCodecMap
+{
+  GstVaapiCodec codec;
+  const gchar *name;
+};
+
+struct _GstVaapiProfileMap
+{
+  GstVaapiProfile profile;
+  VAProfile va_profile;
+  const char *media_str;
+  const gchar *profile_str;
+};
+
+struct _GstVaapiEntrypointMap
+{
+  GstVaapiEntrypoint entrypoint;
+  VAEntrypoint va_entrypoint;
+};
+
+/* Codecs */
+static const GstVaapiCodecMap gst_vaapi_codecs[] = {
+  {GST_VAAPI_CODEC_MPEG1, "mpeg1"},
+  {GST_VAAPI_CODEC_MPEG2, "mpeg2"},
+  {GST_VAAPI_CODEC_MPEG4, "mpeg4"},
+  {GST_VAAPI_CODEC_H263, "h263"},
+  {GST_VAAPI_CODEC_H264, "h264"},
+  {GST_VAAPI_CODEC_WMV3, "wmv3"},
+  {GST_VAAPI_CODEC_VC1, "vc1"},
+  {GST_VAAPI_CODEC_JPEG, "jpeg"},
+  {GST_VAAPI_CODEC_VP8, "vp8"},
+  {GST_VAAPI_CODEC_H265, "h265"},
+  {GST_VAAPI_CODEC_VP9, "vp9"},
+  {GST_VAAPI_CODEC_AV1, "av1"},
+  {0,}
+};
+
+/* Profiles */
+static const GstVaapiProfileMap gst_vaapi_profiles[] = {
+  {GST_VAAPI_PROFILE_MPEG2_SIMPLE, VAProfileMPEG2Simple,
+      "video/mpeg, mpegversion=2", "simple"},
+  {GST_VAAPI_PROFILE_MPEG2_MAIN, VAProfileMPEG2Main,
+      "video/mpeg, mpegversion=2", "main"},
+  {GST_VAAPI_PROFILE_MPEG4_SIMPLE, VAProfileMPEG4Simple,
+      "video/mpeg, mpegversion=4", "simple"},
+  {GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
+      "video/mpeg, mpegversion=4", "advanced-simple"},
+  {GST_VAAPI_PROFILE_MPEG4_MAIN, VAProfileMPEG4Main,
+      "video/mpeg, mpegversion=4", "main"},
+  {GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
+      "video/x-divx, divxversion=5", "advanced-simple"},
+  {GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE, VAProfileMPEG4AdvancedSimple,
+      "video/x-xvid", "advanced-simple"},
+  {GST_VAAPI_PROFILE_H263_BASELINE, VAProfileH263Baseline,
+      "video/x-h263, variant=itu, h263version=h263", "baseline"},
+#if !VA_CHECK_VERSION(1,0,0)
+  {GST_VAAPI_PROFILE_H264_BASELINE, VAProfileH264Baseline,
+      "video/x-h264", "baseline"},
+#endif
+  {GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE,
+        VAProfileH264ConstrainedBaseline,
+      "video/x-h264", "constrained-baseline"},
+  {GST_VAAPI_PROFILE_H264_MAIN, VAProfileH264Main,
+      "video/x-h264", "main"},
+  {GST_VAAPI_PROFILE_H264_HIGH, VAProfileH264High,
+      "video/x-h264", "high"},
+  {GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH, VAProfileH264MultiviewHigh,
+      "video/x-h264", "multiview-high"},
+  {GST_VAAPI_PROFILE_H264_STEREO_HIGH, VAProfileH264StereoHigh,
+      "video/x-h264", "stereo-high"},
+  {GST_VAAPI_PROFILE_VC1_SIMPLE, VAProfileVC1Simple,
+      "video/x-wmv, wmvversion=3", "simple"},
+  {GST_VAAPI_PROFILE_VC1_MAIN, VAProfileVC1Main,
+      "video/x-wmv, wmvversion=3", "main"},
+  {GST_VAAPI_PROFILE_VC1_ADVANCED, VAProfileVC1Advanced,
+      "video/x-wmv, wmvversion=3, format=(string)WVC1", "advanced"},
+  {GST_VAAPI_PROFILE_JPEG_BASELINE, VAProfileJPEGBaseline,
+      "image/jpeg", NULL},
+  {GST_VAAPI_PROFILE_VP8, VAProfileVP8Version0_3,
+      "video/x-vp8", NULL},
+  {GST_VAAPI_PROFILE_H265_MAIN, VAProfileHEVCMain,
+      "video/x-h265", "main"},
+  {GST_VAAPI_PROFILE_H265_MAIN10, VAProfileHEVCMain10,
+      "video/x-h265", "main-10"},
+#if VA_CHECK_VERSION(1,2,0)
+  {GST_VAAPI_PROFILE_H265_MAIN_422_10, VAProfileHEVCMain422_10,
+      "video/x-h265", "main-422-10"},
+  {GST_VAAPI_PROFILE_H265_MAIN_444, VAProfileHEVCMain444,
+      "video/x-h265", "main-444"},
+  {GST_VAAPI_PROFILE_H265_MAIN_444_10, VAProfileHEVCMain444_10,
+      "video/x-h265", "main-444-10"},
+  {GST_VAAPI_PROFILE_H265_MAIN12, VAProfileHEVCMain12,
+      "video/x-h265", "main-12"},
+  {GST_VAAPI_PROFILE_H265_MAIN_444_12, VAProfileHEVCMain444_12,
+      "video/x-h265", "main-444-12"},
+  {GST_VAAPI_PROFILE_H265_MAIN_422_12, VAProfileHEVCMain422_12,
+      "video/x-h265", "main-422-12"},
+  {GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN, VAProfileHEVCSccMain,
+      "video/x-h265", "screen-extended-main"},
+  {GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10, VAProfileHEVCSccMain10,
+      "video/x-h265", "screen-extended-main-10"},
+  {GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444, VAProfileHEVCSccMain444,
+      "video/x-h265", "screen-extended-main-444"},
+#endif
+#if VA_CHECK_VERSION(1,8,0)
+  {GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10,
+        VAProfileHEVCSccMain444_10,
+      "video/x-h265", "screen-extended-main-444-10"},
+#endif
+  {GST_VAAPI_PROFILE_VP9_0, VAProfileVP9Profile0,
+      "video/x-vp9", "0"},
+  {GST_VAAPI_PROFILE_VP9_1, VAProfileVP9Profile1,
+      "video/x-vp9", "1"},
+  {GST_VAAPI_PROFILE_VP9_2, VAProfileVP9Profile2,
+      "video/x-vp9", "2"},
+  {GST_VAAPI_PROFILE_VP9_3, VAProfileVP9Profile3,
+      "video/x-vp9", "3"},
+#if VA_CHECK_VERSION(1,8,0)
+  /* Spec A.2:
+     "Main" compliant decoders must be able to decode streams with
+     seq_profile equal to 0.
+     "High" compliant decoders must be able to decode streams with
+     seq_profile less than or equal to 1.
+     "Professional" compliant decoders must be able to decode streams
+     with seq_profile less than or equal to 2.
+
+     The correct relationship between profile "main" "high" "professional"
+     and seq_profile "0" "1" "2" should be:
+     main <------> { 0 }
+     high <------> { main, 1 }
+     professional <------> { high, 2 }
+
+     So far, all vaapi decoders can support "0" when they support "1",
+     we just map "0" to "main" and "1" to "high" in caps string.  */
+  {GST_VAAPI_PROFILE_AV1_0, VAProfileAV1Profile0,
+      "video/x-av1", "main"},
+  {GST_VAAPI_PROFILE_AV1_1, VAProfileAV1Profile1,
+      "video/x-av1", "high"},
+#endif
+  {0,}
+};
+
+/* Entry-points */
+static const GstVaapiEntrypointMap gst_vaapi_entrypoints[] = {
+  {GST_VAAPI_ENTRYPOINT_VLD, VAEntrypointVLD},
+  {GST_VAAPI_ENTRYPOINT_IDCT, VAEntrypointIDCT},
+  {GST_VAAPI_ENTRYPOINT_MOCO, VAEntrypointMoComp},
+  {GST_VAAPI_ENTRYPOINT_SLICE_ENCODE, VAEntrypointEncSlice},
+  {GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE, VAEntrypointEncPicture},
+#if VA_CHECK_VERSION(0,39,1)
+  {GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP, VAEntrypointEncSliceLP},
+#endif
+  {0,}
+};
+
+static const GstVaapiCodecMap *
+get_codecs_map (GstVaapiCodec codec)
+{
+  const GstVaapiCodecMap *m;
+
+  for (m = gst_vaapi_codecs; m->codec; m++)
+    if (m->codec == codec)
+      return m;
+  return NULL;
+}
+
+static const GstVaapiProfileMap *
+get_profiles_map (GstVaapiProfile profile)
+{
+  const GstVaapiProfileMap *m;
+
+  for (m = gst_vaapi_profiles; m->profile; m++)
+    if (m->profile == profile)
+      return m;
+  return NULL;
+}
+
+static const GstVaapiEntrypointMap *
+get_entrypoints_map (GstVaapiEntrypoint entrypoint)
+{
+  const GstVaapiEntrypointMap *m;
+
+  for (m = gst_vaapi_entrypoints; m->entrypoint; m++)
+    if (m->entrypoint == entrypoint)
+      return m;
+  return NULL;
+}
+
+/**
+ * gst_vaapi_codec_get_name:
+ * @codec: a #GstVaapiCodec
+ *
+ * Returns a string representation for the supplied @codec type.
+ *
+ * Return value: the statically allocated string representation of @codec
+ */
+const gchar *
+gst_vaapi_codec_get_name (GstVaapiCodec codec)
+{
+  const GstVaapiCodecMap *const m = get_codecs_map (codec);
+
+  return m ? m->name : NULL;
+}
+
+/**
+ * gst_vaapi_profile:
+ * @profile: a #VAProfile
+ *
+ * Converts a VA profile into the corresponding #GstVaapiProfile. If
+ * the profile cannot be represented by #GstVaapiProfile, then zero is
+ * returned.
+ *
+ * Return value: the #GstVaapiProfile describing the @profile
+ */
+GstVaapiProfile
+gst_vaapi_profile (VAProfile profile)
+{
+  const GstVaapiProfileMap *m;
+
+  for (m = gst_vaapi_profiles; m->profile; m++)
+    if (m->va_profile == profile)
+      return m->profile;
+  return 0;
+}
+
+/**
+ * gst_vaapi_profile_get_name:
+ * @profile: a #GstVaapiProfile
+ *
+ * Returns a string representation for the supplied @profile.
+ *
+ * Return value: the statically allocated string representation of @profile
+ */
+const gchar *
+gst_vaapi_profile_get_name (GstVaapiProfile profile)
+{
+  const GstVaapiProfileMap *const m = get_profiles_map (profile);
+
+  return m ? m->profile_str : NULL;
+}
+
+/**
+ * gst_vaapi_profile_get_va_name:
+ * @profile: a #GstVaapiProfile
+ *
+ * Returns a string representation for the supplied @profile as VAProfile.
+ *
+ * Return value: the statically allocated string representation of
+ * @profile as VAProfile
+ */
+const gchar *
+gst_vaapi_profile_get_va_name (GstVaapiProfile profile)
+{
+  const GstVaapiProfileMap *const m = get_profiles_map (profile);
+
+  return m ? string_of_VAProfile (m->va_profile) : NULL;
+}
+
+/**
+ * gst_vaapi_profile_get_media_type_name:
+ * @profile: a #GstVaapiProfileo
+ *
+ * Returns a string representation for the media type of the supplied
+ * @profile.
+ *
+ * Return value: the statically allocated string representation of
+ *   @profile media type
+ */
+const gchar *
+gst_vaapi_profile_get_media_type_name (GstVaapiProfile profile)
+{
+  const GstVaapiProfileMap *const m = get_profiles_map (profile);
+
+  return m ? m->media_str : NULL;
+}
+
+/**
+ * gst_vaapi_profile_from_codec_data:
+ * @codec: a #GstVaapiCodec
+ * @buffer: a #GstBuffer holding code data
+ *
+ * Tries to parse VA profile from @buffer data and @codec information.
+ *
+ * Return value: the #GstVaapiProfile described in @buffer
+ */
+static GstVaapiProfile
+gst_vaapi_profile_from_codec_data_h264 (GstBuffer * buffer)
+{
+  /* MPEG-4 Part 15: Advanced Video Coding (AVC) file format */
+  guchar buf[3];
+
+  if (gst_buffer_extract (buffer, 0, buf, sizeof (buf)) != sizeof (buf))
+    return 0;
+
+  if (buf[0] != 1)              /* configurationVersion = 1 */
+    return 0;
+
+  switch (buf[1]) {             /* AVCProfileIndication */
+    case 66:
+      return ((buf[2] & 0x40) ?
+          GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE :
+          GST_VAAPI_PROFILE_H264_BASELINE);
+    case 77:
+      return GST_VAAPI_PROFILE_H264_MAIN;
+    case 100:
+      return GST_VAAPI_PROFILE_H264_HIGH;
+    case 118:
+      return GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH;
+    case 128:
+      return GST_VAAPI_PROFILE_H264_STEREO_HIGH;
+
+  }
+  return 0;
+}
+
+static GstVaapiProfile
+gst_vaapi_profile_from_codec_data_h265 (GstBuffer * buffer)
+{
+  /* ISO/IEC 14496-15:  HEVC file format */
+  guchar buf[3];
+
+  if (gst_buffer_extract (buffer, 0, buf, sizeof (buf)) != sizeof (buf))
+    return 0;
+
+  if (buf[0] != 1)              /* configurationVersion = 1 */
+    return 0;
+
+  if (buf[1] & 0xc0)            /* general_profile_space = 0 */
+    return 0;
+
+  /* We may not recognize the exactly correct profile, which needs more
+     info such as depth, chroma and constraint_flag. We just return the
+     first one that belongs to that profile IDC. */
+  switch (buf[1] & 0x1f) {      /* HEVCProfileIndication */
+    case 1:
+      return GST_VAAPI_PROFILE_H265_MAIN;
+    case 2:
+      return GST_VAAPI_PROFILE_H265_MAIN10;
+    case 3:
+      return GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE;
+    case 4:
+      return GST_VAAPI_PROFILE_H265_MAIN_422_10;
+    case 9:
+      return GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN;
+  }
+  return 0;
+}
+
+static GstVaapiProfile
+gst_vaapi_profile_from_codec_data (GstVaapiCodec codec, GstBuffer * buffer)
+{
+  GstVaapiProfile profile;
+
+  if (!codec || !buffer)
+    return 0;
+
+  switch (codec) {
+    case GST_VAAPI_CODEC_H264:
+      profile = gst_vaapi_profile_from_codec_data_h264 (buffer);
+      break;
+    case GST_VAAPI_CODEC_H265:
+      profile = gst_vaapi_profile_from_codec_data_h265 (buffer);
+      break;
+    default:
+      profile = 0;
+      break;
+  }
+  return profile;
+}
+
+/**
+ * gst_vaapi_profile_from_caps:
+ * @caps: a #GstCaps
+ *
+ * Converts @caps into the corresponding #GstVaapiProfile. If the
+ * profile cannot be represented by #GstVaapiProfile, then zero is
+ * returned.
+ *
+ * Return value: the #GstVaapiProfile describing the @caps
+ */
+GstVaapiProfile
+gst_vaapi_profile_from_caps (const GstCaps * caps)
+{
+  const GstVaapiProfileMap *m;
+  GstCaps *caps_test;
+  GstStructure *structure;
+  const gchar *profile_str;
+  GstVaapiProfile profile, best_profile;
+  GstBuffer *codec_data = NULL;
+  const gchar *name;
+  gsize namelen;
+
+  if (!caps)
+    return 0;
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (!structure)
+    return 0;
+
+  name = gst_structure_get_name (structure);
+  namelen = strlen (name);
+
+  profile_str = gst_structure_get_string (structure, "profile");
+  if (!profile_str) {
+    const GValue *v_codec_data;
+    v_codec_data = gst_structure_get_value (structure, "codec_data");
+    if (v_codec_data)
+      codec_data = gst_value_get_buffer (v_codec_data);
+  }
+
+  profile = 0;
+  best_profile = 0;
+  for (m = gst_vaapi_profiles; !profile && m->profile; m++) {
+    if (strncmp (name, m->media_str, namelen) != 0)
+      continue;
+    caps_test = gst_caps_from_string (m->media_str);
+    if (gst_caps_is_always_compatible (caps, caps_test)) {
+      best_profile = m->profile;
+      if (profile_str && m->profile_str &&
+          strcmp (profile_str, m->profile_str) == 0)
+        profile = best_profile;
+    }
+    if (!profile) {
+      profile =
+          gst_vaapi_profile_from_codec_data (gst_vaapi_profile_get_codec
+          (m->profile), codec_data);
+      if (!profile && WORKAROUND_QTDEMUX_NO_H263_PROFILES
+          && strncmp (name, "video/x-h263", namelen) == 0) {
+        /* HACK: qtdemux does not report profiles for h263 */
+        profile = m->profile;
+      }
+
+      /* Consider HEVC -intra profiles. Just map them to their
+       * non-intra profiles */
+      if (!profile && profile_str
+          && strncmp (name, "video/x-h265", namelen) == 0
+          && g_str_has_prefix (profile_str, m->profile_str)
+          && strncmp (profile_str + strlen (m->profile_str), "-intra", 6) == 0) {
+        profile = m->profile;
+      }
+    }
+    gst_caps_unref (caps_test);
+  }
+  return profile ? profile : best_profile;
+}
+
+/**
+ * gst_vaapi_get_codec_from_caps:
+ * @caps: a #GstCaps
+ *
+ * Converts @caps into the corresponding #GstVaapiCodec. If we can
+ * not recognize the #GstVaapiCodec, then zero is returned.
+ *
+ * Return value: the #GstVaapiCodec describing the @caps
+ */
+GstVaapiCodec
+gst_vaapi_get_codec_from_caps (const GstCaps * caps)
+{
+  GstStructure *structure;
+  const gchar *name;
+  gsize namelen;
+  const GstVaapiProfileMap *m;
+  GstVaapiProfile profile;
+
+  if (!caps)
+    return 0;
+
+  structure = gst_caps_get_structure (caps, 0);
+  if (!structure)
+    return 0;
+
+  name = gst_structure_get_name (structure);
+  namelen = strlen (name);
+
+  profile = GST_VAAPI_PROFILE_UNKNOWN;
+  for (m = gst_vaapi_profiles; m->profile; m++) {
+    if (strncmp (name, m->media_str, namelen) == 0) {
+      profile = m->profile;
+      break;
+    }
+  }
+
+  if (profile == GST_VAAPI_PROFILE_UNKNOWN)
+    return 0;
+
+  return gst_vaapi_profile_get_codec (profile);
+}
+
+/**
+ * gst_vaapi_profile_get_va_profile:
+ * @profile: a #GstVaapiProfile
+ *
+ * Converts a #GstVaapiProfile into the corresponding VA profile. If
+ * no matching VA profile was found, -1 is returned and this error
+ * must be reported to be fixed.
+ *
+ * Return value: the VA profile, or -1 if none was found
+ */
+VAProfile
+gst_vaapi_profile_get_va_profile (GstVaapiProfile profile)
+{
+  const GstVaapiProfileMap *const m = get_profiles_map (profile);
+
+  return m ? m->va_profile : (VAProfile) - 1;
+}
+
+/**
+ * gst_vaapi_profile_get_caps:
+ * @profile: a #GstVaapiProfile
+ *
+ * Converts a #GstVaapiProfile into the corresponding #GstCaps. If no
+ * matching caps were found, %NULL is returned.
+ *
+ * Return value: the newly allocated #GstCaps, or %NULL if none was found
+ */
+GstCaps *
+gst_vaapi_profile_get_caps (GstVaapiProfile profile)
+{
+  const GstVaapiProfileMap *m;
+  GstCaps *out_caps, *caps;
+
+  out_caps = gst_caps_new_empty ();
+  if (!out_caps)
+    return NULL;
+
+  for (m = gst_vaapi_profiles; m->profile; m++) {
+    if (m->profile != profile)
+      continue;
+    caps = gst_caps_from_string (m->media_str);
+    if (!caps)
+      continue;
+    gst_caps_set_simple (caps, "profile", G_TYPE_STRING, m->profile_str, NULL);
+    out_caps = gst_caps_merge (out_caps, caps);
+  }
+  return out_caps;
+}
+
+/**
+ * gst_vaapi_profile_get_codec:
+ * @profile: a #GstVaapiProfile
+ *
+ * Extracts the #GstVaapiCodec from @profile.
+ *
+ * Return value: the #GstVaapiCodec from @profile
+ */
+GstVaapiCodec
+gst_vaapi_profile_get_codec (GstVaapiProfile profile)
+{
+  GstVaapiCodec codec;
+
+  switch (profile) {
+    case GST_VAAPI_PROFILE_VC1_SIMPLE:
+    case GST_VAAPI_PROFILE_VC1_MAIN:
+      codec = GST_VAAPI_CODEC_WMV3;
+      break;
+    case GST_VAAPI_PROFILE_VC1_ADVANCED:
+      codec = GST_VAAPI_CODEC_VC1;
+      break;
+    case GST_VAAPI_PROFILE_JPEG_BASELINE:
+      codec = GST_VAAPI_CODEC_JPEG;
+      break;
+    default:
+      codec = (guint32) profile & GST_MAKE_FOURCC (0xff, 0xff, 0xff, 0);
+      break;
+  }
+  return codec;
+}
+
+/**
+ * gst_vaapi_entrypoint:
+ * @entrypoint: a #VAEntrypoint
+ *
+ * Converts a VA entry-point into the corresponding #GstVaapiEntrypoint.
+ * If the entry-point cannot be represented by #GstVaapiEntrypoint,
+ * then zero is returned.
+ *
+ * Return value: the #GstVaapiEntrypoint describing the @entrypoint
+ */
+GstVaapiEntrypoint
+gst_vaapi_entrypoint (VAEntrypoint entrypoint)
+{
+  const GstVaapiEntrypointMap *m;
+
+  for (m = gst_vaapi_entrypoints; m->entrypoint; m++)
+    if (m->va_entrypoint == entrypoint)
+      return m->entrypoint;
+  return 0;
+}
+
+/**
+ * gst_vaapi_entrypoint_get_va_entrypoint:
+ * @entrypoint: a #GstVaapiEntrypoint
+ *
+ * Converts a #GstVaapiEntrypoint into the corresponding VA
+ * entry-point. If no matching VA entry-point was found, -1 is
+ * returned and this error must be reported to be fixed.
+ *
+ * Return value: the VA entry-point, or -1 if none was found
+ */
+VAEntrypoint
+gst_vaapi_entrypoint_get_va_entrypoint (GstVaapiEntrypoint entrypoint)
+{
+  const GstVaapiEntrypointMap *const m = get_entrypoints_map (entrypoint);
+
+  return m ? m->va_entrypoint : (VAEntrypoint) - 1;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofile.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofile.h
new file mode 100644 (file)
index 0000000..8fc98c1
--- /dev/null
@@ -0,0 +1,271 @@
+/*
+ *  gstvaapiprofile.h - VA profile abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_PROFILE_H
+#define GST_VAAPI_PROFILE_H
+
+#include <va/va.h>
+#include <gst/gstvalue.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstVaapiCodec:
+ * @GST_VAAPI_CODEC_MPEG1: MPEG-1 (ISO/IEC 11172)
+ * @GST_VAAPI_CODEC_MPEG2: MPEG-2 (ISO/IEC 13818-2)
+ * @GST_VAAPI_CODEC_MPEG4: MPEG-4 Part 2 (ISO/IEC 14496-2)
+ * @GST_VAAPI_CODEC_H263: H.263
+ * @GST_VAAPI_CODEC_H264: H.264 aka MPEG-4 Part 10 (ISO/IEC 14496-10)
+ * @GST_VAAPI_CODEC_WMV3: Windows Media Video 9. VC-1 Simple or Main profile (SMPTE 421M)
+ * @GST_VAAPI_CODEC_VC1: VC-1 Advanced profile (SMPTE 421M)
+ * @GST_VAAPI_CODEC_JPEG: JPEG (ITU-T 81)
+ * @GST_VAAPI_CODEC_H265: H.265 aka MPEG-H Part 2 (ITU-T H.265)
+ * @GST_VAAPI_CODEC_VP9: VP9 (libvpx)
+ * @GST_VAAPI_CODEC_AV1: AV1 (aom)
+ *
+ * The set of all codecs for #GstVaapiCodec.
+ */
+typedef enum {
+    GST_VAAPI_CODEC_MPEG1       = GST_MAKE_FOURCC('M','P','1',0),
+    GST_VAAPI_CODEC_MPEG2       = GST_MAKE_FOURCC('M','P','2',0),
+    GST_VAAPI_CODEC_MPEG4       = GST_MAKE_FOURCC('M','P','4',0),
+    GST_VAAPI_CODEC_H263        = GST_MAKE_FOURCC('2','6','3',0),
+    GST_VAAPI_CODEC_H264        = GST_MAKE_FOURCC('2','6','4',0),
+    GST_VAAPI_CODEC_WMV3        = GST_MAKE_FOURCC('W','M','V',0),
+    GST_VAAPI_CODEC_VC1         = GST_MAKE_FOURCC('V','C','1',0),
+    GST_VAAPI_CODEC_JPEG        = GST_MAKE_FOURCC('J','P','G',0),
+    GST_VAAPI_CODEC_VP8         = GST_MAKE_FOURCC('V','P','8',0),
+    GST_VAAPI_CODEC_H265        = GST_MAKE_FOURCC('2','6','5',0),
+    GST_VAAPI_CODEC_VP9         = GST_MAKE_FOURCC('V','P','9',0),
+    GST_VAAPI_CODEC_AV1         = GST_MAKE_FOURCC('A','V','1',0),
+} GstVaapiCodec;
+
+/**
+ * GST_VAAPI_MAKE_PROFILE:
+ * @codec: the #GstVaapiCodec without the GST_VAAPI_CODEC_ prefix
+ * @sub_id: a non-zero sub-codec id
+ *
+ * Macro that evaluates to the profile composed from @codec and
+ * @sub_id.
+ */
+#define GST_VAAPI_MAKE_PROFILE(codec, sub_id) \
+    (GST_VAAPI_CODEC_##codec | GST_MAKE_FOURCC(0,0,0,sub_id))
+
+/**
+ * GstVaapiProfile:
+ * @GST_VAAPI_PROFILE_UNKNOWN:
+ *   Unknown profile, used for initializers
+ * @GST_VAAPI_PROFILE_MPEG1:
+ *   MPEG-1
+ * @GST_VAAPI_PROFILE_MPEG2_SIMPLE:
+ *   MPEG-2 simple profile
+ * @GST_VAAPI_PROFILE_MPEG2_MAIN:
+ *   MPEG-2 main profile
+ * @GST_VAAPI_PROFILE_MPEG2_HIGH:
+ *   MPEG-2 high profile
+ * @GST_VAAPI_PROFILE_MPEG4_SIMPLE:
+ *   MPEG-4 Part-2 simple profile
+ * @GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE:
+ *   MPEG-4 Part-2 advanced simple profile
+ * @GST_VAAPI_PROFILE_MPEG4_MAIN:
+ *   MPEG-4 Part-2 main profile
+ * @GST_VAAPI_PROFILE_H263_BASELINE:
+ *   H.263 baseline profile
+ * @GST_VAAPI_PROFILE_H264_BASELINE:
+ *   H.264 (MPEG-4 Part-10) baseline profile [A.2.1]
+ * @GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE:
+ *   H.264 (MPEG-4 Part-10) constrained baseline profile [A.2.1.1]
+ * @GST_VAAPI_PROFILE_H264_MAIN:
+ *   H.264 (MPEG-4 Part-10) main profile [A.2.2]
+ * @GST_VAAPI_PROFILE_H264_EXTENDED:
+ *   H.264 (MPEG-4 Part 10) extended profile [A.2.3]
+ * @GST_VAAPI_PROFILE_H264_HIGH:
+ *   H.264 (MPEG-4 Part-10) high profile [A.2.4]
+ * @GST_VAAPI_PROFILE_H264_HIGH10:
+ *   H.264 (MPEG-4 Part-10) high 10 profile [A.2.5], or high 10 intra
+ *   profile [A.2.8], depending on constraint_set3_flag
+ * @GST_VAAPI_PROFILE_H264_HIGH_422:
+ *   H.264 (MPEG-4 Part-10) high 4:2:2 profile [A.2.6], or high 4:2:2
+ *   intra profile [A.2.9], depending on constraint_set3_flag
+ * @GST_VAAPI_PROFILE_H264_HIGH_444:
+ *   H.264 (MPEG-4 Part-10) high 4:4:4 predictive profile [A.2.7], or
+ *   high 4:4:4 intra profile [A.2.10], depending on constraint_set3_flag
+ * @GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE:
+ *   H.264 (MPEG-4 Part-10) scalable baseline profile [G.10.1.1]
+ * @GST_VAAPI_PROFILE_H264_SCALABLE_HIGH:
+ *   H.264 (MPEG-4 Part-10) scalable high profile [G.10.1.2], or scalable
+ *   high intra profile [G.10.1.3], depending on constraint_set3_flag
+ * @GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH:
+ *   H.264 (MPEG-4 Part-10) multiview high profile [H.10.1.1]
+ * @GST_VAAPI_PROFILE_H264_STEREO_HIGH:
+ *   H.264 (MPEG-4 Part-10) stereo high profile [H.10.1.2]
+ * @GST_VAAPI_PROFILE_VC1_SIMPLE:
+ *   VC-1 simple profile
+ * @GST_VAAPI_PROFILE_VC1_MAIN:
+ *   VC-1 main profile
+ * @GST_VAAPI_PROFILE_VC1_ADVANCED:
+ *   VC-1 advanced profile
+ * @GST_VAAPI_PROFILE_JPEG_BASELINE:
+ *   JPEG baseline profile
+ * @GST_VAAPI_PROFILE_H265_MAIN:
+ *   H.265 main profile [A.3.2]
+ * @GST_VAAPI_PROFILE_H265_MAIN10:
+ *   H.265 main 10 profile [A.3.3]
+ * @GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE:
+ *   H.265 main still picture profile [A.3.4]
+ * @GST_VAAPI_PROFILE_H265_MAIN_422_10:
+ *   H.265 main still picture profile [A.3.5]
+ * @GST_VAAPI_PROFILE_VP9_0:
+ *   VP9 prfile 0, bitdepth=8, 420
+ * @GST_VAAPI_PROFILE_VP9_1:
+ *   VP9 prfile 1, bitdepth=8, 422/444/440/RGB
+ * @GST_VAAPI_PROFILE_VP9_2:
+ *   VP9 prfile 2, bitdepth=10/12, 420
+ * @GST_VAAPI_PROFILE_VP9_3:
+ *   VP9 prfile 3 bitdepth=10/12, 422/444/440/RGB
+ * @GST_VAAPI_PROFILE_AV1_0:
+ *   AV1 prfile 0, bitdepth=8/10, 420/400
+ * @GST_VAAPI_PROFILE_AV1_1:
+ *   AV1 prfile 1 bitdepth=8/10, 444
+ *
+ * The set of all profiles for #GstVaapiProfile.
+ */
+typedef enum {
+    GST_VAAPI_PROFILE_UNKNOWN               = 0,
+    GST_VAAPI_PROFILE_MPEG1                 = GST_VAAPI_MAKE_PROFILE(MPEG1,1),
+    GST_VAAPI_PROFILE_MPEG2_SIMPLE          = GST_VAAPI_MAKE_PROFILE(MPEG2,1),
+    GST_VAAPI_PROFILE_MPEG2_MAIN            = GST_VAAPI_MAKE_PROFILE(MPEG2,2),
+    GST_VAAPI_PROFILE_MPEG2_HIGH            = GST_VAAPI_MAKE_PROFILE(MPEG2,3),
+    GST_VAAPI_PROFILE_MPEG4_SIMPLE          = GST_VAAPI_MAKE_PROFILE(MPEG4,1),
+    GST_VAAPI_PROFILE_MPEG4_ADVANCED_SIMPLE = GST_VAAPI_MAKE_PROFILE(MPEG4,2),
+    GST_VAAPI_PROFILE_MPEG4_MAIN            = GST_VAAPI_MAKE_PROFILE(MPEG4,3),
+    GST_VAAPI_PROFILE_H263_BASELINE         = GST_VAAPI_MAKE_PROFILE(H263,1),
+    GST_VAAPI_PROFILE_H264_BASELINE         = GST_VAAPI_MAKE_PROFILE(H264,1),
+    GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE =
+                                              GST_VAAPI_MAKE_PROFILE(H264,9),
+    GST_VAAPI_PROFILE_H264_MAIN             = GST_VAAPI_MAKE_PROFILE(H264,2),
+    GST_VAAPI_PROFILE_H264_EXTENDED         = GST_VAAPI_MAKE_PROFILE(H264,10),
+    GST_VAAPI_PROFILE_H264_HIGH             = GST_VAAPI_MAKE_PROFILE(H264,3),
+    GST_VAAPI_PROFILE_H264_HIGH10           = GST_VAAPI_MAKE_PROFILE(H264,7),
+    GST_VAAPI_PROFILE_H264_HIGH_422         = GST_VAAPI_MAKE_PROFILE(H264,4),
+    GST_VAAPI_PROFILE_H264_HIGH_444         = GST_VAAPI_MAKE_PROFILE(H264,8),
+    GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE =
+                                              GST_VAAPI_MAKE_PROFILE(H264,5),
+    GST_VAAPI_PROFILE_H264_SCALABLE_HIGH    = GST_VAAPI_MAKE_PROFILE(H264,6),
+    GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH   = GST_VAAPI_MAKE_PROFILE(H264,11),
+    GST_VAAPI_PROFILE_H264_STEREO_HIGH      = GST_VAAPI_MAKE_PROFILE(H264,15),
+    GST_VAAPI_PROFILE_VC1_SIMPLE            = GST_VAAPI_MAKE_PROFILE(VC1,1),
+    GST_VAAPI_PROFILE_VC1_MAIN              = GST_VAAPI_MAKE_PROFILE(VC1,2),
+    GST_VAAPI_PROFILE_VC1_ADVANCED          = GST_VAAPI_MAKE_PROFILE(VC1,3),
+    GST_VAAPI_PROFILE_JPEG_BASELINE         = GST_VAAPI_MAKE_PROFILE(JPEG,1),
+    GST_VAAPI_PROFILE_VP8                   = GST_VAAPI_MAKE_PROFILE(VP8,1),
+    GST_VAAPI_PROFILE_H265_MAIN             = GST_VAAPI_MAKE_PROFILE(H265,1),
+    GST_VAAPI_PROFILE_H265_MAIN10           = GST_VAAPI_MAKE_PROFILE(H265,2),
+    GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE =
+                                               GST_VAAPI_MAKE_PROFILE(H265,3),
+    GST_VAAPI_PROFILE_H265_MAIN_422_10        = GST_VAAPI_MAKE_PROFILE(H265,4),
+    GST_VAAPI_PROFILE_H265_MAIN_444           = GST_VAAPI_MAKE_PROFILE(H265,5),
+    GST_VAAPI_PROFILE_H265_MAIN_444_10        = GST_VAAPI_MAKE_PROFILE(H265,6),
+    GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN =
+                                                GST_VAAPI_MAKE_PROFILE(H265,7),
+    GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10 =
+                                                GST_VAAPI_MAKE_PROFILE(H265,8),
+    GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444 =
+                                                GST_VAAPI_MAKE_PROFILE(H265,9),
+    GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10 =
+                                                GST_VAAPI_MAKE_PROFILE(H265,10),
+    GST_VAAPI_PROFILE_H265_MAIN12             = GST_VAAPI_MAKE_PROFILE(H265,11),
+    GST_VAAPI_PROFILE_H265_MAIN_444_12        = GST_VAAPI_MAKE_PROFILE(H265,12),
+    GST_VAAPI_PROFILE_H265_MAIN_422_12        = GST_VAAPI_MAKE_PROFILE(H265,13),
+    GST_VAAPI_PROFILE_VP9_0                   = GST_VAAPI_MAKE_PROFILE(VP9,1),
+    GST_VAAPI_PROFILE_VP9_1                   = GST_VAAPI_MAKE_PROFILE(VP9,2),
+    GST_VAAPI_PROFILE_VP9_2                   = GST_VAAPI_MAKE_PROFILE(VP9,3),
+    GST_VAAPI_PROFILE_VP9_3                   = GST_VAAPI_MAKE_PROFILE(VP9,4),
+
+    GST_VAAPI_PROFILE_AV1_0                   = GST_VAAPI_MAKE_PROFILE(AV1,1),
+    GST_VAAPI_PROFILE_AV1_1                   = GST_VAAPI_MAKE_PROFILE(AV1,2),
+} GstVaapiProfile;
+
+/**
+ * GstVaapiEntrypoint:
+ * @GST_VAAPI_ENTRYPOINT_INVALID: Invalid entrypoint
+ * @GST_VAAPI_ENTRYPOINT_VLD: Variable Length Decoding
+ * @GST_VAAPI_ENTRYPOINT_IDCT: Inverse Decrete Cosine Transform
+ * @GST_VAAPI_ENTRYPOINT_MOCO: Motion Compensation
+ * @GST_VAAPI_ENTRYPOINT_SLICE_ENCODE: Encode Slice
+ * @GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE: Encode Picture
+ * @GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP: Encode Slice low power/
+ *                                        high performace varient
+ *
+ * The set of all entrypoints for #GstVaapiEntrypoint
+ */
+typedef enum {
+    GST_VAAPI_ENTRYPOINT_INVALID,
+    GST_VAAPI_ENTRYPOINT_VLD,
+    GST_VAAPI_ENTRYPOINT_IDCT,
+    GST_VAAPI_ENTRYPOINT_MOCO,
+    GST_VAAPI_ENTRYPOINT_SLICE_ENCODE,
+    GST_VAAPI_ENTRYPOINT_PICTURE_ENCODE,
+    GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP,
+} GstVaapiEntrypoint;
+
+const gchar *
+gst_vaapi_codec_get_name(GstVaapiCodec codec);
+
+GstVaapiProfile
+gst_vaapi_profile(VAProfile profile);
+
+GstVaapiProfile
+gst_vaapi_profile_from_caps(const GstCaps *caps);
+
+GstVaapiCodec
+gst_vaapi_get_codec_from_caps (const GstCaps *caps);
+
+const gchar *
+gst_vaapi_profile_get_name(GstVaapiProfile profile);
+
+const gchar *
+gst_vaapi_profile_get_va_name(GstVaapiProfile profile);
+
+const gchar *
+gst_vaapi_profile_get_media_type_name(GstVaapiProfile profile);
+
+VAProfile
+gst_vaapi_profile_get_va_profile(GstVaapiProfile profile);
+
+GstCaps *
+gst_vaapi_profile_get_caps(GstVaapiProfile profile);
+
+GstVaapiCodec
+gst_vaapi_profile_get_codec(GstVaapiProfile profile);
+
+GstVaapiEntrypoint
+gst_vaapi_entrypoint(VAEntrypoint entrypoint);
+
+VAEntrypoint
+gst_vaapi_entrypoint_get_va_entrypoint(GstVaapiEntrypoint entrypoint);
+
+G_END_DECLS
+
+#endif /* GST_GST_VAAPI_IMAGE_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofilecaps.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofilecaps.c
new file mode 100644 (file)
index 0000000..0e44393
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ *  gstvaapiprofilecaps.h - VA config attributes as gstreamer capabilities
+ *
+ *  Copyright (C) 2019 Igalia, S.L.
+ *    Author: Víctor Jáquez <vjaquez@igalia.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiprofilecaps
+ * @short_description: VA config attributes as gstreamer capabilities
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapicontext.h"
+#include "gstvaapiprofilecaps.h"
+#include "gstvaapiutils.h"
+
+static gboolean
+init_context_info (GstVaapiDisplay * display, GstVaapiContextInfo * cip)
+{
+  guint value = 0;
+
+  /* XXX: Only try a context from he first RTFormat in config. */
+  if (!gst_vaapi_get_config_attribute (display,
+          gst_vaapi_profile_get_va_profile (cip->profile),
+          gst_vaapi_entrypoint_get_va_entrypoint (cip->entrypoint),
+          VAConfigAttribRTFormat, &value)) {
+    return FALSE;
+  }
+
+  cip->chroma_type = to_GstVaapiChromaType (value);
+  return cip->chroma_type != 0;
+}
+
+static GstVaapiContext *
+create_context (GstVaapiDisplay * display, GstVaapiContextInfo * cip)
+{
+  if (!init_context_info (display, cip))
+    return NULL;
+  return gst_vaapi_context_new (display, cip);
+}
+
+static gboolean
+append_caps (GstVaapiContext * context, GstStructure * structure)
+{
+  GstVaapiConfigSurfaceAttributes attribs = { 0, };
+
+  if (!gst_vaapi_context_get_surface_attributes (context, &attribs))
+    return FALSE;
+
+  if (attribs.min_width >= attribs.max_width ||
+      attribs.min_height >= attribs.max_height)
+    return FALSE;
+
+  gst_structure_set (structure, "width", GST_TYPE_INT_RANGE, attribs.min_width,
+      attribs.max_width, "height", GST_TYPE_INT_RANGE, attribs.min_height,
+      attribs.max_height, NULL);
+
+  return TRUE;
+}
+
+static gboolean
+append_caps_with_context_info (GstVaapiDisplay * display,
+    GstVaapiContextInfo * cip, GstStructure * structure)
+{
+  GstVaapiContext *context;
+  gboolean ret;
+
+  context = create_context (display, cip);
+  if (!context)
+    return FALSE;
+
+  ret = append_caps (context, structure);
+  gst_vaapi_context_unref (context);
+  return ret;
+}
+
+/**
+ * gst_vaapi_decoder_add_profile_caps:
+ * @display: a #GstVaapiDisplay
+ * @profile: a #GstVaapiProfile
+ * @structure: a #GstStructure
+ *
+ * Extracts the config's surface attributes, from @profile, in a
+ * decoder context, and transforms it into a caps formats and appended
+ * into @structure.
+ *
+ * Returns: %TRUE if the capabilities could be extracted and appended
+ * into @structure; otherwise %FALSE
+ **/
+gboolean
+gst_vaapi_profile_caps_append_decoder (GstVaapiDisplay * display,
+    GstVaapiProfile profile, GstStructure * structure)
+{
+  GstVaapiContextInfo cip = {
+    GST_VAAPI_CONTEXT_USAGE_DECODE, profile, GST_VAAPI_ENTRYPOINT_VLD, 0,
+  };
+
+  g_return_val_if_fail (display != NULL, FALSE);
+  g_return_val_if_fail (structure != NULL, FALSE);
+
+  return append_caps_with_context_info (display, &cip, structure);
+}
+
+/**
+ * gst_vaapi_mem_type_supports:
+ * @va_mem_types:  memory types from VA surface attributes
+ * @mem_type: the #GstVaapiBufferMemoryType to test
+ *
+ * Test if @va_mem_types handles @mem_type
+ *
+ * Returns: %TRUE if @mem_type is supported in @va_mem_types;
+ *    otherwise %FALSE
+ **/
+gboolean
+gst_vaapi_mem_type_supports (guint va_mem_types, guint mem_type)
+{
+  return ((va_mem_types & from_GstVaapiBufferMemoryType (mem_type)) != 0);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofilecaps.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiprofilecaps.h
new file mode 100644 (file)
index 0000000..a33ebc9
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ *  gstvaapiprofilecaps.h - VA config attributes as gstreamer capabilities
+ *
+ *  Copyright (C) 2019 Igalia, S.L.
+ *    Author: Víctor Jáquez <vjaquez@igalia.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_PROFILE_CAPS_H
+#define GST_VAAPI_PROFILE_CAPS_H
+
+#include <gst/gst.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiprofile.h>
+
+G_BEGIN_DECLS
+
+gboolean
+gst_vaapi_profile_caps_append_decoder (GstVaapiDisplay * display,
+    GstVaapiProfile profile, GstStructure * structure);
+
+gboolean
+gst_vaapi_mem_type_supports (guint va_mem_types, guint mem_type);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_PROFILE_CAPS_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisubpicture.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisubpicture.c
new file mode 100644 (file)
index 0000000..c2ba257
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ *  gstvaapisubpicture.c - VA subpicture abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapisubpicture
+ * @short_description: VA subpicture abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+#include "gstvaapisubpicture.h"
+#include "gstvaapiimage_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/**
+ * GstVaapiSubpicture:
+ *
+ * A VA subpicture wrapper
+ */
+struct _GstVaapiSubpicture
+{
+  /*< private > */
+  GstMiniObject mini_object;
+  GstVaapiDisplay *display;
+  GstVaapiID object_id;
+
+  GstVaapiImage *image;
+  guint flags;
+  gfloat global_alpha;
+};
+
+static void
+gst_vaapi_subpicture_free_image (GstVaapiSubpicture * subpicture)
+{
+  GstVaapiDisplay *const display = subpicture->display;
+  VASubpictureID subpicture_id;
+  VAStatus status;
+
+  subpicture_id = subpicture->object_id;
+  GST_DEBUG ("subpicture %" GST_VAAPI_ID_FORMAT,
+      GST_VAAPI_ID_ARGS (subpicture_id));
+
+  if (subpicture_id != VA_INVALID_ID) {
+    GST_VAAPI_DISPLAY_LOCK (display);
+    status = vaDestroySubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display),
+        subpicture_id);
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+    if (!vaapi_check_status (status, "vaDestroySubpicture()"))
+      GST_WARNING ("failed to destroy subpicture %" GST_VAAPI_ID_FORMAT,
+          GST_VAAPI_ID_ARGS (subpicture_id));
+    subpicture->object_id = VA_INVALID_ID;
+  }
+
+  if (subpicture->image)
+    gst_mini_object_replace ((GstMiniObject **) & subpicture->image, NULL);
+}
+
+static void
+gst_vaapi_subpicture_free (GstVaapiSubpicture * subpicture)
+{
+  gst_vaapi_subpicture_free_image (subpicture);
+  gst_vaapi_display_replace (&subpicture->display, NULL);
+  g_slice_free1 (sizeof (GstVaapiSubpicture), subpicture);
+}
+
+GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiSubpicture, gst_vaapi_subpicture);
+
+static gboolean
+gst_vaapi_subpicture_bind_image (GstVaapiSubpicture * subpicture,
+    GstVaapiImage * image)
+{
+  GstVaapiDisplay *const display = subpicture->display;
+  VASubpictureID subpicture_id;
+  VAStatus status;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaCreateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_IMAGE_ID (image), &subpicture_id);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaCreateSubpicture()"))
+    return FALSE;
+
+  GST_DEBUG ("subpicture %" GST_VAAPI_ID_FORMAT,
+      GST_VAAPI_ID_ARGS (subpicture_id));
+  subpicture->object_id = subpicture_id;
+  subpicture->image =
+      (GstVaapiImage *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (image));
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_subpicture_new:
+ * @image: a #GstVaapiImage
+ * @flags: #GstVaapiSubpictureFlags, or zero
+ *
+ * Creates a new #GstVaapiSubpicture with @image as source pixels. The
+ * newly created object holds a reference on @image.
+ *
+ * Return value: the newly allocated #GstVaapiSubpicture object
+ */
+GstVaapiSubpicture *
+gst_vaapi_subpicture_new (GstVaapiImage * image, guint flags)
+{
+  GstVaapiSubpicture *subpicture;
+  GstVaapiDisplay *display;
+  GstVideoFormat format;
+  guint va_flags;
+
+  g_return_val_if_fail (image != NULL, NULL);
+
+  GST_DEBUG ("create from image %" GST_VAAPI_ID_FORMAT,
+      GST_VAAPI_ID_ARGS (GST_VAAPI_IMAGE_ID (image)));
+
+  display = GST_VAAPI_IMAGE_DISPLAY (image);
+  format = GST_VAAPI_IMAGE_FORMAT (image);
+  if (!gst_vaapi_display_has_subpicture_format (display, format, &va_flags))
+    return NULL;
+  if (flags & ~va_flags)
+    return NULL;
+
+  subpicture = g_slice_new (GstVaapiSubpicture);
+  if (!subpicture)
+    return NULL;
+
+  gst_mini_object_init (GST_MINI_OBJECT_CAST (subpicture), 0,
+      GST_TYPE_VAAPI_SUBPICTURE, NULL, NULL,
+      (GstMiniObjectFreeFunction) gst_vaapi_subpicture_free);
+  subpicture->display = gst_object_ref (display);
+  subpicture->object_id = VA_INVALID_ID;
+  subpicture->flags = flags;
+  subpicture->global_alpha = 1.0f;
+
+  if (!gst_vaapi_subpicture_bind_image (subpicture, image))
+    goto error;
+  return subpicture;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_subpicture_unref (subpicture);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_subpicture_new_from_overlay_rectangle:
+ * @display: a #GstVaapiDisplay
+ * @rect: a #GstVideoOverlayRectangle
+ *
+ * Helper function that creates a new #GstVaapiSubpicture from a
+ * #GstVideoOverlayRectangle. A new #GstVaapiImage is also created
+ * along the way and attached to the resulting subpicture. The
+ * subpicture holds a unique reference to the underlying image.
+ *
+ * Return value: the newly allocated #GstVaapiSubpicture object
+ */
+GstVaapiSubpicture *
+gst_vaapi_subpicture_new_from_overlay_rectangle (GstVaapiDisplay * display,
+    GstVideoOverlayRectangle * rect)
+{
+  GstVaapiSubpicture *subpicture;
+  GstVideoFormat format;
+  GstVaapiImage *image;
+  GstVaapiImageRaw raw_image;
+  GstBuffer *buffer;
+  guint8 *data;
+  gfloat global_alpha;
+  guint width, height, stride;
+  guint hw_flags, flags;
+  GstVideoMeta *vmeta;
+  GstMapInfo map_info;
+
+  g_return_val_if_fail (GST_IS_VIDEO_OVERLAY_RECTANGLE (rect), NULL);
+
+  format = GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB;
+
+  if (!gst_vaapi_display_has_subpicture_format (display, format, &hw_flags))
+    return NULL;
+
+  flags =
+      hw_flags &
+      from_GstVideoOverlayFormatFlags (gst_video_overlay_rectangle_get_flags
+      (rect));
+
+  buffer = gst_video_overlay_rectangle_get_pixels_unscaled_argb (rect,
+      to_GstVideoOverlayFormatFlags (flags));
+  if (!buffer)
+    return NULL;
+
+  vmeta = gst_buffer_get_video_meta (buffer);
+  if (!vmeta)
+    return NULL;
+  width = vmeta->width;
+  height = vmeta->height;
+
+  if (!gst_video_meta_map (vmeta, 0, &map_info, (gpointer *) & data,
+          (gint *) & stride, GST_MAP_READ))
+    return NULL;
+
+  image = gst_vaapi_image_new (display, format, width, height);
+  if (!image)
+    return NULL;
+
+  raw_image.format = format;
+  raw_image.width = width;
+  raw_image.height = height;
+  raw_image.num_planes = 1;
+  raw_image.pixels[0] = data;
+  raw_image.stride[0] = stride;
+  if (!gst_vaapi_image_update_from_raw (image, &raw_image, NULL)) {
+    GST_WARNING ("could not update VA image with subtitle data");
+    gst_vaapi_image_unref (image);
+    return NULL;
+  }
+
+  subpicture = gst_vaapi_subpicture_new (image, flags);
+  gst_vaapi_image_unref (image);
+  gst_video_meta_unmap (vmeta, 0, &map_info);
+  if (!subpicture)
+    return NULL;
+
+  if (flags & GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA) {
+    global_alpha = gst_video_overlay_rectangle_get_global_alpha (rect);
+    if (!gst_vaapi_subpicture_set_global_alpha (subpicture, global_alpha))
+      return NULL;
+  }
+  return subpicture;
+}
+
+/**
+ * gst_vaapi_subpicture_get_id:
+ * @subpicture: a #GstVaapiSubpicture
+ *
+ * Returns the underlying VASubpictureID of the @subpicture.
+ *
+ * Return value: the underlying VA subpicture id
+ */
+GstVaapiID
+gst_vaapi_subpicture_get_id (GstVaapiSubpicture * subpicture)
+{
+  g_return_val_if_fail (subpicture != NULL, VA_INVALID_ID);
+
+  return subpicture->object_id;
+}
+
+/**
+ * gst_vaapi_subpicture_get_flags:
+ * @subpicture: a #GstVaapiSubpicture
+ *
+ * Returns the @subpicture flags.
+ *
+ * Return value: the @subpicture flags
+ */
+guint
+gst_vaapi_subpicture_get_flags (GstVaapiSubpicture * subpicture)
+{
+  g_return_val_if_fail (subpicture != NULL, 0);
+
+  return subpicture->flags;
+}
+
+/**
+ * gst_vaapi_subpicture_get_image:
+ * @subpicture: a #GstVaapiSubpicture
+ *
+ * Returns the #GstVaapiImage this @subpicture is bound to.
+ *
+ * Return value: the #GstVaapiImage this @subpicture is bound to
+ */
+GstVaapiImage *
+gst_vaapi_subpicture_get_image (GstVaapiSubpicture * subpicture)
+{
+  g_return_val_if_fail (subpicture != NULL, NULL);
+
+  return subpicture->image;
+}
+
+/**
+ * gst_vaapi_subpicture_set_image:
+ * @subpicture: a #GstVaapiSubpicture
+ * @image: a #GstVaapiImage
+ *
+ * Binds a new #GstVaapiImage to the @subpicture. The reference to the
+ * previous image is released and a new one is acquired on @image.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_subpicture_set_image (GstVaapiSubpicture * subpicture,
+    GstVaapiImage * image)
+{
+  g_return_val_if_fail (subpicture != NULL, FALSE);
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  gst_vaapi_subpicture_free_image (subpicture);
+  return gst_vaapi_subpicture_bind_image (subpicture, image);
+}
+
+/**
+ * gst_vaapi_subpicture_get_global_alpha:
+ * @subpicture: a #GstVaapiSubpicture
+ *
+ * Returns the value of global_alpha, set for this @subpicture.
+ *
+ * Return value: the global_alpha value of this @subpicture
+ */
+gfloat
+gst_vaapi_subpicture_get_global_alpha (GstVaapiSubpicture * subpicture)
+{
+  g_return_val_if_fail (subpicture != NULL, 1.0);
+
+  return subpicture->global_alpha;
+}
+
+/**
+ * gst_vaapi_subpicture_set_global_alpha:
+ * @subpicture: a #GstVaapiSubpicture
+ * @global_alpha: value for global-alpha (range: 0.0 to 1.0, inclusive)
+ *
+ * Sets the global_alpha value of @subpicture. This function calls
+ * vaSetSubpictureGlobalAlpha() if the format of @subpicture, i.e.
+ * the current VA driver supports it.
+ *
+ * Return value: %TRUE if global_alpha could be set, %FALSE otherwise
+ */
+gboolean
+gst_vaapi_subpicture_set_global_alpha (GstVaapiSubpicture * subpicture,
+    gfloat global_alpha)
+{
+  GstVaapiDisplay *display;
+  VAStatus status;
+
+  g_return_val_if_fail (subpicture != NULL, FALSE);
+
+  if (!(subpicture->flags & GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA))
+    return FALSE;
+
+  if (subpicture->global_alpha == global_alpha)
+    return TRUE;
+
+  display = subpicture->display;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaSetSubpictureGlobalAlpha (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      subpicture->object_id, global_alpha);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaSetSubpictureGlobalAlpha()"))
+    return FALSE;
+
+  subpicture->global_alpha = global_alpha;
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisubpicture.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisubpicture.h
new file mode 100644 (file)
index 0000000..d61314d
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *  gstvaapisubpicture.h - VA subpicture abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_SUBPICTURE_H
+#define GST_VAAPI_SUBPICTURE_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiimage.h>
+#include <gst/video/video-overlay-composition.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_SUBPICTURE(obj) \
+    ((GstVaapiSubpicture *)(obj))
+
+typedef struct _GstVaapiSubpicture              GstVaapiSubpicture;
+
+/**
+ * GstVaapiSubpictureFlags:
+ * @GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA:
+ *   subpicture has RGB pixels with pre-multiplied alpha
+ * @GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA:
+ *   subpicture needs to be blended with some global-alpha value at
+ *   rendering time
+ *
+ * The set of all subpicture rendering flags for #GstVaapiSubpicture.
+ */
+typedef enum {
+    GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA    = (1 << 0),
+    GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA           = (1 << 1),
+} GstVaapiSubpictureFlags;
+
+#define GST_TYPE_VAAPI_SUBPICTURE (gst_vaapi_subpicture_get_type ())
+
+#define GST_VAAPI_SUBPICTURE_ID(subpicture)      (gst_vaapi_subpicture_get_id (subpicture))
+
+GType
+gst_vaapi_subpicture_get_type (void) G_GNUC_CONST;
+
+/**
+ * gst_vaapi_subpicture_unref: (skip)
+ * @subpicture: (transfer full): a #GstVaapiSubpicture.
+ *
+ * Decreases the refcount of the subpicture. If the refcount reaches 0, the
+ * subpicture will be freed.
+ */
+static inline void
+gst_vaapi_subpicture_unref (GstVaapiSubpicture *subpicture)
+{
+  gst_mini_object_unref (GST_MINI_OBJECT_CAST (subpicture));
+}
+
+GstVaapiSubpicture *
+gst_vaapi_subpicture_new(GstVaapiImage *image, guint flags);
+
+GstVaapiSubpicture *
+gst_vaapi_subpicture_new_from_overlay_rectangle(
+    GstVaapiDisplay          *display,
+    GstVideoOverlayRectangle *rect
+);
+
+GstVaapiID
+gst_vaapi_subpicture_get_id(GstVaapiSubpicture *subpicture);
+
+guint
+gst_vaapi_subpicture_get_flags(GstVaapiSubpicture *subpicture);
+
+GstVaapiImage *
+gst_vaapi_subpicture_get_image(GstVaapiSubpicture *subpicture);
+
+gboolean
+gst_vaapi_subpicture_set_image(GstVaapiSubpicture *subpicture,
+    GstVaapiImage *image);
+
+gfloat
+gst_vaapi_subpicture_get_global_alpha(GstVaapiSubpicture *subpicture);
+
+gboolean
+gst_vaapi_subpicture_set_global_alpha(GstVaapiSubpicture *subpicture,
+    gfloat global_alpha);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiSubpicture, gst_vaapi_subpicture_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_SUBPICTURE_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface.c
new file mode 100644 (file)
index 0000000..0fdafd9
--- /dev/null
@@ -0,0 +1,1094 @@
+/*
+ *  gstvaapisurface.c - VA surface abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapisurface
+ * @short_description: VA surface abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+#include "gstvaapisurface.h"
+#include "gstvaapisurface_priv.h"
+#include "gstvaapicontext.h"
+#include "gstvaapiimage.h"
+#include "gstvaapiimage_priv.h"
+#include "gstvaapibufferproxy_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+static gboolean
+_gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface,
+    GstVaapiSubpicture * subpicture, const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect);
+
+static gboolean
+_gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface,
+    GstVaapiSubpicture * subpicture);
+
+static void
+destroy_subpicture_cb (gpointer subpicture, gpointer surface)
+{
+  _gst_vaapi_surface_deassociate_subpicture (surface, subpicture);
+  gst_vaapi_subpicture_unref (subpicture);
+}
+
+static void
+gst_vaapi_surface_destroy_subpictures (GstVaapiSurface * surface)
+{
+  if (surface->subpictures) {
+    g_ptr_array_foreach (surface->subpictures, destroy_subpicture_cb, surface);
+    g_clear_pointer (&surface->subpictures, g_ptr_array_unref);
+  }
+}
+
+static void
+gst_vaapi_surface_free (GstVaapiSurface * surface)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  VASurfaceID surface_id;
+  VAStatus status;
+
+  surface_id = GST_VAAPI_SURFACE_ID (surface);
+  GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
+
+  gst_vaapi_surface_destroy_subpictures (surface);
+
+  if (surface_id != VA_INVALID_SURFACE) {
+    GST_VAAPI_DISPLAY_LOCK (display);
+    status = vaDestroySurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
+        &surface_id, 1);
+    GST_VAAPI_DISPLAY_UNLOCK (display);
+    if (!vaapi_check_status (status, "vaDestroySurfaces()"))
+      GST_WARNING ("failed to destroy surface %" GST_VAAPI_ID_FORMAT,
+          GST_VAAPI_ID_ARGS (surface_id));
+    GST_VAAPI_SURFACE_ID (surface) = VA_INVALID_SURFACE;
+  }
+  gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, NULL);
+  gst_vaapi_display_replace (&GST_VAAPI_SURFACE_DISPLAY (surface), NULL);
+
+  g_slice_free1 (sizeof (GstVaapiSurface), surface);
+}
+
+static gboolean
+gst_vaapi_surface_init (GstVaapiSurface * surface,
+    GstVaapiChromaType chroma_type, guint width, guint height)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  VASurfaceID surface_id;
+  VAStatus status;
+  guint va_chroma_format;
+
+  va_chroma_format = from_GstVaapiChromaType (chroma_type);
+  if (!va_chroma_format)
+    goto error_unsupported_chroma_type;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      width, height, va_chroma_format, 1, &surface_id);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaCreateSurfaces()"))
+    return FALSE;
+
+  GST_VAAPI_SURFACE_FORMAT (surface) = GST_VIDEO_FORMAT_UNKNOWN;
+  GST_VAAPI_SURFACE_CHROMA_TYPE (surface) = chroma_type;
+  GST_VAAPI_SURFACE_WIDTH (surface) = width;
+  GST_VAAPI_SURFACE_HEIGHT (surface) = height;
+
+  GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
+  GST_VAAPI_SURFACE_ID (surface) = surface_id;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_chroma_type:
+  GST_ERROR ("unsupported chroma-type %u", chroma_type);
+  return FALSE;
+}
+
+static guint
+get_usage_hint (guint alloc_flags)
+{
+  guint usage_hints = VA_SURFACE_ATTRIB_USAGE_HINT_GENERIC;
+
+  /* XXX(victor): So far, only media-driver uses hints for encoders
+   * and it doesn't test it as bitwise */
+  if (alloc_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_DECODER)
+    usage_hints = VA_SURFACE_ATTRIB_USAGE_HINT_DECODER;
+  else if (alloc_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_ENCODER)
+    usage_hints = VA_SURFACE_ATTRIB_USAGE_HINT_ENCODER;
+
+  return usage_hints;
+}
+
+static gboolean
+gst_vaapi_surface_init_full (GstVaapiSurface * surface,
+    const GstVideoInfo * vip, guint surface_allocation_flags)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  const GstVideoFormat format = GST_VIDEO_INFO_FORMAT (vip);
+  VASurfaceID surface_id;
+  VAStatus status;
+  guint chroma_type, va_chroma_format, i;
+  const VAImageFormat *va_format;
+  VASurfaceAttrib attribs[4], *attrib;
+  VASurfaceAttribExternalBuffers extbuf = { 0, };
+  gboolean extbuf_needed = FALSE;
+
+  va_format = gst_vaapi_video_format_to_va_format (format);
+  if (!va_format)
+    goto error_unsupported_format;
+
+  chroma_type = gst_vaapi_video_format_get_chroma_type (format);
+  if (!chroma_type)
+    goto error_unsupported_format;
+
+  va_chroma_format = from_GstVaapiChromaType (chroma_type);
+  if (!va_chroma_format)
+    goto error_unsupported_format;
+
+  extbuf.pixel_format = va_format->fourcc;
+  extbuf.width = GST_VIDEO_INFO_WIDTH (vip);
+  extbuf.height = GST_VIDEO_INFO_HEIGHT (vip);
+  if (surface_allocation_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE) {
+    extbuf.flags &= ~VA_SURFACE_EXTBUF_DESC_ENABLE_TILING;
+    extbuf_needed = TRUE;
+  }
+
+  extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip);
+  if (surface_allocation_flags & (GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES |
+          GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS)) {
+    for (i = 0; i < extbuf.num_planes; i++) {
+      if (surface_allocation_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES)
+        extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i);
+      if (surface_allocation_flags & GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS)
+        extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i);
+    }
+    extbuf_needed = TRUE;
+  }
+
+  attrib = attribs;
+  attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
+  attrib->type = VASurfaceAttribPixelFormat;
+  attrib->value.type = VAGenericValueTypeInteger;
+  attrib->value.value.i = va_format->fourcc;
+  attrib++;
+
+  attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
+  attrib->type = VASurfaceAttribUsageHint;
+  attrib->value.type = VAGenericValueTypeInteger;
+  attrib->value.value.i = get_usage_hint (surface_allocation_flags);
+  attrib++;
+
+  if (extbuf_needed) {
+    attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
+    attrib->type = VASurfaceAttribMemoryType;
+    attrib->value.type = VAGenericValueTypeInteger;
+    attrib->value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_VA;
+    attrib++;
+
+    attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
+    attrib->type = VASurfaceAttribExternalBufferDescriptor;
+    attrib->value.type = VAGenericValueTypePointer;
+    attrib->value.value.p = &extbuf;
+    attrib++;
+  }
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      va_chroma_format, extbuf.width, extbuf.height, &surface_id, 1,
+      attribs, attrib - attribs);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaCreateSurfaces()"))
+    return FALSE;
+
+  GST_VAAPI_SURFACE_FORMAT (surface) = format;
+  GST_VAAPI_SURFACE_CHROMA_TYPE (surface) = chroma_type;
+  GST_VAAPI_SURFACE_WIDTH (surface) = extbuf.width;
+  GST_VAAPI_SURFACE_HEIGHT (surface) = extbuf.height;
+
+  GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
+  GST_VAAPI_SURFACE_ID (surface) = surface_id;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_format:
+  GST_ERROR ("unsupported format %s",
+      gst_vaapi_video_format_to_string (format));
+  return FALSE;
+}
+
+static gboolean
+gst_vaapi_surface_init_from_buffer_proxy (GstVaapiSurface * surface,
+    GstVaapiBufferProxy * proxy, const GstVideoInfo * vip)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  GstVideoFormat format;
+  VASurfaceID surface_id;
+  VAStatus status;
+  guint chroma_type, va_chroma_format;
+  const VAImageFormat *va_format;
+  VASurfaceAttrib attribs[2], *attrib;
+  VASurfaceAttribExternalBuffers extbuf = { 0, };
+  unsigned long extbuf_handle;
+  guint i, width, height;
+
+  format = GST_VIDEO_INFO_FORMAT (vip);
+  width = GST_VIDEO_INFO_WIDTH (vip);
+  height = GST_VIDEO_INFO_HEIGHT (vip);
+
+  gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, proxy);
+
+  va_format = gst_vaapi_video_format_to_va_format (format);
+  if (!va_format)
+    goto error_unsupported_format;
+
+  chroma_type = gst_vaapi_video_format_get_chroma_type (format);
+  if (!chroma_type)
+    goto error_unsupported_format;
+
+  va_chroma_format = from_GstVaapiChromaType (chroma_type);
+  if (!va_chroma_format)
+    goto error_unsupported_format;
+
+  extbuf_handle = GST_VAAPI_BUFFER_PROXY_HANDLE (proxy);
+  extbuf.pixel_format = va_format->fourcc;
+  extbuf.width = width;
+  extbuf.height = height;
+  extbuf.data_size = GST_VAAPI_BUFFER_PROXY_SIZE (proxy);
+  extbuf.num_planes = GST_VIDEO_INFO_N_PLANES (vip);
+  for (i = 0; i < extbuf.num_planes; i++) {
+    extbuf.pitches[i] = GST_VIDEO_INFO_PLANE_STRIDE (vip, i);
+    extbuf.offsets[i] = GST_VIDEO_INFO_PLANE_OFFSET (vip, i);
+  }
+  extbuf.buffers = (uintptr_t *) & extbuf_handle;
+  extbuf.num_buffers = 1;
+  extbuf.flags = 0;
+  extbuf.private_data = NULL;
+
+  attrib = attribs;
+  attrib->type = VASurfaceAttribExternalBufferDescriptor;
+  attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
+  attrib->value.type = VAGenericValueTypePointer;
+  attrib->value.value.p = &extbuf;
+  attrib++;
+  attrib->type = VASurfaceAttribMemoryType;
+  attrib->flags = VA_SURFACE_ATTRIB_SETTABLE;
+  attrib->value.type = VAGenericValueTypeInteger;
+  attrib->value.value.i =
+      from_GstVaapiBufferMemoryType (GST_VAAPI_BUFFER_PROXY_TYPE (proxy));
+  attrib++;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaCreateSurfaces (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      va_chroma_format, width, height, &surface_id, 1, attribs,
+      attrib - attribs);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaCreateSurfaces()"))
+    return FALSE;
+
+  GST_VAAPI_SURFACE_FORMAT (surface) = format;
+  GST_VAAPI_SURFACE_CHROMA_TYPE (surface) = chroma_type;
+  GST_VAAPI_SURFACE_WIDTH (surface) = width;
+  GST_VAAPI_SURFACE_HEIGHT (surface) = height;
+
+  GST_DEBUG ("surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id));
+  GST_VAAPI_SURFACE_ID (surface) = surface_id;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_format:
+  GST_ERROR ("unsupported format %s",
+      gst_vaapi_video_format_to_string (format));
+  return FALSE;
+}
+
+GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiSurface, gst_vaapi_surface);
+
+static GstVaapiSurface *
+gst_vaapi_surface_create (GstVaapiDisplay * display)
+{
+  GstVaapiSurface *surface = g_slice_new (GstVaapiSurface);
+  if (!surface)
+    return NULL;
+
+  gst_mini_object_init (GST_MINI_OBJECT_CAST (surface), 0,
+      GST_TYPE_VAAPI_SURFACE, NULL, NULL,
+      (GstMiniObjectFreeFunction) gst_vaapi_surface_free);
+
+  GST_VAAPI_SURFACE_DISPLAY (surface) = gst_object_ref (display);
+  GST_VAAPI_SURFACE_ID (surface) = VA_INVALID_ID;
+  surface->extbuf_proxy = NULL;
+  surface->subpictures = NULL;
+
+  return surface;
+}
+
+/**
+ * gst_vaapi_surface_get_display:
+ * @surface: a #GstVaapiSurface
+ *
+ * Returns the #GstVaapiDisplay this @surface is bound to.
+ *
+ * Return value: the parent #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_surface_get_display (GstVaapiSurface * surface)
+{
+  g_return_val_if_fail (surface != NULL, NULL);
+  return GST_VAAPI_SURFACE_DISPLAY (surface);
+}
+
+/**
+ * gst_vaapi_surface_new:
+ * @display: a #GstVaapiDisplay
+ * @chroma_type: the surface chroma format
+ * @width: the requested surface width
+ * @height: the requested surface height
+ *
+ * Creates a new #GstVaapiSurface with the specified chroma format and
+ * dimensions.
+ *
+ * NOTE: this method for creating surfaces uses deprecated VA API,
+ * which is still used by drivers (v.gr. i965 for jpeg decoding).
+ *
+ * Return value: the newly allocated #GstVaapiSurface object
+ */
+GstVaapiSurface *
+gst_vaapi_surface_new (GstVaapiDisplay * display,
+    GstVaapiChromaType chroma_type, guint width, guint height)
+{
+  GstVaapiSurface *surface;
+
+  GST_DEBUG ("size %ux%u, chroma type 0x%x", width, height, chroma_type);
+
+  surface = gst_vaapi_surface_create (display);
+  if (!surface)
+    return NULL;
+
+  if (!gst_vaapi_surface_init (surface, chroma_type, width, height))
+    goto error;
+  return surface;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_surface_unref (surface);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_surface_new_full:
+ * @display: a #GstVaapiDisplay
+ * @vip: the pointer to a #GstVideoInfo
+ * @surface_allocation_flags: (optional) allocation flags
+ *
+ * Creates a new #GstVaapiSurface with the specified video information
+ * and optional #GstVaapiSurfaceAllocFlags
+ *
+ * Return value: the newly allocated #GstVaapiSurface object, or %NULL
+ *   if creation of VA surface with explicit pixel format is not
+ *   supported or failed.
+ */
+GstVaapiSurface *
+gst_vaapi_surface_new_full (GstVaapiDisplay * display, const GstVideoInfo * vip,
+    guint surface_allocation_flags)
+{
+  GstVaapiSurface *surface;
+
+  GST_DEBUG ("size %ux%u, format %s, flags 0x%08x", GST_VIDEO_INFO_WIDTH (vip),
+      GST_VIDEO_INFO_HEIGHT (vip),
+      gst_vaapi_video_format_to_string (GST_VIDEO_INFO_FORMAT (vip)),
+      surface_allocation_flags);
+
+  surface = gst_vaapi_surface_create (display);
+  if (!surface)
+    return NULL;
+
+  if (!gst_vaapi_surface_init_full (surface, vip, surface_allocation_flags))
+    goto error;
+  return surface;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_surface_unref (surface);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_surface_new_with_format:
+ * @display: a #GstVaapiDisplay
+ * @format: the surface format
+ * @width: the requested surface width
+ * @height: the requested surface height
+ * @surface_allocation_flags: (optional) allocation flags
+ *
+ * Creates a new #GstVaapiSurface with the specified pixel format and
+ * dimensions.
+ *
+ * Return value: the newly allocated #GstVaapiSurface object, or %NULL
+ *   if creation of VA surface with explicit pixel format is not
+ *   supported or failed.
+ */
+GstVaapiSurface *
+gst_vaapi_surface_new_with_format (GstVaapiDisplay * display,
+    GstVideoFormat format, guint width, guint height,
+    guint surface_allocation_flags)
+{
+  GstVideoInfo vi;
+
+  gst_video_info_set_format (&vi, format, width, height);
+  return gst_vaapi_surface_new_full (display, &vi, surface_allocation_flags);
+}
+
+/**
+ * gst_vaapi_surface_new_from_buffer_proxy:
+ * @display: a #GstVaapiDisplay
+ * @proxy: a #GstVaapiBufferProxy
+ * @info: the #GstVideoInfo structure defining the layout of the buffer
+ *
+ * Creates a new #GstVaapiSurface with the supplied VA buffer proxy
+ * abstraction. The underlying VA buffer memory type could be anything
+ * that is supported by the VA driver.
+ *
+ * The resulting #GstVaapiSurface object owns an extra reference to
+ * the buffer @proxy, so the caller can safely release that handle as
+ * early as on return of this call.
+ *
+ * Return value: the newly allocated #GstVaapiSurface object, or %NULL
+ *   if creation of VA surface failed or is not supported
+ */
+GstVaapiSurface *
+gst_vaapi_surface_new_from_buffer_proxy (GstVaapiDisplay * display,
+    GstVaapiBufferProxy * proxy, const GstVideoInfo * info)
+{
+  GstVaapiSurface *surface;
+
+  g_return_val_if_fail (proxy != NULL, NULL);
+  g_return_val_if_fail (info != NULL, NULL);
+  g_return_val_if_fail (!proxy->surface, NULL);
+
+  surface = gst_vaapi_surface_create (display);
+  if (!surface)
+    return NULL;
+
+  if (!gst_vaapi_surface_init_from_buffer_proxy (surface, proxy, info))
+    goto error;
+
+  proxy->surface = GST_MINI_OBJECT_CAST (surface);
+  return surface;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_surface_unref (surface);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_surface_get_id:
+ * @surface: a #GstVaapiSurface
+ *
+ * Returns the underlying VASurfaceID of the @surface.
+ *
+ * Return value: the underlying VA surface id
+ */
+GstVaapiID
+gst_vaapi_surface_get_id (GstVaapiSurface * surface)
+{
+  g_return_val_if_fail (surface != NULL, VA_INVALID_SURFACE);
+
+  return GST_VAAPI_SURFACE_ID (surface);
+}
+
+/**
+ * gst_vaapi_surface_get_chroma_type:
+ * @surface: a #GstVaapiSurface
+ *
+ * Returns the #GstVaapiChromaType the @surface was created with.
+ *
+ * Return value: the #GstVaapiChromaType
+ */
+GstVaapiChromaType
+gst_vaapi_surface_get_chroma_type (GstVaapiSurface * surface)
+{
+  g_return_val_if_fail (surface != NULL, 0);
+
+  return GST_VAAPI_SURFACE_CHROMA_TYPE (surface);
+}
+
+/**
+ * gst_vaapi_surface_get_format:
+ * @surface: a #GstVaapiSurface
+ *
+ * Returns the #GstVideoFormat the @surface was created with.
+ *
+ * Return value: the #GstVideoFormat, or %GST_VIDEO_FORMAT_ENCODED if
+ *   the surface was not created with an explicit video format, or if
+ *   the underlying video format could not be determined
+ */
+GstVideoFormat
+gst_vaapi_surface_get_format (GstVaapiSurface * surface)
+{
+  g_return_val_if_fail (surface != NULL, 0);
+
+  /* Try to determine the underlying VA surface format */
+  if (GST_VAAPI_SURFACE_FORMAT (surface) == GST_VIDEO_FORMAT_UNKNOWN) {
+    GstVaapiImage *const image = gst_vaapi_surface_derive_image (surface);
+    if (image) {
+      GST_VAAPI_SURFACE_FORMAT (surface) = GST_VAAPI_IMAGE_FORMAT (image);
+      gst_vaapi_image_unref (image);
+    }
+    if (GST_VAAPI_SURFACE_FORMAT (surface) == GST_VIDEO_FORMAT_UNKNOWN)
+      GST_VAAPI_SURFACE_FORMAT (surface) = GST_VIDEO_FORMAT_ENCODED;
+  }
+  return GST_VAAPI_SURFACE_FORMAT (surface);
+}
+
+/**
+ * gst_vaapi_surface_get_width:
+ * @surface: a #GstVaapiSurface
+ *
+ * Returns the @surface width.
+ *
+ * Return value: the surface width, in pixels
+ */
+guint
+gst_vaapi_surface_get_width (GstVaapiSurface * surface)
+{
+  g_return_val_if_fail (surface != NULL, 0);
+
+  return GST_VAAPI_SURFACE_WIDTH (surface);
+}
+
+/**
+ * gst_vaapi_surface_get_height:
+ * @surface: a #GstVaapiSurface
+ *
+ * Returns the @surface height.
+ *
+ * Return value: the surface height, in pixels.
+ */
+guint
+gst_vaapi_surface_get_height (GstVaapiSurface * surface)
+{
+  g_return_val_if_fail (surface != NULL, 0);
+
+  return GST_VAAPI_SURFACE_HEIGHT (surface);
+}
+
+/**
+ * gst_vaapi_surface_get_size:
+ * @surface: a #GstVaapiSurface
+ * @width_ptr: return location for the width, or %NULL
+ * @height_ptr: return location for the height, or %NULL
+ *
+ * Retrieves the dimensions of a #GstVaapiSurface.
+ */
+void
+gst_vaapi_surface_get_size (GstVaapiSurface * surface,
+    guint * width_ptr, guint * height_ptr)
+{
+  g_return_if_fail (surface != NULL);
+
+  if (width_ptr)
+    *width_ptr = GST_VAAPI_SURFACE_WIDTH (surface);
+
+  if (height_ptr)
+    *height_ptr = GST_VAAPI_SURFACE_HEIGHT (surface);
+}
+
+/**
+ * gst_vaapi_surface_derive_image:
+ * @surface: a #GstVaapiSurface
+ *
+ * Derives a #GstVaapiImage from the @surface. This image buffer can
+ * then be mapped/unmapped for direct CPU access. This operation is
+ * only possible if the underlying implementation supports direct
+ * rendering capabilities and internal surface formats that can be
+ * represented with a #GstVaapiImage.
+ *
+ * When the operation is not possible, the function returns %NULL and
+ * the user should then fallback to using gst_vaapi_surface_get_image()
+ * or gst_vaapi_surface_put_image() to accomplish the same task in an
+ * indirect manner (additional copy).
+ *
+ * An image created with gst_vaapi_surface_derive_image() should be
+ * unreferenced when it's no longer needed. The image and image buffer
+ * data structures will be destroyed. However, the surface contents
+ * will remain unchanged until destroyed through the last call to
+ * gst_vaapi_image_unref().
+ *
+ * Return value: the newly allocated #GstVaapiImage object, or %NULL
+ *   on failure
+ */
+GstVaapiImage *
+gst_vaapi_surface_derive_image (GstVaapiSurface * surface)
+{
+  GstVaapiDisplay *display;
+  VAImage va_image;
+  VAStatus status;
+  GstVaapiImage *image;
+
+  g_return_val_if_fail (surface != NULL, NULL);
+
+  display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  va_image.image_id = VA_INVALID_ID;
+  va_image.buf = VA_INVALID_ID;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaDeriveImage (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_SURFACE_ID (surface), &va_image);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaDeriveImage()"))
+    return NULL;
+  if (va_image.image_id == VA_INVALID_ID || va_image.buf == VA_INVALID_ID)
+    return NULL;
+
+  image = gst_vaapi_image_new_with_image (display, &va_image);
+  if (!image)
+    vaDestroyImage (GST_VAAPI_DISPLAY_VADISPLAY (display), va_image.image_id);
+  return image;
+}
+
+/**
+ * gst_vaapi_surface_get_image
+ * @surface: a #GstVaapiSurface
+ * @image: a #GstVaapiImage
+ *
+ * Retrieves surface data into a #GstVaapiImage. The @image must have
+ * a format supported by the @surface.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_surface_get_image (GstVaapiSurface * surface, GstVaapiImage * image)
+{
+  GstVaapiDisplay *display;
+  VAImageID image_id;
+  VAStatus status;
+  guint width, height;
+
+  g_return_val_if_fail (surface != NULL, FALSE);
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  if (!display)
+    return FALSE;
+
+  width = GST_VAAPI_IMAGE_WIDTH (image);
+  height = GST_VAAPI_IMAGE_HEIGHT (image);
+  if (width != GST_VAAPI_SURFACE_WIDTH (surface)
+      || height != GST_VAAPI_SURFACE_HEIGHT (surface))
+    return FALSE;
+
+  image_id = GST_VAAPI_IMAGE_ID (image);
+  if (image_id == VA_INVALID_ID)
+    return FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaGetImage (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_SURFACE_ID (surface), 0, 0, width, height, image_id);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaGetImage()"))
+    return FALSE;
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_surface_put_image:
+ * @surface: a #GstVaapiSurface
+ * @image: a #GstVaapiImage
+ *
+ * Copies data from a #GstVaapiImage into a @surface. The @image must
+ * have a format supported by the @surface.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_surface_put_image (GstVaapiSurface * surface, GstVaapiImage * image)
+{
+  GstVaapiDisplay *display;
+  VAImageID image_id;
+  VAStatus status;
+  guint width, height;
+
+  g_return_val_if_fail (surface != NULL, FALSE);
+  g_return_val_if_fail (image != NULL, FALSE);
+
+  display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  if (!display)
+    return FALSE;
+
+  width = GST_VAAPI_IMAGE_WIDTH (image);
+  height = GST_VAAPI_IMAGE_HEIGHT (image);
+  if (width != GST_VAAPI_SURFACE_WIDTH (surface)
+      || height != GST_VAAPI_SURFACE_HEIGHT (surface))
+    return FALSE;
+
+  image_id = GST_VAAPI_IMAGE_ID (image);
+  if (image_id == VA_INVALID_ID)
+    return FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaPutImage (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_SURFACE_ID (surface), image_id, 0, 0, width, height, 0, 0,
+      width, height);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaPutImage()"))
+    return FALSE;
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_surface_associate_subpicture:
+ * @surface: a #GstVaapiSurface
+ * @subpicture: a #GstVaapiSubpicture
+ * @src_rect: the sub-rectangle of the source subpicture
+ *   image to extract and process. If %NULL, the entire image will be used.
+ * @dst_rect: the sub-rectangle of the destination
+ *   surface into which the image is rendered. If %NULL, the entire
+ *   surface will be used.
+ *
+ * Associates the @subpicture with the @surface. The @src_rect
+ * coordinates and size are relative to the source image bound to
+ * @subpicture. The @dst_rect coordinates and size are relative to the
+ * target @surface. Note that the @surface holds an additional
+ * reference to the @subpicture.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface,
+    GstVaapiSubpicture * subpicture,
+    const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect)
+{
+  gboolean success;
+
+  g_return_val_if_fail (surface != NULL, FALSE);
+  g_return_val_if_fail (subpicture != NULL, FALSE);
+
+  if (!surface->subpictures) {
+    surface->subpictures = g_ptr_array_new ();
+    if (!surface->subpictures)
+      return FALSE;
+  }
+
+  if (g_ptr_array_remove_fast (surface->subpictures, subpicture)) {
+    success = _gst_vaapi_surface_deassociate_subpicture (surface, subpicture);
+    gst_vaapi_subpicture_unref (subpicture);
+    if (!success)
+      return FALSE;
+  }
+
+  success = _gst_vaapi_surface_associate_subpicture (surface,
+      subpicture, src_rect, dst_rect);
+  if (!success)
+    return FALSE;
+
+  g_ptr_array_add (surface->subpictures,
+      gst_mini_object_ref (GST_MINI_OBJECT_CAST (subpicture)));
+  return TRUE;
+}
+
+gboolean
+_gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface,
+    GstVaapiSubpicture * subpicture,
+    const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect)
+{
+  GstVaapiDisplay *display;
+  GstVaapiRectangle src_rect_default, dst_rect_default;
+  GstVaapiImage *image;
+  VASurfaceID surface_id;
+  VAStatus status;
+
+  display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  if (!display)
+    return FALSE;
+
+  surface_id = GST_VAAPI_SURFACE_ID (surface);
+  if (surface_id == VA_INVALID_SURFACE)
+    return FALSE;
+
+  if (!src_rect) {
+    image = gst_vaapi_subpicture_get_image (subpicture);
+    if (!image)
+      return FALSE;
+    src_rect = &src_rect_default;
+    src_rect_default.x = 0;
+    src_rect_default.y = 0;
+    src_rect_default.width = GST_VAAPI_IMAGE_WIDTH (image);
+    src_rect_default.height = GST_VAAPI_IMAGE_HEIGHT (image);
+  }
+
+  if (!dst_rect) {
+    dst_rect = &dst_rect_default;
+    dst_rect_default.x = 0;
+    dst_rect_default.y = 0;
+    dst_rect_default.width = GST_VAAPI_SURFACE_WIDTH (surface);
+    dst_rect_default.height = GST_VAAPI_SURFACE_HEIGHT (surface);
+  }
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaAssociateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_SUBPICTURE_ID (subpicture), &surface_id, 1,
+      src_rect->x, src_rect->y, src_rect->width, src_rect->height,
+      dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height,
+      from_GstVaapiSubpictureFlags (gst_vaapi_subpicture_get_flags
+          (subpicture)));
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaAssociateSubpicture()"))
+    return FALSE;
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_surface_deassociate_subpicture:
+ * @surface: a #GstVaapiSurface
+ * @subpicture: a #GstVaapiSubpicture
+ *
+ * Deassociates @subpicture from @surface. Other associations are kept.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface,
+    GstVaapiSubpicture * subpicture)
+{
+  gboolean success;
+
+  g_return_val_if_fail (surface != NULL, FALSE);
+  g_return_val_if_fail (subpicture != NULL, FALSE);
+
+  if (!surface->subpictures)
+    return TRUE;
+
+  /* First, check subpicture was really associated with this surface */
+  if (!g_ptr_array_remove_fast (surface->subpictures, subpicture)) {
+    GST_DEBUG ("subpicture %" GST_VAAPI_ID_FORMAT " was not bound to "
+        "surface %" GST_VAAPI_ID_FORMAT,
+        GST_VAAPI_ID_ARGS (GST_VAAPI_SUBPICTURE_ID (subpicture)),
+        GST_VAAPI_ID_ARGS (GST_VAAPI_SURFACE_ID (surface)));
+    return TRUE;
+  }
+
+  success = _gst_vaapi_surface_deassociate_subpicture (surface, subpicture);
+  gst_vaapi_subpicture_unref (subpicture);
+  return success;
+}
+
+gboolean
+_gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface,
+    GstVaapiSubpicture * subpicture)
+{
+  GstVaapiDisplay *display;
+  VASurfaceID surface_id;
+  VAStatus status;
+
+  display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  if (!display)
+    return FALSE;
+
+  surface_id = GST_VAAPI_SURFACE_ID (surface);
+  if (surface_id == VA_INVALID_SURFACE)
+    return FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaDeassociateSubpicture (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_SUBPICTURE_ID (subpicture), &surface_id, 1);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaDeassociateSubpicture()"))
+    return FALSE;
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_surface_sync:
+ * @surface: a #GstVaapiSurface
+ *
+ * Blocks until all pending operations on the @surface have been
+ * completed.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_surface_sync (GstVaapiSurface * surface)
+{
+  GstVaapiDisplay *display;
+  VAStatus status;
+
+  g_return_val_if_fail (surface != NULL, FALSE);
+
+  display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  if (!display)
+    return FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaSyncSurface (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_SURFACE_ID (surface));
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaSyncSurface()"))
+    return FALSE;
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_surface_query_status:
+ * @surface: a #GstVaapiSurface
+ * @pstatus: return location for the #GstVaapiSurfaceStatus
+ *
+ * Finds out any pending operations on the @surface. The
+ * #GstVaapiSurfaceStatus flags are returned into @pstatus.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_surface_query_status (GstVaapiSurface * surface,
+    GstVaapiSurfaceStatus * pstatus)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  VASurfaceStatus surface_status;
+  VAStatus status;
+
+  g_return_val_if_fail (surface != NULL, FALSE);
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  status = vaQuerySurfaceStatus (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_SURFACE_ID (surface), &surface_status);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaQuerySurfaceStatus()"))
+    return FALSE;
+
+  if (pstatus)
+    *pstatus = to_GstVaapiSurfaceStatus (surface_status);
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_surface_set_subpictures_from_composition:
+ * @surface: a #GstVaapiSurface
+ * @compostion: a #GstVideoOverlayCompositon
+ *
+ * Helper to update the subpictures from #GstVideoOverlayCompositon. Sending
+ * a NULL composition will clear all the current subpictures. Note that this
+ * method will clear existing subpictures.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_surface_set_subpictures_from_composition (GstVaapiSurface * surface,
+    GstVideoOverlayComposition * composition)
+{
+  GstVaapiDisplay *display;
+  guint n, nb_rectangles;
+
+  g_return_val_if_fail (surface != NULL, FALSE);
+
+  display = GST_VAAPI_SURFACE_DISPLAY (surface);
+  if (!display)
+    return FALSE;
+
+  /* Clear current subpictures */
+  gst_vaapi_surface_destroy_subpictures (surface);
+
+  if (!composition)
+    return TRUE;
+
+  nb_rectangles = gst_video_overlay_composition_n_rectangles (composition);
+
+  /* Overlay all the rectangles cantained in the overlay composition */
+  for (n = 0; n < nb_rectangles; ++n) {
+    GstVideoOverlayRectangle *rect;
+    GstVaapiRectangle sub_rect;
+    GstVaapiSubpicture *subpicture;
+
+    rect = gst_video_overlay_composition_get_rectangle (composition, n);
+    subpicture = gst_vaapi_subpicture_new_from_overlay_rectangle (display,
+        rect);
+    if (subpicture == NULL) {
+      GST_WARNING ("could not create subpicture for rectangle %p", rect);
+      return FALSE;
+    }
+
+    gst_video_overlay_rectangle_get_render_rectangle (rect,
+        (gint *) & sub_rect.x, (gint *) & sub_rect.y,
+        &sub_rect.width, &sub_rect.height);
+
+    /* ensure that the overlay is not bigger than the surface */
+    sub_rect.y = MIN (sub_rect.y, GST_VAAPI_SURFACE_HEIGHT (surface));
+    sub_rect.width = MIN (sub_rect.width, GST_VAAPI_SURFACE_WIDTH (surface));
+
+    if (!gst_vaapi_surface_associate_subpicture (surface, subpicture,
+            NULL, &sub_rect)) {
+      GST_WARNING ("could not render overlay rectangle %p", rect);
+      gst_vaapi_subpicture_unref (subpicture);
+      return FALSE;
+    }
+    gst_vaapi_subpicture_unref (subpicture);
+  }
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_surface_set_buffer_proxy:
+ * @surface: a #GstVaapiSurface
+ * @proxy: an external #GstVaapiBufferProxy
+ *
+ * Replaces the external buffer proxy in @surface with @proxy.
+ *
+ * This is useful when a dmabuf-based memory is instantiated in order
+ * to relate the generated buffer @proxy with the processed @surface.
+ **/
+void
+gst_vaapi_surface_set_buffer_proxy (GstVaapiSurface * surface,
+    GstVaapiBufferProxy * proxy)
+{
+  gst_vaapi_buffer_proxy_replace (&surface->extbuf_proxy, proxy);
+}
+
+/**
+ * gst_vaapi_surface_peek_buffer_proxy:
+ * @surface: a #GstVaapiSurface
+ *
+ * This is useful when a dmabuf-based memory is instantiated in order
+ * to relate the generated buffer @proxy with the processed @surface.
+ *
+ * Returns: (transfer none): the associated external
+ * #GstVaapiBufferProxy
+ **/
+GstVaapiBufferProxy *
+gst_vaapi_surface_peek_buffer_proxy (GstVaapiSurface * surface)
+{
+  return surface->extbuf_proxy;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface.h
new file mode 100644 (file)
index 0000000..822bb1c
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ *  gstvaapisurface.h - VA surface abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_SURFACE_H
+#define GST_VAAPI_SURFACE_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiimage.h>
+#include <gst/vaapi/gstvaapisubpicture.h>
+#include <gst/vaapi/gstvaapibufferproxy.h>
+#include <gst/video/video.h>
+#include <gst/video/video-overlay-composition.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GST_VAAPI_SURFACE_CAPS_NAME:
+ *
+ * Generic caps type for VA surfaces.
+ */
+#define GST_VAAPI_SURFACE_CAPS_NAME "video/x-surface"
+
+/**
+ * GST_VAAPI_SURFACE_CAPS:
+ *
+ * Generic caps for VA surfaces.
+ */
+#define GST_VAAPI_SURFACE_CAPS                  \
+    GST_VAAPI_SURFACE_CAPS_NAME ", "            \
+    "type = vaapi, "                            \
+    "opengl = (boolean) { true, false }, "      \
+    "width  = (int) [ 1, MAX ], "               \
+    "height = (int) [ 1, MAX ], "               \
+    "framerate = (fraction) [ 0, MAX ]"
+
+/**
+ * GstVaapiChromaType:
+ * @GST_VAAPI_CHROMA_TYPE_YUV420: YUV 4:2:0 chroma format
+ * @GST_VAAPI_CHROMA_TYPE_YUV422: YUV 4:2:2 chroma format
+ * @GST_VAAPI_CHROMA_TYPE_YUV444: YUV 4:4:4 chroma format
+ * @GST_VAAPI_CHROMA_TYPE_YUV411: YUV 4:1:1 chroma format
+ * @GST_VAAPI_CHROMA_TYPE_YUV400: YUV 4:0:0 chroma format (grayscale)
+ * @GST_VAAPI_CHROMA_TYPE_YUV420_10BPP: YUV 4:2:0 chroma format, 10 bits per channel
+ * @GST_VAAPI_CHROMA_TYPE_YUV422_10BPP: YUV 4:2:2 chroma format, 10 bits per channel
+ * @GST_VAAPI_CHROMA_TYPE_YUV444_10BPP: YUV 4:4:4 chroma format, 10 bits per channel
+ * @GST_VAAPI_CHROMA_TYPE_YUV420_12BPP: YUV 4:2:0 chroma format, 12 bits per channel
+ * @GST_VAAPI_CHROMA_TYPE_YUV422_12BPP: YUV 4:2:2 chroma format, 12 bits per channel
+ * @GST_VAAPI_CHROMA_TYPE_YUV444_12BPP: YUV 4:4:4 chroma format, 12 bits per channel
+ * @GST_VAAPI_CHROMA_TYPE_RGB16: 16-bit RGB chroma format
+ * @GST_VAAPI_CHROMA_TYPE_RGB32: 32-bit RGB chroma format
+ * @GST_VAAPI_CHROMA_TYPE_RGBP: Planar RGB, 8 bits per colour sample.
+ * @GST_VAAPI_CHROMA_TYPE_RGB32_10BPP: 32-bit RGB chroma format, 10 bits per colour sample
+ *
+ * The set of all chroma types for #GstVaapiSurface.
+ */
+typedef enum
+{
+  GST_VAAPI_CHROMA_TYPE_YUV420 = 1,
+  GST_VAAPI_CHROMA_TYPE_YUV422,
+  GST_VAAPI_CHROMA_TYPE_YUV444,
+  GST_VAAPI_CHROMA_TYPE_YUV411,
+  GST_VAAPI_CHROMA_TYPE_YUV400,
+  GST_VAAPI_CHROMA_TYPE_YUV420_10BPP,
+  GST_VAAPI_CHROMA_TYPE_YUV422_10BPP,
+  GST_VAAPI_CHROMA_TYPE_YUV444_10BPP,
+  GST_VAAPI_CHROMA_TYPE_YUV420_12BPP,
+  GST_VAAPI_CHROMA_TYPE_YUV422_12BPP,
+  GST_VAAPI_CHROMA_TYPE_YUV444_12BPP,
+  GST_VAAPI_CHROMA_TYPE_RGB16,
+  GST_VAAPI_CHROMA_TYPE_RGB32,
+  GST_VAAPI_CHROMA_TYPE_RGBP,
+  GST_VAAPI_CHROMA_TYPE_RGB32_10BPP,
+} GstVaapiChromaType;
+
+/**
+ * GstVaapiSurfaceStatus:
+ * @GST_VAAPI_SURFACE_STATUS_IDLE:
+ *   the surface is not being rendered or displayed
+ * @GST_VAAPI_SURFACE_STATUS_RENDERING:
+ *   the surface is used for rendering (decoding to the surface in progress)
+ * @GST_VAAPI_SURFACE_STATUS_DISPLAYING:
+ *   the surface is being displayed to screen
+ * @GST_VAAPI_SURFACE_STATUS_SKIPPED:
+ *   indicates a skipped frame during encode
+ *
+ * The set of all surface status for #GstVaapiSurface.
+ */
+typedef enum
+{
+  GST_VAAPI_SURFACE_STATUS_IDLE = 1 << 0,
+  GST_VAAPI_SURFACE_STATUS_RENDERING = 1 << 1,
+  GST_VAAPI_SURFACE_STATUS_DISPLAYING = 1 << 2,
+  GST_VAAPI_SURFACE_STATUS_SKIPPED = 1 << 3
+} GstVaapiSurfaceStatus;
+
+/**
+ * GstVaapiSurfaceRenderFlags:
+ * @GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
+ *   selects the top field of the surface
+ * @GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
+ *   selects the bottom field of the surface
+ * @GST_VAAPI_PICTURE_STRUCTURE_FRAME:
+ *   selects the entire surface
+ * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_601:
+ *   uses ITU-R BT.601 standard for color space conversion
+ * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_709:
+ *   uses ITU-R BT.709 standard for color space conversion
+ * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_470M:
+ *   uses ITU-R BT.470-2 System M standard for color space conversion
+ * @GST_VAAPI_COLOR_STANDARD_ITUR_BT_470BG:
+ *   uses ITU-R BT.470-2 System B, G standard for color space conversion
+ * @GST_VAAPI_COLOR_STANDARD_SMPTE_170M:
+ *   uses SMPTE-170M standard for color space conversion
+ * @GST_VAAPI_COLOR_STANDARD_SMPTE_240M:
+ *   uses SMPTE-240M standard for color space conversion
+ *
+ * The set of all render flags for gst_vaapi_window_put_surface().
+ */
+typedef enum
+{
+  /* Picture structure */
+  GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD         = 0x01 << 0,
+  GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD      = 0x02 << 0,
+  GST_VAAPI_PICTURE_STRUCTURE_FRAME             = 0x03 << 0,
+  GST_VAAPI_PICTURE_STRUCTURE_MASK              = 0x00000003, /* 2 bits */
+
+  /* Color standard */
+  GST_VAAPI_COLOR_STANDARD_ITUR_BT_601          = 0x01 << 2,
+  GST_VAAPI_COLOR_STANDARD_ITUR_BT_709          = 0x02 << 2,
+  GST_VAAPI_COLOR_STANDARD_ITUR_BT_470M         = 0x03 << 2,
+  GST_VAAPI_COLOR_STANDARD_ITUR_BT_470BG        = 0x04 << 2,
+  GST_VAAPI_COLOR_STANDARD_SMPTE_170M           = 0x05 << 2,
+  GST_VAAPI_COLOR_STANDARD_SMPTE_240M           = 0x06 << 2,
+  GST_VAAPI_COLOR_STANDARD_MASK                 = 0x0000003c, /* 4 bits */
+} GstVaapiSurfaceRenderFlags;
+
+/**
+ * GstVaapiSurfaceAllocFlags:
+ * @GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE: forces allocation
+ *   with linear storage. Default behaviour matches native
+ *   requirements, and thus could be tiled.
+ * @GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES: force allocation with
+ *   the supplied strides information from #GstVideoInfo
+ * @GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS: force allocation with
+ *   the supplied offsets information from #GstVideoInfo
+ * @GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_DECODER: Surface used by video
+ *   decoder
+ * @GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_ENCODER: Surface used by encoder
+ *
+ * The set of optional allocation flags for gst_vaapi_surface_new_full().
+ */
+typedef enum
+{
+  GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE   = 1 << 0,
+  GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_STRIDES    = 1 << 1,
+  GST_VAAPI_SURFACE_ALLOC_FLAG_FIXED_OFFSETS    = 1 << 2,
+  GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_DECODER     = 1 << 3,
+  GST_VAAPI_SURFACE_ALLOC_FLAG_HINT_ENCODER     = 1 << 4,
+} GstVaapiSurfaceAllocFlags;
+
+#define GST_VAAPI_SURFACE(obj) \
+    ((GstVaapiSurface *)(obj))
+
+#define GST_TYPE_VAAPI_SURFACE (gst_vaapi_surface_get_type ())
+
+#define GST_VAAPI_SURFACE_ID(surface)      (gst_vaapi_surface_get_id (surface))
+#define GST_VAAPI_SURFACE_DISPLAY(surface) (gst_vaapi_surface_get_display (surface))
+
+typedef struct _GstVaapiSurface                 GstVaapiSurface;
+typedef struct _GstVaapiSurfaceProxy            GstVaapiSurfaceProxy;
+
+GType
+gst_vaapi_surface_get_type (void) G_GNUC_CONST;
+
+/**
+ * gst_vaapi_surface_unref: (skip)
+ * @surface: (transfer full): a #GstVaapiSurface.
+ *
+ * Decreases the refcount of the surface. If the refcount reaches 0, the
+ * surface will be freed.
+ */
+static inline void
+gst_vaapi_surface_unref (GstVaapiSurface * surface)
+{
+  gst_mini_object_unref (GST_MINI_OBJECT_CAST (surface));
+}
+
+GstVaapiDisplay *
+gst_vaapi_surface_get_display (GstVaapiSurface * surface);
+
+GstVaapiSurface *
+gst_vaapi_surface_new (GstVaapiDisplay * display,
+    GstVaapiChromaType chroma_type, guint width, guint height);
+
+GstVaapiSurface *
+gst_vaapi_surface_new_full (GstVaapiDisplay * display,
+    const GstVideoInfo * vip, guint surface_allocation_flags);
+
+GstVaapiSurface *
+gst_vaapi_surface_new_with_format (GstVaapiDisplay * display,
+    GstVideoFormat format, guint width, guint height,
+    guint surface_allocation_flags);
+
+GstVaapiSurface *
+gst_vaapi_surface_new_from_buffer_proxy (GstVaapiDisplay * display,
+    GstVaapiBufferProxy * proxy, const GstVideoInfo * vip);
+
+GstVaapiID
+gst_vaapi_surface_get_id (GstVaapiSurface * surface);
+
+GstVaapiChromaType
+gst_vaapi_surface_get_chroma_type (GstVaapiSurface * surface);
+
+GstVideoFormat
+gst_vaapi_surface_get_format (GstVaapiSurface * surface);
+
+guint
+gst_vaapi_surface_get_width (GstVaapiSurface * surface);
+
+guint
+gst_vaapi_surface_get_height (GstVaapiSurface * surface);
+
+void
+gst_vaapi_surface_get_size (GstVaapiSurface * surface, guint * width_ptr,
+    guint * height_ptr);
+
+GstVaapiImage *
+gst_vaapi_surface_derive_image (GstVaapiSurface * surface);
+
+gboolean
+gst_vaapi_surface_get_image (GstVaapiSurface * surface, GstVaapiImage * image);
+
+gboolean
+gst_vaapi_surface_put_image (GstVaapiSurface * surface, GstVaapiImage * image);
+
+gboolean
+gst_vaapi_surface_associate_subpicture (GstVaapiSurface * surface,
+    GstVaapiSubpicture * subpicture, const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect);
+
+gboolean
+gst_vaapi_surface_deassociate_subpicture (GstVaapiSurface * surface,
+    GstVaapiSubpicture * subpicture);
+
+gboolean
+gst_vaapi_surface_sync (GstVaapiSurface * surface);
+
+gboolean
+gst_vaapi_surface_query_status (GstVaapiSurface * surface,
+    GstVaapiSurfaceStatus * pstatus);
+
+gboolean
+gst_vaapi_surface_set_subpictures_from_composition (GstVaapiSurface * surface,
+    GstVideoOverlayComposition * composition);
+
+void
+gst_vaapi_surface_set_buffer_proxy (GstVaapiSurface * surface,
+    GstVaapiBufferProxy * proxy);
+
+GstVaapiBufferProxy *
+gst_vaapi_surface_peek_buffer_proxy (GstVaapiSurface * surface);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiSurface, gst_vaapi_surface_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_SURFACE_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_drm.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_drm.c
new file mode 100644 (file)
index 0000000..833c6ac
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ *  gstvaapisurface_drm.c - VA surface abstraction (DRM interop)
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapisurface_drm.h"
+#include "gstvaapisurface_priv.h"
+#include "gstvaapiimage_priv.h"
+#include "gstvaapibufferproxy_priv.h"
+
+static GstVaapiBufferProxy *
+gst_vaapi_surface_get_drm_buf_handle (GstVaapiSurface * surface, guint type)
+{
+  GstVaapiBufferProxy *proxy;
+  GstVaapiImage *image;
+
+  image = gst_vaapi_surface_derive_image (surface);
+  if (!image)
+    goto error_derive_image;
+
+  /* The proxy takes ownership if the image, even creation failure. */
+  proxy =
+      gst_vaapi_buffer_proxy_new_from_surface (GST_MINI_OBJECT_CAST (surface),
+      image->internal_image.buf, type, (GDestroyNotify) gst_vaapi_image_unref,
+      image);
+  if (!proxy)
+    goto error_alloc_export_buffer;
+  return proxy;
+
+  /* ERRORS */
+error_derive_image:
+  {
+    GST_ERROR ("failed to extract image handle from surface");
+    return NULL;
+  }
+error_alloc_export_buffer:
+  {
+    GST_ERROR ("failed to allocate export buffer proxy");
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_surface_peek_dma_buf_handle:
+ * @surface: a #GstVaapiSurface
+ *
+ * If the underlying VA driver implementation supports it, this
+ * function allows for returning a suitable dma_buf (DRM) buffer
+ * handle as a #GstVaapiBufferProxy instance. The returned buffer
+ * proxy does not increase the ref of underlying buffer proxy.
+ *
+ * Return value: the underlying buffer as a #GstVaapiBufferProxy
+ * instance.
+ */
+GstVaapiBufferProxy *
+gst_vaapi_surface_peek_dma_buf_handle (GstVaapiSurface * surface)
+{
+  GstVaapiBufferProxy *buf_proxy;
+
+  g_return_val_if_fail (surface != NULL, NULL);
+
+  if (surface->extbuf_proxy)
+    return surface->extbuf_proxy;
+
+  buf_proxy = gst_vaapi_surface_get_drm_buf_handle (surface,
+      GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF);
+
+  if (buf_proxy) {
+    gst_vaapi_surface_set_buffer_proxy (surface, buf_proxy);
+    gst_vaapi_buffer_proxy_unref (buf_proxy);
+  }
+
+  return buf_proxy;
+}
+
+/**
+ * gst_vaapi_surface_peek_gem_buf_handle:
+ * @surface: a #GstVaapiSurface
+ *
+ * If the underlying VA driver implementation supports it, this
+ * function allows for returning a suitable GEM buffer handle as a
+ * #GstVaapiBufferProxy instance. The returned buffer proxy does
+ * not increase the ref of underlying buffer proxy.
+ *
+ * Return value: the underlying buffer as a #GstVaapiBufferProxy
+ * instance.
+ */
+GstVaapiBufferProxy *
+gst_vaapi_surface_peek_gem_buf_handle (GstVaapiSurface * surface)
+{
+  GstVaapiBufferProxy *buf_proxy;
+
+  g_return_val_if_fail (surface != NULL, NULL);
+
+  if (surface->extbuf_proxy)
+    return surface->extbuf_proxy;
+
+  buf_proxy = gst_vaapi_surface_get_drm_buf_handle (surface,
+      GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF);
+
+  if (buf_proxy) {
+    gst_vaapi_surface_set_buffer_proxy (surface, buf_proxy);
+    gst_vaapi_buffer_proxy_unref (buf_proxy);
+  }
+
+  return buf_proxy;
+}
+
+static void
+fill_video_info (GstVideoInfo * vip, GstVideoFormat format, guint width,
+    guint height, gsize offset[GST_VIDEO_MAX_PLANES],
+    gint stride[GST_VIDEO_MAX_PLANES])
+{
+  guint i;
+
+  gst_video_info_set_format (vip, format, width, height);
+  for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); i++) {
+    GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = offset[i];
+    GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = stride[i];
+  }
+}
+
+/**
+ * gst_vaapi_surface_new_with_dma_buf_handle:
+ * @display: a #GstVaapiDisplay
+ * @fd: the DRM PRIME file descriptor
+ * @size: the underlying DRM buffer size
+ * @format: the desired surface format
+ * @width: the desired surface width in pixels
+ * @height: the desired surface height in pixels
+ * @offset: the offsets to each plane
+ * @stride: the pitches for each plane
+ *
+ * Creates a new #GstVaapiSurface with an external DRM PRIME file
+ * descriptor. The newly created VA surfaces owns the supplied buffer
+ * handle.
+ *
+ * Return value: the newly allocated #GstVaapiSurface object, or %NULL
+ *   if creation from DRM PRIME fd failed, or is not supported
+ */
+GstVaapiSurface *
+gst_vaapi_surface_new_with_dma_buf_handle (GstVaapiDisplay * display, gint fd,
+    GstVideoInfo * vi)
+{
+  GstVaapiBufferProxy *proxy;
+  GstVaapiSurface *surface;
+
+  proxy = gst_vaapi_buffer_proxy_new ((gintptr) fd,
+      GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF, GST_VIDEO_INFO_SIZE (vi), NULL,
+      NULL);
+  if (!proxy)
+    return NULL;
+
+  surface = gst_vaapi_surface_new_from_buffer_proxy (display, proxy, vi);
+  /* Surface holds proxy's reference */
+  gst_vaapi_buffer_proxy_unref (proxy);
+  return surface;
+}
+
+/**
+ * gst_vaapi_surface_new_with_gem_buf_handle:
+ * @display: a #GstVaapiDisplay
+ * @name: the DRM GEM buffer name
+ * @size: the underlying DRM buffer size
+ * @format: the desired surface format
+ * @width: the desired surface width in pixels
+ * @height: the desired surface height in pixels
+ * @offset: the offsets to each plane
+ * @stride: the pitches for each plane
+ *
+ * Creates a new #GstVaapiSurface with an external DRM GEM buffer
+ * name. The newly created VA surfaces owns the supplied buffer
+ * handle.
+ *
+ * Return value: the newly allocated #GstVaapiSurface object, or %NULL
+ *   if creation from GEM @name failed, or is not supported
+ */
+GstVaapiSurface *
+gst_vaapi_surface_new_with_gem_buf_handle (GstVaapiDisplay * display,
+    guint32 name, guint size, GstVideoFormat format, guint width, guint height,
+    gsize offset[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES])
+{
+  GstVaapiBufferProxy *proxy;
+  GstVaapiSurface *surface;
+  GstVideoInfo vi;
+
+  proxy = gst_vaapi_buffer_proxy_new ((guintptr) name,
+      GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF, size, NULL, NULL);
+  if (!proxy)
+    return NULL;
+
+  fill_video_info (&vi, format, width, height, offset, stride);
+  surface = gst_vaapi_surface_new_from_buffer_proxy (display, proxy, &vi);
+  /* Surface holds proxy's reference */
+  gst_vaapi_buffer_proxy_unref (proxy);
+  return surface;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_drm.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_drm.h
new file mode 100644 (file)
index 0000000..0bc5f84
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *  gstvaapisurface_drm.h - VA surface abstraction (DRM interop)
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_SURFACE_DRM_H
+#define GST_VAAPI_SURFACE_DRM_H
+
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapibufferproxy.h>
+
+G_BEGIN_DECLS
+
+GstVaapiBufferProxy *
+gst_vaapi_surface_peek_dma_buf_handle (GstVaapiSurface * surface);
+
+GstVaapiBufferProxy *
+gst_vaapi_surface_peek_gem_buf_handle (GstVaapiSurface * surface);
+
+GstVaapiSurface *
+gst_vaapi_surface_new_with_dma_buf_handle (GstVaapiDisplay * display, gint fd,
+    GstVideoInfo * vi);
+
+GstVaapiSurface *
+gst_vaapi_surface_new_with_gem_buf_handle (GstVaapiDisplay * display,
+    guint32 name, guint size, GstVideoFormat format, guint width, guint height,
+    gsize offset[GST_VIDEO_MAX_PLANES], gint stride[GST_VIDEO_MAX_PLANES]);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_SURFACE_DRM_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_egl.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_egl.c
new file mode 100644 (file)
index 0000000..07ba0a5
--- /dev/null
@@ -0,0 +1,353 @@
+/*
+ *  gstvaapisurface_egl.c - VA surface abstraction (EGL interop)
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+
+#include "gstvaapisurface_egl.h"
+
+#include "gstvaapibufferproxy_priv.h"
+#include "gstvaapicompat.h"
+#include "gstvaapidisplay_egl_priv.h"
+#include "gstvaapifilter.h"
+#include "gstvaapiimage_priv.h"
+#include "gstvaapisurface_drm.h"
+#include "gstvaapisurface_priv.h"
+
+#if GST_VAAPI_USE_DRM
+#include <drm_fourcc.h>
+#else
+#define DRM_FORMAT_MOD_LINEAR 0ULL
+#define DRM_FORMAT_MOD_INVALID ((1ULL << 56) - 1)
+#endif
+
+typedef struct
+{
+  GstVaapiDisplayEGL *display;
+  EGLImageKHR image;
+  GstVideoFormat format;
+  guint width;
+  guint height;
+  guint mem_types;
+  GstVaapiSurface *surface;     /* result */
+} CreateSurfaceWithEGLImageArgs;
+
+static GstVaapiSurface *
+do_create_surface_with_egl_image_unlocked (GstVaapiDisplayEGL * display,
+    EGLImageKHR image, GstVideoFormat format, guint width, guint height,
+    guint mem_types)
+{
+  GstVaapiDisplay *const base_display = GST_VAAPI_DISPLAY_CAST (display);
+  EglContext *const ctx = GST_VAAPI_DISPLAY_EGL_CONTEXT (display);
+  EglVTable *vtable;
+
+  if (!ctx || !(vtable = egl_context_get_vtable (ctx, FALSE)))
+    return NULL;
+
+  if ((mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM)
+      && vtable->has_EGL_MESA_drm_image) {
+    gsize size, offset[GST_VIDEO_MAX_PLANES] = { 0, };
+    gint name, stride[GST_VIDEO_MAX_PLANES] = { 0, };
+
+    /* EGL_MESA_drm_image extension */
+    if (!vtable->eglExportDRMImageMESA (ctx->display->base.handle.p, image,
+            &name, NULL, &stride[0]))
+      goto error_export_image_gem_buf;
+
+    size = height * stride[0];
+    /*
+     * XXX: The below surface creation may fail on Intel due to:
+     *   https://github.com/01org/intel-vaapi-driver/issues/222
+     * A permanent fix for that problem will be released in intel-vaapi-driver
+     * version 1.8.4 and later, and also in 1.8.3-1ubuntu1.
+     * However if you don't have that fix then a simple workaround is to
+     * uncomment this line of code:
+     *   size = GST_ROUND_UP_32 (height) * stride[0];
+     */
+
+    return gst_vaapi_surface_new_with_gem_buf_handle (base_display, name, size,
+        format, width, height, offset, stride);
+  }
+
+  if ((mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME)
+      && vtable->has_EGL_MESA_image_dma_buf_export) {
+    int fourcc, num_planes, fd;
+    EGLint offset = 0;
+    EGLint stride = 0;
+    EGLuint64KHR modifier;
+    GstVideoInfo vi;
+
+    if (!vtable->eglExportDMABUFImageQueryMESA (ctx->display->base.handle.p,
+            image, &fourcc, &num_planes, &modifier))
+      goto error_export_dma_buf_image_query;
+
+    /* Don't allow multi-plane dmabufs */
+    if (num_planes != 1)
+      goto error_bad_parameters;
+
+    /* FIXME: We don't support modifiers */
+    if (modifier != DRM_FORMAT_MOD_LINEAR && modifier != DRM_FORMAT_MOD_INVALID)
+      goto error_bad_parameters;
+
+    /* fix color format if needed */
+    if (fourcc == GST_MAKE_FOURCC ('A', 'B', '2', '4'))
+      format = gst_vaapi_video_format_from_va_fourcc (VA_FOURCC_RGBA);
+    else if (fourcc == GST_MAKE_FOURCC ('A', 'R', '2', '4'))
+      format = gst_vaapi_video_format_from_va_fourcc (VA_FOURCC_BGRA);
+
+    if (!vtable->eglExportDMABUFImageMESA (ctx->display->base.handle.p, image,
+            &fd, &stride, &offset))
+      goto error_export_dma_buf_image;
+
+    gst_video_info_set_format (&vi, format, width, height);
+    GST_VIDEO_INFO_PLANE_OFFSET (&vi, 0) = offset;
+    GST_VIDEO_INFO_PLANE_STRIDE (&vi, 0) = stride;
+
+    return gst_vaapi_surface_new_with_dma_buf_handle (base_display, fd, &vi);
+  }
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    GString *str = g_string_new (NULL);
+
+    if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_VA)
+      g_string_append (str, "VA ");
+    if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_V4L2)
+      g_string_append (str, "V4L2 ");
+    if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR)
+      g_string_append (str, "PTR ");
+#if VA_CHECK_VERSION(1,1,0)
+    if (mem_types & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2)
+      g_string_append (str, "PRIME_2 ");
+#endif
+
+    GST_ERROR ("missing EGL extensions for memory types: %s", str->str);
+    g_string_free (str, TRUE);
+  }
+#endif
+
+  return NULL;
+
+  /* ERRORS */
+error_export_image_gem_buf:
+  {
+    GST_ERROR ("failed to export EGL image to GEM buffer");
+    return NULL;
+  }
+error_export_dma_buf_image_query:
+  {
+    GST_ERROR ("failed to query EGL image for dmabuf export");
+    return NULL;
+  }
+error_bad_parameters:
+  {
+    GST_ERROR ("multi-planed nor non-linear dmabufs are not supported");
+    return NULL;
+  }
+error_export_dma_buf_image:
+  {
+    GST_ERROR ("missing EGL_MESA_image_dma_buf_export extension");
+    return NULL;
+  }
+}
+
+static void
+do_create_surface_with_egl_image (CreateSurfaceWithEGLImageArgs * args)
+{
+  GST_VAAPI_DISPLAY_LOCK (args->display);
+  args->surface = do_create_surface_with_egl_image_unlocked (args->display,
+      args->image, args->format, args->width, args->height, args->mem_types);
+  GST_VAAPI_DISPLAY_UNLOCK (args->display);
+}
+
+// Creates VA surface with EGLImage buffer as backing storage (internal)
+static inline GstVaapiSurface *
+create_surface_with_egl_image (GstVaapiDisplayEGL * display, EGLImageKHR image,
+    GstVideoFormat format, guint width, guint height, guint mem_types)
+{
+  CreateSurfaceWithEGLImageArgs args =
+      { display, image, format, width, height, mem_types };
+
+  if (!egl_context_run (GST_VAAPI_DISPLAY_EGL_CONTEXT (display),
+          (EglContextRunFunc) do_create_surface_with_egl_image, &args))
+    return NULL;
+  return args.surface;
+}
+
+// Creates VA surface from an EGLImage buffer copy (internal)
+static GstVaapiSurface *
+create_surface_from_egl_image (GstVaapiDisplayEGL * display,
+    const GstVideoInfo * vip, EGLImageKHR image, GstVideoFormat format,
+    guint width, guint height, guint flags)
+{
+  GstVaapiDisplay *const base_display = GST_VAAPI_DISPLAY_CAST (display);
+  GstVaapiSurface *img_surface = NULL, *out_surface = NULL;
+  gboolean use_native_format = TRUE;
+  GstVaapiFilter *filter = NULL;
+  GstVaapiFilterStatus filter_status;
+
+  img_surface = create_surface_with_egl_image (display, image, format,
+      width, height, 0);
+  if (!img_surface)
+    return NULL;
+
+  if (vip) {
+    use_native_format =
+        GST_VIDEO_INFO_FORMAT (vip) == GST_VIDEO_FORMAT_ENCODED ||
+        GST_VIDEO_INFO_FORMAT (vip) == GST_VIDEO_FORMAT_UNKNOWN;
+
+    if (GST_VIDEO_INFO_WIDTH (vip) && GST_VIDEO_INFO_HEIGHT (vip)) {
+      width = GST_VIDEO_INFO_WIDTH (vip);
+      height = GST_VIDEO_INFO_HEIGHT (vip);
+    }
+  }
+
+  if (use_native_format) {
+    out_surface = gst_vaapi_surface_new (base_display,
+        GST_VAAPI_CHROMA_TYPE_YUV420, width, height);
+  } else {
+    out_surface = gst_vaapi_surface_new_with_format (base_display,
+        GST_VIDEO_INFO_FORMAT (vip), width, height, 0);
+  }
+  if (!out_surface)
+    goto error_create_surface;
+
+  filter = gst_vaapi_filter_new (base_display);
+  if (!filter)
+    goto error_create_filter;
+
+  filter_status = gst_vaapi_filter_process (filter,
+      img_surface, out_surface, flags);
+  if (filter_status != GST_VAAPI_FILTER_STATUS_SUCCESS)
+    goto error_convert_surface;
+
+  gst_vaapi_surface_unref (img_surface);
+  gst_object_unref (filter);
+  return out_surface;
+
+  /* ERRORS */
+error_create_surface:
+  GST_ERROR ("failed to create output surface format:%s size:%dx%d",
+      gst_vaapi_video_format_to_string (vip ? GST_VIDEO_INFO_FORMAT (vip) :
+          GST_VIDEO_FORMAT_ENCODED), width, height);
+  goto error_cleanup;
+error_convert_surface:
+  GST_ERROR ("failed to transfer EGL image to VA surface (status = %d)",
+      filter_status);
+  goto error_cleanup;
+error_create_filter:
+  GST_ERROR ("failed to create video processing filter");
+  // fall-through
+error_cleanup:
+  gst_mini_object_replace ((GstMiniObject **) & img_surface, NULL);
+  gst_mini_object_replace ((GstMiniObject **) & out_surface, NULL);
+  gst_vaapi_filter_replace (&filter, NULL);
+  return NULL;
+}
+
+/**
+ * gst_vaapi_surface_new_from_egl_image:
+ * @display: a #GstVaapiDisplay
+ * @vip: the desired (optional) #GstVideoInfo constraints
+ * @image: the EGL image to import
+ * @format: the EGL @image format
+ * @width: the EGL @image width in pixels
+ * @height: the EGL @image height in pixels
+ * @flags: postprocessing flags. See #GstVaapiSurfaceRenderFlags
+ *
+ * Creates a new #GstVaapiSurface with a copy of the EGL image
+ * contents. i.e. the input EGL @image can be disposed and the
+ * resulting VA surface would still be valid with the contents at the
+ * time this function was called.
+ *
+ * If @vip is %NULL, then the resulting VA surface will be created
+ * with the same video format and size as the original @image. If @vip
+ * is non-%NULL and the desired format is GST_VIDEO_FORMAT_ENCODED,
+ * then the resulting VA surface will have the best "native" HW
+ * format, usually NV12.
+ *
+ * Return value: the newly allocated #GstVaapiSurface object, or %NULL
+ *   if creation from EGL image failed, or is not supported
+ */
+GstVaapiSurface *
+gst_vaapi_surface_new_from_egl_image (GstVaapiDisplay * base_display,
+    const GstVideoInfo * vip, EGLImageKHR image, GstVideoFormat format,
+    guint width, guint height, guint flags)
+{
+  GstVaapiDisplayEGL *display;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (base_display), NULL);
+  g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+
+  display = GST_VAAPI_DISPLAY_EGL (base_display);
+  if (!display || !GST_VAAPI_IS_DISPLAY_EGL (display))
+    goto error_invalid_display;
+  return create_surface_from_egl_image (display, vip, image, format,
+      width, height, flags);
+
+  /* ERRORS */
+error_invalid_display:
+  GST_ERROR ("invalid display (NULL or not of EGL class");
+  return NULL;
+}
+
+/**
+ * gst_vaapi_surface_new_with_egl_image:
+ * @display: a #GstVaapiDisplay
+ * @image: the EGL image to import
+ * @format: the EGL @image format
+ * @width: the EGL @image width in pixels
+ * @height: the EGL @image height in pixels
+ * @mem_types: the supported memory types
+ *
+ * Creates a new #GstVaapiSurface bound to an external EGL image.
+ *
+ * The caller maintains the lifetime of the EGL image object. In
+ * particular, the EGL image shall not be destroyed before the last
+ * reference to the resulting VA surface is released.
+ *
+ * Return value: the newly allocated #GstVaapiSurface object, or %NULL
+ *   if creation from EGL image failed, or is not supported
+ */
+GstVaapiSurface *
+gst_vaapi_surface_new_with_egl_image (GstVaapiDisplay * base_display,
+    EGLImageKHR image, GstVideoFormat format, guint width, guint height,
+    guint mem_types)
+{
+  GstVaapiDisplayEGL *display;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (base_display), NULL);
+  g_return_val_if_fail (image != EGL_NO_IMAGE_KHR, NULL);
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+
+  display = GST_VAAPI_DISPLAY_EGL (base_display);
+  if (!display || !GST_VAAPI_IS_DISPLAY_EGL (display))
+    goto error_invalid_display;
+  return create_surface_with_egl_image (display, image, format, width, height,
+      mem_types);
+
+  /* ERRORS */
+error_invalid_display:
+  GST_ERROR ("invalid display (NULL or not of EGL class");
+  return NULL;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_egl.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_egl.h
new file mode 100644 (file)
index 0000000..71cb150
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ *  gstvaapisurface_egl.h - VA surface abstraction (EGL interop)
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_SURFACE_EGL_H
+#define GST_VAAPI_SURFACE_EGL_H
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <gst/vaapi/gstvaapisurface.h>
+
+G_BEGIN_DECLS
+
+GstVaapiSurface *
+gst_vaapi_surface_new_from_egl_image (GstVaapiDisplay * display,
+    const GstVideoInfo * vip, EGLImageKHR image, GstVideoFormat format,
+    guint width, guint height, guint flags);
+
+GstVaapiSurface *
+gst_vaapi_surface_new_with_egl_image (GstVaapiDisplay * display,
+    EGLImageKHR image, GstVideoFormat format, guint width, guint height,
+    guint mem_types);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_SURFACE_EGL_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurface_priv.h
new file mode 100644 (file)
index 0000000..f0e8ce7
--- /dev/null
@@ -0,0 +1,124 @@
+/*
+ *  gstvaapisurface_priv.h - VA surface abstraction (private data)
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_SURFACE_PRIV_H
+#define GST_VAAPI_SURFACE_PRIV_H
+
+#include <gst/vaapi/gstvaapisurface.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstVaapiSurface:
+ *
+ * A VA surface wrapper.
+ */
+struct _GstVaapiSurface
+{
+  /*< private >*/
+  GstMiniObject mini_object;
+  GstVaapiDisplay *display;
+  GstVaapiID object_id;
+
+  GstVaapiBufferProxy *extbuf_proxy;
+  GstVideoFormat format;
+  guint width;
+  guint height;
+  GstVaapiChromaType chroma_type;
+  GPtrArray *subpictures;
+};
+
+/**
+ * GST_VAAPI_SURFACE_DISPLAY:
+ * @surface: a #GstVaapiSurface
+ *
+ * Macro that evaluates to the @surface's display.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef GST_VAAPI_SURFACE_DISPLAY
+#define GST_VAAPI_SURFACE_DISPLAY(surface) \
+  (GST_VAAPI_SURFACE (surface)->display)
+
+/**
+ * GST_VAAPI_SURFACE_ID:
+ * @surface: a #GstVaapiSurface
+ *
+ * Macro that evaluates to the @surface's ID.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef GST_VAAPI_SURFACE_ID
+#define GST_VAAPI_SURFACE_ID(surface) \
+  (GST_VAAPI_SURFACE (surface)->object_id)
+
+/**
+ * GST_VAAPI_SURFACE_CHROMA_TYPE:
+ * @surface: a #GstVaapiSurface
+ *
+ * Macro that evaluates to the @surface chroma type.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_CHROMA_TYPE
+#define GST_VAAPI_SURFACE_CHROMA_TYPE(surface) \
+  (GST_VAAPI_SURFACE (surface)->chroma_type)
+
+/**
+ * GST_VAAPI_SURFACE_FORMAT:
+ * @surface: a #GstVaapiSurface
+ *
+ * Macro that evaluates to the @surface format.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_FORMAT
+#define GST_VAAPI_SURFACE_FORMAT(surface) \
+  (GST_VAAPI_SURFACE (surface)->format)
+
+/**
+ * GST_VAAPI_SURFACE_WIDTH:
+ * @surface: a #GstVaapiSurface
+ *
+ * Macro that evaluates to the @surface width in pixels.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_WIDTH
+#define GST_VAAPI_SURFACE_WIDTH(surface) \
+  (GST_VAAPI_SURFACE (surface)->width)
+
+/**
+ * GST_VAAPI_SURFACE_HEIGHT:
+ * @surface: a #GstVaapiSurface
+ *
+ * Macro that evaluates to the @surface height in pixels.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_HEIGHT
+#define GST_VAAPI_SURFACE_HEIGHT(surface) \
+  (GST_VAAPI_SURFACE (surface)->height)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_SURFACE_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfacepool.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfacepool.c
new file mode 100644 (file)
index 0000000..5ad85f0
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ *  gstvaapisurfacepool.c - Gst VA surface pool
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapisurfacepool
+ * @short_description: VA surface pool
+ */
+
+#include "sysdeps.h"
+#include "gstvaapisurfacepool.h"
+#include "gstvaapivideopool_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/**
+ * GstVaapiSurfacePool:
+ *
+ * A pool of lazily allocated #GstVaapiSurface objects.
+ */
+struct _GstVaapiSurfacePool
+{
+  /*< private > */
+  GstVaapiVideoPool parent_instance;
+
+  GstVaapiChromaType chroma_type;
+  GstVideoInfo video_info;
+  guint alloc_flags;
+};
+
+static gboolean
+surface_pool_init (GstVaapiSurfacePool * pool, const GstVideoInfo * vip,
+    guint surface_allocation_flags)
+{
+  const GstVideoFormat format = GST_VIDEO_INFO_FORMAT (vip);
+
+  pool->video_info = *vip;
+  pool->alloc_flags = surface_allocation_flags;
+
+  if (format == GST_VIDEO_FORMAT_UNKNOWN)
+    return FALSE;
+
+  if (format == GST_VIDEO_FORMAT_ENCODED)
+    pool->chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+  else
+    pool->chroma_type = gst_vaapi_video_format_get_chroma_type (format);
+  if (!pool->chroma_type)
+    return FALSE;
+  return TRUE;
+}
+
+static gpointer
+gst_vaapi_surface_pool_alloc_object (GstVaapiVideoPool * base_pool)
+{
+  GstVaapiSurfacePool *const pool = GST_VAAPI_SURFACE_POOL (base_pool);
+
+  /* Try to allocate a surface with an explicit pixel format first */
+  if (GST_VIDEO_INFO_FORMAT (&pool->video_info) != GST_VIDEO_FORMAT_ENCODED) {
+    GstVaapiSurface *const surface =
+        gst_vaapi_surface_new_full (base_pool->display, &pool->video_info,
+        pool->alloc_flags);
+    if (surface)
+      return surface;
+  }
+
+  /* Otherwise, fallback to the original interface, based on chroma format */
+  return gst_vaapi_surface_new (base_pool->display,
+      pool->chroma_type, GST_VIDEO_INFO_WIDTH (&pool->video_info),
+      GST_VIDEO_INFO_HEIGHT (&pool->video_info));
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_surface_pool_class (void)
+{
+  static const GstVaapiVideoPoolClass GstVaapiSurfacePoolClass = {
+    {sizeof (GstVaapiSurfacePool),
+        (GDestroyNotify) gst_vaapi_video_pool_finalize}
+    ,
+    .alloc_object = gst_vaapi_surface_pool_alloc_object
+  };
+  return GST_VAAPI_MINI_OBJECT_CLASS (&GstVaapiSurfacePoolClass);
+}
+
+/**
+ * gst_vaapi_surface_pool_new:
+ * @display: a #GstVaapiDisplay
+ * @format: a #GstVideoFormat
+ * @width: the desired width, in pixels
+ * @height: the desired height, in pixels
+ * @surface_allocation_flags: (optional) allocation flags
+ *
+ * Creates a new #GstVaapiVideoPool of #GstVaapiSurface with the specified
+ * format and dimensions. If @format is GST_VIDEO_FORMAT_ENCODED, then
+ * surfaces with best "native" format would be created. Typically, this is
+ * NV12 format, but this is implementation (driver) defined.
+ *
+ * Return value: the newly allocated #GstVaapiVideoPool
+ */
+GstVaapiVideoPool *
+gst_vaapi_surface_pool_new (GstVaapiDisplay * display, GstVideoFormat format,
+    guint width, guint height, guint surface_allocation_flags)
+{
+  GstVideoInfo vi;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+
+  gst_video_info_set_format (&vi, format, width, height);
+  return gst_vaapi_surface_pool_new_full (display, &vi,
+      surface_allocation_flags);
+}
+
+/**
+ * gst_vaapi_surface_pool_new_full:
+ * @display: a #GstVaapiDisplay
+ * @vip: a #GstVideoInfo
+ * @surface_allocation_flags: (optional) allocation flags
+ *
+ * Creates a new #GstVaapiVideoPool of #GstVaapiSurface with the
+ * specified format and dimensions in @vip.
+ *
+ * Return value: the newly allocated #GstVaapiVideoPool
+ */
+GstVaapiVideoPool *
+gst_vaapi_surface_pool_new_full (GstVaapiDisplay * display,
+    const GstVideoInfo * vip, guint surface_allocation_flags)
+{
+  GstVaapiVideoPool *pool;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (vip != NULL, NULL);
+
+  pool = (GstVaapiVideoPool *)
+      gst_vaapi_mini_object_new (gst_vaapi_surface_pool_class ());
+  if (!pool)
+    return NULL;
+
+  gst_vaapi_video_pool_init (pool, display,
+      GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_SURFACE);
+  if (!surface_pool_init (GST_VAAPI_SURFACE_POOL (pool), vip,
+          surface_allocation_flags))
+    goto error;
+  return pool;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (pool));
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_surface_pool_new_with_chroma_type:
+ * @display: a #GstVaapiDisplay
+ * @chroma_type: a #GstVaapiChromatype
+ * @width: the desired width, in pixels
+ * @height: the desired height, in pixels
+ * @surface_allocation_flags: (optional) allocation flags
+ *
+ * Creates a new #GstVaapiVideoPool of #GstVaapiSurface with the specified
+ * chroma type and dimensions. The underlying format of the surfaces is
+ * implementation (driver) defined.
+ *
+ * Return value: the newly allocated #GstVaapiVideoPool
+ */
+GstVaapiVideoPool *
+gst_vaapi_surface_pool_new_with_chroma_type (GstVaapiDisplay * display,
+    GstVaapiChromaType chroma_type, guint width, guint height,
+    guint surface_allocation_flags)
+{
+  GstVaapiVideoPool *pool;
+  GstVideoInfo vi;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (chroma_type > 0, NULL);
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+
+  gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED, width, height);
+
+  pool =
+      gst_vaapi_surface_pool_new_full (display, &vi, surface_allocation_flags);
+  if (!pool)
+    return NULL;
+
+  GST_VAAPI_SURFACE_POOL (pool)->chroma_type = chroma_type;
+
+  return pool;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfacepool.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfacepool.h
new file mode 100644 (file)
index 0000000..1fa7fe1
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ *  gstvaapisurfacepool.h - Gst VA surface pool
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_SURFACE_POOL_H
+#define GST_VAAPI_SURFACE_POOL_H
+
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapivideopool.h>
+#include <gst/vaapi/video-format.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_SURFACE_POOL(obj) \
+  ((GstVaapiSurfacePool *)(obj))
+
+typedef struct _GstVaapiSurfacePool GstVaapiSurfacePool;
+
+GstVaapiVideoPool *
+gst_vaapi_surface_pool_new (GstVaapiDisplay * display, GstVideoFormat format,
+    guint width, guint height, guint surface_allocation_flags);
+
+GstVaapiVideoPool *
+gst_vaapi_surface_pool_new_full (GstVaapiDisplay * display,
+    const GstVideoInfo * vip, guint surface_allocation_flags);
+
+GstVaapiVideoPool *
+gst_vaapi_surface_pool_new_with_chroma_type (GstVaapiDisplay * display,
+    GstVaapiChromaType chroma_type, guint width, guint height,
+    guint surface_allocation_flags);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_SURFACE_POOL_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfaceproxy.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfaceproxy.c
new file mode 100644 (file)
index 0000000..729efeb
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ *  gstvaapisurfaceproxy.c - VA surface proxy
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapisurfaceproxy
+ * @short_description: VA surface proxy
+ */
+
+#include "sysdeps.h"
+#include "gstvaapisurfaceproxy.h"
+#include "gstvaapisurfaceproxy_priv.h"
+#include "gstvaapivideopool_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+static void
+gst_vaapi_surface_proxy_finalize (GstVaapiSurfaceProxy * proxy)
+{
+  if (proxy->surface) {
+    if (proxy->pool && !proxy->parent)
+      gst_vaapi_video_pool_put_object (proxy->pool, proxy->surface);
+    gst_vaapi_surface_unref (proxy->surface);
+    proxy->surface = NULL;
+  }
+  gst_vaapi_video_pool_replace (&proxy->pool, NULL);
+  gst_vaapi_surface_proxy_replace (&proxy->parent, NULL);
+
+  /* Notify the user function that the object is now destroyed */
+  if (proxy->destroy_func)
+    proxy->destroy_func (proxy->destroy_data);
+}
+
+static inline const GstVaapiMiniObjectClass *
+gst_vaapi_surface_proxy_class (void)
+{
+  static const GstVaapiMiniObjectClass GstVaapiSurfaceProxyClass = {
+    sizeof (GstVaapiSurfaceProxy),
+    (GDestroyNotify) gst_vaapi_surface_proxy_finalize
+  };
+  return &GstVaapiSurfaceProxyClass;
+}
+
+static void
+gst_vaapi_surface_proxy_init_properties (GstVaapiSurfaceProxy * proxy)
+{
+  proxy->view_id = 0;
+  proxy->timestamp = GST_CLOCK_TIME_NONE;
+  proxy->duration = GST_CLOCK_TIME_NONE;
+  proxy->has_crop_rect = FALSE;
+}
+
+/**
+ * gst_vaapi_surface_proxy_new:
+ * @surface: a #GstVaapiSurface
+ *
+ * Creates a new #GstVaapiSurfaceProxy with the specified
+ * surface. This allows for transporting additional information that
+ * are not to be attached to the @surface directly.
+ *
+ * Return value: the newly allocated #GstVaapiSurfaceProxy object
+ */
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_new (GstVaapiSurface * surface)
+{
+  GstVaapiSurfaceProxy *proxy;
+
+  g_return_val_if_fail (surface != NULL, NULL);
+
+  proxy = (GstVaapiSurfaceProxy *)
+      gst_vaapi_mini_object_new (gst_vaapi_surface_proxy_class ());
+  if (!proxy)
+    return NULL;
+
+  proxy->parent = NULL;
+  proxy->destroy_func = NULL;
+  proxy->pool = NULL;
+  proxy->surface =
+      (GstVaapiSurface *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (surface));
+  if (!proxy->surface)
+    goto error;
+  gst_vaapi_surface_proxy_init_properties (proxy);
+  return proxy;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_surface_proxy_unref (proxy);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_surface_proxy_new_from_pool:
+ * @pool: a #GstVaapiSurfacePool
+ *
+ * Allocates a new surface from the supplied surface @pool and creates
+ * the wrapped surface proxy object from it. When the last reference
+ * to the proxy object is released, then the underlying VA surface is
+ * pushed back to its parent pool.
+ *
+ * Returns: The same newly allocated @proxy object, or %NULL on error
+ */
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_new_from_pool (GstVaapiSurfacePool * pool)
+{
+  GstVaapiSurfaceProxy *proxy;
+
+  g_return_val_if_fail (pool != NULL, NULL);
+
+  proxy = (GstVaapiSurfaceProxy *)
+      gst_vaapi_mini_object_new (gst_vaapi_surface_proxy_class ());
+  if (!proxy)
+    return NULL;
+
+  proxy->parent = NULL;
+  proxy->destroy_func = NULL;
+  proxy->pool = gst_vaapi_video_pool_ref (GST_VAAPI_VIDEO_POOL (pool));
+  proxy->surface = gst_vaapi_video_pool_get_object (proxy->pool);
+  if (!proxy->surface)
+    goto error;
+  gst_mini_object_ref (GST_MINI_OBJECT_CAST (proxy->surface));
+  gst_vaapi_surface_proxy_init_properties (proxy);
+  return proxy;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_surface_proxy_unref (proxy);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_surface_proxy_copy:
+ * @proxy: the parent #GstVaapiSurfaceProxy
+ *
+ * Creates are new VA surface proxy object from the supplied parent
+ * @proxy object with the same initial information, e.g. timestamp,
+ * duration.
+ *
+ * Note: the destroy notify function is not copied into the new
+ * surface proxy object.
+ *
+ * Returns: The same newly allocated @proxy object, or %NULL on error
+ */
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_copy (GstVaapiSurfaceProxy * proxy)
+{
+  GstVaapiSurfaceProxy *copy;
+
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  copy = (GstVaapiSurfaceProxy *)
+      gst_vaapi_mini_object_new (gst_vaapi_surface_proxy_class ());
+  if (!copy)
+    return NULL;
+
+  GST_VAAPI_SURFACE_PROXY_FLAGS (copy) = GST_VAAPI_SURFACE_PROXY_FLAGS (proxy);
+
+  copy->parent = gst_vaapi_surface_proxy_ref (proxy->parent ?
+      proxy->parent : proxy);
+  copy->pool = proxy->pool ? gst_vaapi_video_pool_ref (proxy->pool) : NULL;
+  copy->surface = (GstVaapiSurface *)
+      gst_mini_object_ref (GST_MINI_OBJECT_CAST (proxy->surface));
+  copy->view_id = proxy->view_id;
+  copy->timestamp = proxy->timestamp;
+  copy->duration = proxy->duration;
+  copy->destroy_func = NULL;
+  copy->has_crop_rect = proxy->has_crop_rect;
+  if (copy->has_crop_rect)
+    copy->crop_rect = proxy->crop_rect;
+
+  return copy;
+}
+
+/**
+ * gst_vaapi_surface_proxy_ref:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Atomically increases the reference count of the given @proxy by one.
+ *
+ * Returns: The same @proxy argument
+ */
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_ref (GstVaapiSurfaceProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  return
+      GST_VAAPI_SURFACE_PROXY (gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT
+          (proxy)));
+}
+
+/**
+ * gst_vaapi_surface_proxy_unref:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Atomically decreases the reference count of the @proxy by one. If
+ * the reference count reaches zero, the object will be free'd.
+ */
+void
+gst_vaapi_surface_proxy_unref (GstVaapiSurfaceProxy * proxy)
+{
+  g_return_if_fail (proxy != NULL);
+
+  gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (proxy));
+}
+
+/**
+ * gst_vaapi_surface_proxy_replace:
+ * @old_proxy_ptr: a pointer to a #GstVaapiSurfaceProxy
+ * @new_proxy: a #GstVaapiSurfaceProxy
+ *
+ * Atomically replaces the proxy object held in @old_proxy_ptr with
+ * @new_proxy. This means that @old_proxy_ptr shall reference a valid
+ * object. However, @new_proxy can be NULL.
+ */
+void
+gst_vaapi_surface_proxy_replace (GstVaapiSurfaceProxy ** old_proxy_ptr,
+    GstVaapiSurfaceProxy * new_proxy)
+{
+  g_return_if_fail (old_proxy_ptr != NULL);
+
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) old_proxy_ptr,
+      GST_VAAPI_MINI_OBJECT (new_proxy));
+}
+
+/**
+ * gst_vaapi_surface_proxy_get_surface:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Returns the #GstVaapiSurface stored in the @proxy.
+ *
+ * Return value: the #GstVaapiSurface
+ */
+GstVaapiSurface *
+gst_vaapi_surface_proxy_get_surface (GstVaapiSurfaceProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  return GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_get_flags:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Returns the #GstVaapiSurfaceProxyFlags associated with this surface
+ * @proxy.
+ *
+ * Return value: the set of #GstVaapiSurfaceProxyFlags
+ */
+guint
+gst_vaapi_surface_proxy_get_flags (GstVaapiSurfaceProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, 0);
+
+  return GST_VAAPI_SURFACE_PROXY_FLAGS (proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_get_surface_id:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Returns the VA surface ID stored in the @proxy.
+ *
+ * Return value: the #GstVaapiID
+ */
+GstVaapiID
+gst_vaapi_surface_proxy_get_surface_id (GstVaapiSurfaceProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, VA_INVALID_ID);
+  g_return_val_if_fail (proxy->surface != NULL, VA_INVALID_ID);
+
+  return GST_VAAPI_SURFACE_PROXY_SURFACE_ID (proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_get_view_id:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Returns the decoded view-id stored in the @proxy.
+ *
+ * Return value: the #GstVaapiID
+ */
+guintptr
+gst_vaapi_surface_proxy_get_view_id (GstVaapiSurfaceProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, 0);
+
+  return GST_VAAPI_SURFACE_PROXY_VIEW_ID (proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_get_timestamp:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Returns the presentation timestamp for this surface @proxy.
+ *
+ * Return value: the presentation timestamp
+ */
+GstClockTime
+gst_vaapi_surface_proxy_get_timestamp (GstVaapiSurfaceProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, 0);
+
+  return GST_VAAPI_SURFACE_PROXY_TIMESTAMP (proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_get_duration:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Returns the presentation duration for this surface @proxy.
+ *
+ * Return value: the presentation duration
+ */
+GstClockTime
+gst_vaapi_surface_proxy_get_duration (GstVaapiSurfaceProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, 0);
+
+  return GST_VAAPI_SURFACE_PROXY_DURATION (proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_set_destroy_notify:
+ * @proxy: a @GstVaapiSurfaceProxy
+ * @destroy_func: a #GDestroyNotify function
+ * @user_data: some extra data to pass to the @destroy_func function
+ *
+ * Sets @destroy_func as the function to call when the surface @proxy
+ * was released. At this point, the proxy object is considered
+ * released, i.e. the underlying data storage is no longer valid and
+ * the callback function shall not expect anything from that.
+ */
+void
+gst_vaapi_surface_proxy_set_destroy_notify (GstVaapiSurfaceProxy * proxy,
+    GDestroyNotify destroy_func, gpointer user_data)
+{
+  g_return_if_fail (proxy != NULL);
+
+  proxy->destroy_func = destroy_func;
+  proxy->destroy_data = user_data;
+}
+
+/**
+ * gst_vaapi_surface_proxy_get_crop_rect:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Returns the #GstVaapiRectangle stored in the @proxy and that
+ * represents the cropping rectangle for the underlying surface to be
+ * used for rendering.
+ *
+ * If no cropping rectangle was associated with the @proxy, then this
+ * function returns %NULL.
+ *
+ * Return value: the #GstVaapiRectangle, or %NULL if none was
+ *   associated with the surface proxy
+ */
+const GstVaapiRectangle *
+gst_vaapi_surface_proxy_get_crop_rect (GstVaapiSurfaceProxy * proxy)
+{
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  return GST_VAAPI_SURFACE_PROXY_CROP_RECT (proxy);
+}
+
+/**
+ * gst_vaapi_surface_proxy_set_crop_rect:
+ * @proxy: #GstVaapiSurfaceProxy
+ * @crop_rect: the #GstVaapiRectangle to be stored in @proxy
+ *
+ * Associates the @crop_rect with the @proxy
+ */
+void
+gst_vaapi_surface_proxy_set_crop_rect (GstVaapiSurfaceProxy * proxy,
+    const GstVaapiRectangle * crop_rect)
+{
+  g_return_if_fail (proxy != NULL);
+
+  proxy->has_crop_rect = crop_rect != NULL;
+  if (proxy->has_crop_rect)
+    proxy->crop_rect = *crop_rect;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfaceproxy.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfaceproxy.h
new file mode 100644 (file)
index 0000000..1dc218c
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ *  gstvaapisurfaceproxy.h - VA surface proxy
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_SURFACE_PROXY_H
+#define GST_VAAPI_SURFACE_PROXY_H
+
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapisurfacepool.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstVaapiSurfaceProxyFlags:
+ * @GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED: interlaced frame
+ * @GST_VAAPI_SURFACE_PROXY_FLAG_TFF: top-field-first
+ * @GST_VAAPI_SURFACE_PROXY_FLAG_RFF: repeat-first-field
+ * @GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD: only one field is available
+ * @GST_VAAPI_SURFACE_PROXY_FLAG_FFB: first frame in bundle, e.g. the first
+ *   view component of a MultiView Coded (MVC) frame
+ * @GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED: the underlying surface is
+ *   corrupted somehow, e.g. reconstructed from invalid references
+ * @GST_VAAPI_SURFACE_PROXY_FLAG_LAST: first flag that can be used by subclasses
+ *
+ * Flags for #GstVaapiDecoderFrame.
+ */
+typedef enum
+{
+  GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED = (1 << 0),
+  GST_VAAPI_SURFACE_PROXY_FLAG_TFF = (1 << 1),
+  GST_VAAPI_SURFACE_PROXY_FLAG_RFF = (1 << 2),
+  GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD = (1 << 3),
+  GST_VAAPI_SURFACE_PROXY_FLAG_FFB = (1 << 4),
+  GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED = (1 << 5),
+  GST_VAAPI_SURFACE_PROXY_FLAG_LAST = (1 << 8)
+} GstVaapiSurfaceProxyFlags;
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_SURFACE:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the #GstVaapiSurface of @proxy.
+ */
+#define GST_VAAPI_SURFACE_PROXY_SURFACE(proxy) \
+  gst_vaapi_surface_proxy_get_surface (proxy)
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_SURFACE_ID:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the VA surface ID of the underlying @proxy
+ * surface.
+ */
+#define GST_VAAPI_SURFACE_PROXY_SURFACE_ID(proxy) \
+  gst_vaapi_surface_proxy_get_surface_id (proxy)
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_VIEW_ID:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the decoded view ID of the underlying @proxy
+ * surface.
+ */
+#define GST_VAAPI_SURFACE_PROXY_VIEW_ID(proxy) \
+  gst_vaapi_surface_proxy_get_view_id (proxy)
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_TIMESTAMP:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the presentation timestamp of the
+ * underlying @proxy surface.
+ */
+#define GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy) \
+  gst_vaapi_surface_proxy_get_timestamp (proxy)
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_DURATION:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the presentation duration of the
+ * underlying @proxy surface.
+ */
+#define GST_VAAPI_SURFACE_PROXY_DURATION(proxy) \
+  gst_vaapi_surface_proxy_get_duration (proxy)
+
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_new (GstVaapiSurface * surface);
+
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_new_from_pool (GstVaapiSurfacePool * pool);
+
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_copy (GstVaapiSurfaceProxy * proxy);
+
+GstVaapiSurfaceProxy *
+gst_vaapi_surface_proxy_ref (GstVaapiSurfaceProxy * proxy);
+
+void
+gst_vaapi_surface_proxy_unref (GstVaapiSurfaceProxy * proxy);
+
+void
+gst_vaapi_surface_proxy_replace (GstVaapiSurfaceProxy ** old_proxy_ptr,
+    GstVaapiSurfaceProxy * new_proxy);
+
+guint
+gst_vaapi_surface_proxy_get_flags (GstVaapiSurfaceProxy * proxy);
+
+GstVaapiSurface *
+gst_vaapi_surface_proxy_get_surface (GstVaapiSurfaceProxy * proxy);
+
+GstVaapiID
+gst_vaapi_surface_proxy_get_surface_id (GstVaapiSurfaceProxy * proxy);
+
+guintptr
+gst_vaapi_surface_proxy_get_view_id (GstVaapiSurfaceProxy * proxy);
+
+GstClockTime
+gst_vaapi_surface_proxy_get_timestamp (GstVaapiSurfaceProxy * proxy);
+
+GstClockTime
+gst_vaapi_surface_proxy_get_duration (GstVaapiSurfaceProxy * proxy);
+
+void
+gst_vaapi_surface_proxy_set_destroy_notify (GstVaapiSurfaceProxy * proxy,
+    GDestroyNotify destroy_func, gpointer user_data);
+
+const GstVaapiRectangle *
+gst_vaapi_surface_proxy_get_crop_rect (GstVaapiSurfaceProxy * proxy);
+
+void
+gst_vaapi_surface_proxy_set_crop_rect (GstVaapiSurfaceProxy * proxy,
+    const GstVaapiRectangle * crop_rect);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_SURFACE_PROXY_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapisurfaceproxy_priv.h
new file mode 100644 (file)
index 0000000..6abe2a2
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ *  gstvaapisurfaceproxy_priv.h - VA surface proxy (private definitions)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_SURFACE_PROXY_PRIV_H
+#define GST_VAAPI_SURFACE_PROXY_PRIV_H
+
+#include "gstvaapiminiobject.h"
+#include "gstvaapisurfaceproxy.h"
+#include "gstvaapisurface_priv.h"
+
+#define GST_VAAPI_SURFACE_PROXY(obj) \
+  ((GstVaapiSurfaceProxy *) (obj))
+
+struct _GstVaapiSurfaceProxy
+{
+  /*< private >*/
+  GstVaapiMiniObject parent_instance;
+  GstVaapiSurfaceProxy *parent;
+
+  GstVaapiVideoPool *pool;
+  GstVaapiSurface *surface;
+  guintptr view_id;
+  GstClockTime timestamp;
+  GstClockTime duration;
+  GDestroyNotify destroy_func;
+  gpointer destroy_data;
+  GstVaapiRectangle crop_rect;
+  guint has_crop_rect:1;
+};
+
+#define GST_VAAPI_SURFACE_PROXY_FLAGS       GST_VAAPI_MINI_OBJECT_FLAGS
+#define GST_VAAPI_SURFACE_PROXY_FLAG_IS_SET GST_VAAPI_MINI_OBJECT_FLAG_IS_SET
+#define GST_VAAPI_SURFACE_PROXY_FLAG_SET    GST_VAAPI_MINI_OBJECT_FLAG_SET
+#define GST_VAAPI_SURFACE_PROXY_FLAG_UNSET  GST_VAAPI_MINI_OBJECT_FLAG_UNSET
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_SURFACE:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the #GstVaapiSurface of @proxy.
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_PROXY_SURFACE
+#define GST_VAAPI_SURFACE_PROXY_SURFACE(proxy) \
+  (GST_VAAPI_SURFACE_PROXY (proxy)->surface)
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_SURFACE_ID:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the VA surface ID of the underlying @proxy
+ * surface.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_PROXY_SURFACE_ID
+#define GST_VAAPI_SURFACE_PROXY_SURFACE_ID(proxy) \
+  (GST_VAAPI_SURFACE_ID (GST_VAAPI_SURFACE_PROXY (proxy)->surface))
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_VIEW_ID:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the decoded view ID of the underlying @proxy
+ * surface.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_PROXY_VIEW_ID
+#define GST_VAAPI_SURFACE_PROXY_VIEW_ID(proxy) \
+  (GST_VAAPI_SURFACE_PROXY (proxy)->view_id)
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_TIMESTAMP:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the presentation timestamp of the
+ * underlying @proxy surface.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_PROXY_TIMESTAMP
+#define GST_VAAPI_SURFACE_PROXY_TIMESTAMP(proxy) \
+  (GST_VAAPI_SURFACE_PROXY (proxy)->timestamp)
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_DURATION:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the presentation duration of the
+ * underlying @proxy surface.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_PROXY_DURATION
+#define GST_VAAPI_SURFACE_PROXY_DURATION(proxy) \
+  (GST_VAAPI_SURFACE_PROXY (proxy)->duration)
+
+/**
+ * GST_VAAPI_SURFACE_PROXY_CROP_RECT:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Macro that evaluates to the video cropping rectangle of the underlying @proxy surface.
+ *
+ * This is an internal macro that does not do any run-time type check.
+ */
+#undef  GST_VAAPI_SURFACE_PROXY_CROP_RECT
+#define GST_VAAPI_SURFACE_PROXY_CROP_RECT(proxy) \
+  (GST_VAAPI_SURFACE_PROXY (proxy)->has_crop_rect ? \
+     &GST_VAAPI_SURFACE_PROXY (proxy)->crop_rect : NULL)
+
+#endif /* GST_VAAPI_SURFACE_PROXY_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture.c
new file mode 100644 (file)
index 0000000..9bfc87b
--- /dev/null
@@ -0,0 +1,371 @@
+/*
+ *  gstvaapitexture.c - VA texture abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapitexture
+ * @short_description: VA/GLX texture abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapitexture.h"
+#include "gstvaapitexture_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_TEXTURE_ORIENTATION_FLAGS \
+  (GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED | \
+   GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED)
+
+#define GST_VAAPI_TEXTURE_PRIVATE_QUARK gst_vaapi_texture_private_quark ()
+static GQuark
+gst_vaapi_texture_private_quark (void)
+{
+  static gsize g_quark;
+
+  if (g_once_init_enter (&g_quark)) {
+    gsize quark = (gsize) g_quark_from_static_string ("GstVaapiTexturePrivate");
+    g_once_init_leave (&g_quark, quark);
+  }
+  return g_quark;
+}
+
+gpointer
+gst_vaapi_texture_get_private (GstVaapiTexture * texture)
+{
+  return gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (texture),
+      GST_VAAPI_TEXTURE_PRIVATE_QUARK);
+}
+
+void
+gst_vaapi_texture_set_private (GstVaapiTexture * texture, gpointer priv,
+    GDestroyNotify destroy)
+{
+  gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (texture),
+      GST_VAAPI_TEXTURE_PRIVATE_QUARK, (gpointer) priv, destroy);
+}
+
+static void
+gst_vaapi_texture_init (GstVaapiTexture * texture, GstVaapiID id,
+    guint target, guint format, guint width, guint height)
+{
+  texture->is_wrapped = id != GST_VAAPI_ID_INVALID;
+  GST_VAAPI_TEXTURE_ID (texture) = texture->is_wrapped ? id : 0;
+  texture->gl_target = target;
+  texture->gl_format = format;
+  texture->width = width;
+  texture->height = height;
+}
+
+static void
+gst_vaapi_texture_free (GstVaapiTexture * texture)
+{
+  gst_vaapi_display_replace (&GST_VAAPI_TEXTURE_DISPLAY (texture), NULL);
+  g_slice_free1 (sizeof (GstVaapiTexture), texture);
+}
+
+GST_DEFINE_MINI_OBJECT_TYPE (GstVaapiTexture, gst_vaapi_texture);
+
+GstVaapiTexture *
+gst_vaapi_texture_new_internal (GstVaapiDisplay * display, GstVaapiID id,
+    guint target, guint format, guint width, guint height)
+{
+  GstVaapiTexture *texture;
+
+  g_return_val_if_fail (display, NULL);
+  g_return_val_if_fail (target != 0, NULL);
+  g_return_val_if_fail (format != 0, NULL);
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+
+  texture = g_slice_alloc (sizeof (GstVaapiTexture));
+  if (!texture)
+    return NULL;
+
+  gst_mini_object_init (GST_MINI_OBJECT_CAST (texture), 0,
+      GST_TYPE_VAAPI_TEXTURE, NULL, NULL,
+      (GstMiniObjectFreeFunction) gst_vaapi_texture_free);
+
+  GST_VAAPI_TEXTURE_DISPLAY (texture) = gst_object_ref (display);
+
+  gst_vaapi_texture_init (texture, id, target, format, width, height);
+
+  return texture;
+}
+
+/**
+ * gst_vaapi_texture_new:
+ * @display: a #GstVaapiDisplay
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates a texture with the specified dimensions, @target and
+ * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or
+ * GL_BGRA formats are supported at this time.
+ *
+ * The application shall maintain the live GL context itself.
+ *
+ * Return value: the newly created #GstVaapiTexture object
+ */
+GstVaapiTexture *
+gst_vaapi_texture_new (GstVaapiDisplay * display, guint target, guint format,
+    guint width, guint height)
+{
+  GstVaapiDisplayClass *dpy_class;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (gst_vaapi_display_has_opengl (display), NULL);
+
+  dpy_class = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  if (G_UNLIKELY (!dpy_class->create_texture))
+    return NULL;
+  return dpy_class->create_texture (display, GST_VAAPI_ID_INVALID, target,
+      format, width, height);
+}
+
+/**
+ * gst_vaapi_texture_new_wrapped:
+ * @display: a #GstVaapiDisplay
+ * @texture_id: the foreign GL texture name to use
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the suggested width, in pixels
+ * @height: the suggested height, in pixels
+ *
+ * Creates a texture with the specified dimensions, @target and
+ * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or
+ * GL_BGRA formats are supported at this time.
+ *
+ * The size arguments @width and @height are only a suggestion. Should
+ * this be 0x0, then the actual size of the allocated texture storage
+ * would be either inherited from the original texture storage, if any
+ * and/or if possible, or derived from the VA surface in subsequent
+ * gst_vaapi_texture_put_surface() calls.
+ *
+ * The application shall maintain the live GL context itself.
+ *
+ * Return value: the newly created #GstVaapiTexture object
+ */
+GstVaapiTexture *
+gst_vaapi_texture_new_wrapped (GstVaapiDisplay * display, guint id,
+    guint target, guint format, guint width, guint height)
+{
+  GstVaapiDisplayClass *dpy_class;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (gst_vaapi_display_has_opengl (display), NULL);
+
+  dpy_class = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  if (G_UNLIKELY (!dpy_class->create_texture))
+    return NULL;
+  return dpy_class->create_texture (display, id, target, format, width, height);
+}
+
+/**
+ * gst_vaapi_texture_get_id:
+ * @texture: a #GstVaapiTexture
+ *
+ * Returns the underlying texture id of the @texture.
+ *
+ * Return value: the underlying texture id of the @texture
+ */
+guint
+gst_vaapi_texture_get_id (GstVaapiTexture * texture)
+{
+  g_return_val_if_fail (texture != NULL, 0);
+
+  return GST_VAAPI_TEXTURE_ID (texture);
+}
+
+/**
+ * gst_vaapi_texture_get_target:
+ * @texture: a #GstVaapiTexture
+ *
+ * Returns the @texture target type
+ *
+ * Return value: the texture target
+ */
+guint
+gst_vaapi_texture_get_target (GstVaapiTexture * texture)
+{
+  g_return_val_if_fail (texture != NULL, 0);
+
+  return GST_VAAPI_TEXTURE_TARGET (texture);
+}
+
+/**
+ * gst_vaapi_texture_get_format
+ * @texture: a #GstVaapiTexture
+ *
+ * Returns the @texture format
+ *
+ * Return value: the texture format
+ */
+guint
+gst_vaapi_texture_get_format (GstVaapiTexture * texture)
+{
+  g_return_val_if_fail (texture != NULL, 0);
+
+  return GST_VAAPI_TEXTURE_FORMAT (texture);
+}
+
+/**
+ * gst_vaapi_texture_get_width:
+ * @texture: a #GstVaapiTexture
+ *
+ * Returns the @texture width.
+ *
+ * Return value: the texture width, in pixels
+ */
+guint
+gst_vaapi_texture_get_width (GstVaapiTexture * texture)
+{
+  g_return_val_if_fail (texture != NULL, 0);
+
+  return GST_VAAPI_TEXTURE_WIDTH (texture);
+}
+
+/**
+ * gst_vaapi_texture_get_height:
+ * @texture: a #GstVaapiTexture
+ *
+ * Returns the @texture height.
+ *
+ * Return value: the texture height, in pixels.
+ */
+guint
+gst_vaapi_texture_get_height (GstVaapiTexture * texture)
+{
+  g_return_val_if_fail (texture != NULL, 0);
+
+  return GST_VAAPI_TEXTURE_HEIGHT (texture);
+}
+
+/**
+ * gst_vaapi_texture_get_size:
+ * @texture: a #GstVaapiTexture
+ * @width_ptr: return location for the width, or %NULL
+ * @height_ptr: return location for the height, or %NULL
+ *
+ * Retrieves the dimensions of a #GstVaapiTexture.
+ */
+void
+gst_vaapi_texture_get_size (GstVaapiTexture * texture,
+    guint * width_ptr, guint * height_ptr)
+{
+  g_return_if_fail (texture != NULL);
+
+  if (width_ptr)
+    *width_ptr = GST_VAAPI_TEXTURE_WIDTH (texture);
+
+  if (height_ptr)
+    *height_ptr = GST_VAAPI_TEXTURE_HEIGHT (texture);
+}
+
+/**
+ * gst_vaapi_texture_get_display:
+ * @texture: a #GstVaapiTexture
+ *
+ * Returns the #GstVaapiDisplay this @texture is bound to.
+ *
+ * Return value: the parent #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_texture_get_display (GstVaapiTexture * texture)
+{
+  g_return_val_if_fail (texture != NULL, NULL);
+  return GST_VAAPI_TEXTURE_DISPLAY (texture);
+}
+
+/**
+ * gst_vaapi_texture_get_orientation_flags:
+ * @texture: a #GstVaapiTexture
+ *
+ * Retrieves the texture memory layout flags, i.e. orientation.
+ *
+ * Return value: the #GstVaapiTextureOrientationFlags.
+ */
+guint
+gst_vaapi_texture_get_orientation_flags (GstVaapiTexture * texture)
+{
+  g_return_val_if_fail (texture != NULL, 0);
+
+  return GST_MINI_OBJECT_FLAGS (texture) & GST_VAAPI_TEXTURE_ORIENTATION_FLAGS;
+}
+
+/**
+ * gst_vaapi_texture_set_orientation_flags:
+ * @texture: a #GstVaapiTexture
+ * @flags: a bitmask of #GstVaapiTextureOrientationFlags
+ *
+ * Reset the texture orientation flags to the supplied set of
+ * @flags. This completely replaces the previously installed
+ * flags. So, should they still be needed, then they shall be
+ * retrieved first with gst_vaapi_texture_get_orientation_flags().
+ */
+void
+gst_vaapi_texture_set_orientation_flags (GstVaapiTexture * texture, guint flags)
+{
+  g_return_if_fail (texture != NULL);
+  g_return_if_fail ((flags & ~GST_VAAPI_TEXTURE_ORIENTATION_FLAGS) == 0);
+
+  GST_MINI_OBJECT_FLAG_UNSET (texture, GST_VAAPI_TEXTURE_ORIENTATION_FLAGS);
+  GST_MINI_OBJECT_FLAG_SET (texture, flags);
+}
+
+/**
+ * gst_vaapi_texture_put_surface:
+ * @texture: a #GstVaapiTexture
+ * @surface: a #GstVaapiSurface
+ * @flags: postprocessing flags. See #GstVaapiTextureRenderFlags
+ *
+ * Renders the @surface into the @texture. The @flags specify how
+ * de-interlacing (if needed), color space conversion, scaling and
+ * other postprocessing transformations are performed.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_texture_put_surface (GstVaapiTexture * texture,
+    GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags)
+{
+  GstVaapiRectangle rect;
+
+  g_return_val_if_fail (texture != NULL, FALSE);
+  g_return_val_if_fail (surface != NULL, FALSE);
+
+  if (!texture->put_surface)
+    return FALSE;
+
+  if (!crop_rect) {
+    rect.x = 0;
+    rect.y = 0;
+    gst_vaapi_surface_get_size (surface, &rect.width, &rect.height);
+    crop_rect = &rect;
+  }
+  return texture->put_surface (texture, surface, crop_rect, flags);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture.h
new file mode 100644 (file)
index 0000000..ef9b586
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ *  gstvaapitexture.h - VA texture abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_TEXTURE_H
+#define GST_VAAPI_TEXTURE_H
+
+#include <gst/vaapi/gstvaapitypes.h>
+#include <gst/vaapi/gstvaapisurface.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_TEXTURE(obj) \
+  ((GstVaapiTexture *)(obj))
+
+#define GST_TYPE_VAAPI_TEXTURE (gst_vaapi_texture_get_type ())
+
+/**
+ * GST_VAAPI_TEXTURE_DISPLAY:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the display associated with the @texture
+ */
+#define GST_VAAPI_TEXTURE_DISPLAY(texture) \
+  gst_vaapi_texture_get_display (GST_VAAPI_TEXTURE (texture))
+
+/**
+ * GST_VAAPI_TEXTURE_ID:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture id associated with the @texture
+ */
+#define GST_VAAPI_TEXTURE_ID(texture) \
+  gst_vaapi_texture_get_id (GST_VAAPI_TEXTURE (texture))
+
+/**
+ * GST_VAAPI_TEXTURE_TARGET:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture target associated with the @texture
+ */
+#define GST_VAAPI_TEXTURE_TARGET(texture) \
+  gst_vaapi_texture_get_target (GST_VAAPI_TEXTURE (texture))
+
+/**
+ * GST_VAAPI_TEXTURE_FORMAT:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture format associated with the @texture
+ */
+#define GST_VAAPI_TEXTURE_FORMAT(texture) \
+  gst_vaapi_texture_get_format (GST_VAAPI_TEXTURE (texture))
+
+/**
+ * GST_VAAPI_TEXTURE_WIDTH:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture width associated with the @texture
+ */
+#define GST_VAAPI_TEXTURE_WIDTH(texture) \
+  gst_vaapi_texture_get_width (GST_VAAPI_TEXTURE (texture))
+
+/**
+ * GST_VAAPI_TEXTURE_HEIGHT:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture height associated with the @texture
+ */
+#define GST_VAAPI_TEXTURE_HEIGHT(texture) \
+  gst_vaapi_texture_get_height (GST_VAAPI_TEXTURE (texture))
+
+typedef struct _GstVaapiTexture GstVaapiTexture;
+
+/**
+ * GstVaapiTextureOrientationFlags:
+ * @GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED: indicates whether
+ *   the right row comes first in memory.
+ * @GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED: indicates whether
+ *   the bottom line comes first in memory.
+ *
+ * Additional flags to indicate whether the texture data is organized
+ * in memory with the X or Y, or both, axis inverted. e.g. if only
+ * @GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED is set, this means
+ * that the bottom line comes first in memory, with pixels laid out
+ * from the left to the right.
+ */
+typedef enum {
+  GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED = (GST_MINI_OBJECT_FLAG_LAST << 1),
+  GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED = (GST_MINI_OBJECT_FLAG_LAST << 2),
+} GstVaapiTextureOrientationFlags;
+
+GType
+gst_vaapi_texture_get_type (void) G_GNUC_CONST;
+
+/**
+ * gst_vaapi_texture_unref: (skip)
+ * @texture: (transfer full): a #GstVaapiTexture.
+ *
+ * Decreases the refcount of the texture. If the refcount reaches 0, the
+ * texture will be freed.
+ */
+static inline void
+gst_vaapi_texture_unref (GstVaapiTexture * texture)
+{
+  gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture));
+}
+
+GstVaapiTexture *
+gst_vaapi_texture_new (GstVaapiDisplay * display, guint target, guint format,
+    guint width, guint height);
+
+GstVaapiTexture *
+gst_vaapi_texture_new_wrapped (GstVaapiDisplay * display, guint id,
+    guint target, guint format, guint width, guint height);
+
+guint
+gst_vaapi_texture_get_id (GstVaapiTexture * texture);
+
+GstVaapiDisplay *
+gst_vaapi_texture_get_display (GstVaapiTexture * texture);
+
+guint
+gst_vaapi_texture_get_target (GstVaapiTexture * texture);
+
+guint
+gst_vaapi_texture_get_format (GstVaapiTexture * texture);
+
+guint
+gst_vaapi_texture_get_width (GstVaapiTexture * texture);
+
+guint
+gst_vaapi_texture_get_height (GstVaapiTexture * texture);
+
+void
+gst_vaapi_texture_get_size (GstVaapiTexture * texture, guint * width_ptr,
+    guint * height_ptr);
+
+guint
+gst_vaapi_texture_get_orientation_flags (GstVaapiTexture * texture);
+
+void
+gst_vaapi_texture_set_orientation_flags (GstVaapiTexture * texture,
+    guint flags);
+
+gboolean
+gst_vaapi_texture_put_surface (GstVaapiTexture * texture,
+    GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect,
+    guint flags);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiTexture, gst_vaapi_texture_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_TEXTURE_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_egl.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_egl.c
new file mode 100644 (file)
index 0000000..49edcc8
--- /dev/null
@@ -0,0 +1,379 @@
+/*
+ *  gstvaapitexture_egl.c - VA/EGL texture abstraction
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapitexture_egl
+ * @short_description: VA/EGL texture abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapitexture.h"
+#include "gstvaapitexture_egl.h"
+#include "gstvaapitexture_priv.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiutils_egl.h"
+#include "gstvaapidisplay_egl.h"
+#include "gstvaapidisplay_egl_priv.h"
+#include "gstvaapisurface_egl.h"
+#include "gstvaapifilter.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+typedef struct _GstVaapiTextureEGLPrivate GstVaapiTextureEGLPrivate;
+
+/**
+ * GstVaapiTextureEGLPrivate:
+ *
+ * EGL texture specific fields.
+ */
+struct _GstVaapiTextureEGLPrivate
+{
+  /*< private > */
+  GstVaapiTexture *texture;
+  EglContext *egl_context;
+  EGLImageKHR egl_image;
+  GstVaapiSurface *surface;
+  GstVaapiFilter *filter;
+};
+
+typedef struct
+{
+  GstVaapiTexture *texture;
+  gboolean success;             /* result */
+} CreateTextureArgs;
+
+typedef struct
+{
+  GstVaapiTexture *texture;
+  GstVaapiSurface *surface;
+  const GstVaapiRectangle *crop_rect;
+  guint flags;
+  gboolean success;             /* result */
+} UploadSurfaceArgs;
+
+static gboolean
+create_objects (GstVaapiTexture * texture, GLuint texture_id)
+{
+  GstVaapiTextureEGLPrivate *const texture_egl =
+      gst_vaapi_texture_get_private (texture);
+  EglContext *const ctx = texture_egl->egl_context;
+  EglVTable *const vtable = egl_context_get_vtable (ctx, FALSE);
+  GLint attribs[3] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+  guint mem_types;
+
+  texture_egl->filter =
+      gst_vaapi_filter_new (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  if (!texture_egl->filter)
+    goto error_create_filter;
+
+  mem_types = gst_vaapi_filter_get_memory_types (texture_egl->filter);
+
+  texture_egl->egl_image =
+      vtable->eglCreateImageKHR (ctx->display->base.handle.p,
+      ctx->base.handle.p, EGL_GL_TEXTURE_2D_KHR,
+      (EGLClientBuffer) GSIZE_TO_POINTER (texture_id), attribs);
+  if (!texture_egl->egl_image)
+    goto error_create_image;
+
+  texture_egl->surface =
+      gst_vaapi_surface_new_with_egl_image (GST_VAAPI_TEXTURE_DISPLAY (texture),
+      texture_egl->egl_image, GST_VIDEO_FORMAT_RGBA, texture->width,
+      texture->height, mem_types);
+  if (!texture_egl->surface)
+    goto error_create_surface;
+
+  return TRUE;
+
+  /* ERRORS */
+error_create_image:
+  {
+    GST_ERROR ("failed to create EGL image from 2D texture %u", texture_id);
+    return FALSE;
+  }
+error_create_surface:
+  {
+    GST_ERROR ("failed to create VA surface from 2D texture %u", texture_id);
+    return FALSE;
+  }
+error_create_filter:
+  {
+    GST_ERROR ("failed to create VPP filter for color conversion");
+    return FALSE;
+  }
+}
+
+static gboolean
+do_create_texture_unlocked (GstVaapiTexture * texture)
+{
+  GLuint texture_id;
+  GstVaapiTextureEGLPrivate *texture_egl =
+      gst_vaapi_texture_get_private (texture);
+
+  if (texture->is_wrapped)
+    texture_id = GST_VAAPI_TEXTURE_ID (texture);
+  else {
+    texture_id = egl_create_texture (texture_egl->egl_context,
+        texture->gl_target, texture->gl_format,
+        texture->width, texture->height);
+    if (!texture_id)
+      return FALSE;
+    GST_VAAPI_TEXTURE_ID (texture) = texture_id;
+  }
+  return create_objects (texture, texture_id);
+}
+
+static void
+do_create_texture (CreateTextureArgs * args)
+{
+  GstVaapiTexture *const texture = args->texture;
+  GstVaapiTextureEGLPrivate *texture_egl =
+      gst_vaapi_texture_get_private (texture);
+  EglContextState old_cs;
+
+  args->success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  if (egl_context_set_current (texture_egl->egl_context, TRUE, &old_cs)) {
+    args->success = do_create_texture_unlocked (texture);
+    egl_context_set_current (texture_egl->egl_context, FALSE, &old_cs);
+  }
+  GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+}
+
+static void
+destroy_objects (GstVaapiTextureEGLPrivate * texture_egl)
+{
+  EglContext *const ctx = texture_egl->egl_context;
+  EglVTable *const vtable = egl_context_get_vtable (ctx, FALSE);
+
+  if (texture_egl->egl_image != EGL_NO_IMAGE_KHR) {
+    vtable->eglDestroyImageKHR (ctx->display->base.handle.p,
+        texture_egl->egl_image);
+    texture_egl->egl_image = EGL_NO_IMAGE_KHR;
+  }
+  gst_mini_object_replace ((GstMiniObject **) & texture_egl->surface, NULL);
+  gst_vaapi_filter_replace (&texture_egl->filter, NULL);
+}
+
+static void
+do_destroy_texture_unlocked (GstVaapiTextureEGLPrivate * texture_egl)
+{
+  GstVaapiTexture *const base_texture = texture_egl->texture;
+  const GLuint texture_id = GST_VAAPI_TEXTURE_ID (base_texture);
+
+  destroy_objects (texture_egl);
+
+  if (texture_id) {
+    if (!base_texture->is_wrapped)
+      egl_destroy_texture (texture_egl->egl_context, texture_id);
+    GST_VAAPI_TEXTURE_ID (base_texture) = 0;
+  }
+}
+
+static void
+do_destroy_texture (GstVaapiTextureEGLPrivate * texture_egl)
+{
+  EglContextState old_cs;
+  GstVaapiTexture *texture = texture_egl->texture;
+
+  GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  if (egl_context_set_current (texture_egl->egl_context, TRUE, &old_cs)) {
+    do_destroy_texture_unlocked (texture_egl);
+    egl_context_set_current (texture_egl->egl_context, FALSE, &old_cs);
+  }
+  GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  egl_object_replace (&texture_egl->egl_context, NULL);
+  g_free (texture_egl);
+}
+
+static gboolean
+do_upload_surface_unlocked (GstVaapiTextureEGLPrivate * texture_egl,
+    GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags)
+{
+  GstVaapiFilterStatus status;
+
+  if (!gst_vaapi_filter_set_cropping_rectangle (texture_egl->filter, crop_rect))
+    return FALSE;
+
+  status = gst_vaapi_filter_process (texture_egl->filter, surface,
+      texture_egl->surface, flags);
+  if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
+    return FALSE;
+  return TRUE;
+}
+
+static void
+do_upload_surface (UploadSurfaceArgs * args)
+{
+  GstVaapiTexture *const texture = args->texture;
+  GstVaapiTextureEGLPrivate *texture_egl =
+      gst_vaapi_texture_get_private (texture);
+  EglContextState old_cs;
+
+  args->success = FALSE;
+
+  GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  if (egl_context_set_current (texture_egl->egl_context, TRUE, &old_cs)) {
+    args->success = do_upload_surface_unlocked (texture_egl, args->surface,
+        args->crop_rect, args->flags);
+    egl_context_set_current (texture_egl->egl_context, FALSE, &old_cs);
+  }
+  GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+}
+
+static gboolean
+gst_vaapi_texture_egl_create (GstVaapiTexture * texture)
+{
+  CreateTextureArgs args = { texture };
+  GstVaapiDisplayEGL *display =
+      GST_VAAPI_DISPLAY_EGL (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  GstVaapiTextureEGLPrivate *texture_egl =
+      gst_vaapi_texture_get_private (texture);
+
+  if (GST_VAAPI_TEXTURE (texture)->is_wrapped) {
+    if (!gst_vaapi_display_egl_set_current_display (display))
+      return FALSE;
+  }
+
+  egl_object_replace (&texture_egl->egl_context,
+      GST_VAAPI_DISPLAY_EGL_CONTEXT (display));
+
+  return egl_context_run (texture_egl->egl_context,
+      (EglContextRunFunc) do_create_texture, &args) && args.success;
+}
+
+static void
+gst_vaapi_texture_egl_destroy (GstVaapiTextureEGLPrivate * texture_egl)
+{
+  egl_context_run (texture_egl->egl_context,
+      (EglContextRunFunc) do_destroy_texture, texture_egl);
+}
+
+static gboolean
+gst_vaapi_texture_egl_put_surface (GstVaapiTexture * texture,
+    GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags)
+{
+  UploadSurfaceArgs args = { texture, surface, crop_rect, flags };
+  GstVaapiTextureEGLPrivate *texture_egl =
+      gst_vaapi_texture_get_private (texture);
+
+  return egl_context_run (texture_egl->egl_context,
+      (EglContextRunFunc) do_upload_surface, &args) && args.success;
+}
+
+static GstVaapiTexture *
+gst_vaapi_texture_egl_new_internal (GstVaapiTexture * texture)
+{
+  GstVaapiTextureEGLPrivate *texture_egl;
+
+  texture->put_surface = gst_vaapi_texture_egl_put_surface;
+
+  texture_egl = g_malloc0 (sizeof (GstVaapiTextureEGLPrivate));
+  if (!texture_egl) {
+    gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture));
+    return NULL;
+  }
+  texture_egl->texture = texture;
+  gst_vaapi_texture_set_private (texture, texture_egl,
+      (GDestroyNotify) gst_vaapi_texture_egl_destroy);
+
+  if (!gst_vaapi_texture_egl_create (texture)) {
+    gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture));
+    return NULL;
+  }
+
+  return texture;
+}
+
+/**
+ * gst_vaapi_texture_egl_new:
+ * @display: a #GstVaapiDisplay
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates a texture with the specified dimensions, @target and
+ * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or
+ * GL_BGRA formats are supported at this time.
+ *
+ * The application shall maintain the live EGL context itself. That
+ * is, gst_vaapi_window_egl_make_current() must be called beforehand,
+ * or any other function like eglMakeCurrent() if the context is
+ * managed outside of this library.
+ *
+ * Return value: the newly created #GstVaapiTexture object
+ */
+GstVaapiTexture *
+gst_vaapi_texture_egl_new (GstVaapiDisplay * display, guint target,
+    guint format, guint width, guint height)
+{
+  GstVaapiTexture *texture;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), NULL);
+
+  texture = gst_vaapi_texture_new_internal (display, GST_VAAPI_ID_INVALID,
+      target, format, width, height);
+  if (!texture)
+    return NULL;
+
+  return gst_vaapi_texture_egl_new_internal (texture);
+}
+
+/**
+ * gst_vaapi_texture_egl_new_wrapped:
+ * @display: a #GstVaapiDisplay
+ * @texture_id: the foreign GL texture name to use
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the texture width, in pixels
+ * @height: the texture height, in pixels
+ *
+ * Creates a texture from an existing GL texture, with the specified
+ * @target and @format. Note that only GL_TEXTURE_2D @target and
+ * GL_RGBA or GL_BGRA formats are supported at this time.
+ *
+ * The application shall maintain the live EGL context itself. That
+ * is, gst_vaapi_window_egl_make_current() must be called beforehand,
+ * or any other function like eglMakeCurrent() if the context is
+ * managed outside of this library.
+ *
+ * Return value: the newly created #GstVaapiTexture object
+ */
+GstVaapiTexture *
+gst_vaapi_texture_egl_new_wrapped (GstVaapiDisplay * display,
+    guint texture_id, guint target, GLenum format, guint width, guint height)
+{
+  GstVaapiTexture *texture;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), NULL);
+  g_return_val_if_fail (texture_id != GL_NONE, NULL);
+
+  texture = gst_vaapi_texture_new_internal (display, texture_id,
+      target, format, width, height);
+  if (!texture)
+    return texture;
+
+  return gst_vaapi_texture_egl_new_internal (texture);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_egl.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_egl.h
new file mode 100644 (file)
index 0000000..848c15d
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  gstvaapitexture_egl.h - VA/EGL texture abstraction
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_TEXTURE_EGL_H
+#define GST_VAAPI_TEXTURE_EGL_H
+
+#include <gst/vaapi/gstvaapitexture.h>
+
+G_BEGIN_DECLS
+
+GstVaapiTexture *
+gst_vaapi_texture_egl_new (GstVaapiDisplay * display, guint target,
+    guint format, guint width, guint height);
+
+GstVaapiTexture *
+gst_vaapi_texture_egl_new_wrapped (GstVaapiDisplay * display, guint id,
+    guint target, guint format, guint width, guint height);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_TEXTURE_EGL_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_glx.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_glx.c
new file mode 100644 (file)
index 0000000..76f450a
--- /dev/null
@@ -0,0 +1,431 @@
+/*
+ *  gstvaapitexture_glx.c - VA/GLX texture abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapitexture_glx
+ * @short_description: VA/GLX texture abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapitexture.h"
+#include "gstvaapitexture_glx.h"
+#include "gstvaapitexture_priv.h"
+#include "gstvaapisurface_priv.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiutils_glx.h"
+#include "gstvaapidisplay_glx.h"
+#include "gstvaapidisplay_x11_priv.h"
+#include "gstvaapidisplay_glx_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_TEXTURE_GLX(texture) \
+  ((GstVaapiTextureGLX *)(texture))
+
+typedef struct _GstVaapiTextureGLXPrivate GstVaapiTextureGLXPrivate;
+
+/**
+ * GstVaapiTextureGLXPrivate:
+ *
+ * GLX texture specific fields.
+ */
+struct _GstVaapiTextureGLXPrivate
+{
+  /*< private > */
+  GstVaapiTexture *texture;
+  GLContextState *gl_context;
+  GLPixmapObject *pixo;
+  GLFramebufferObject *fbo;
+};
+
+static gboolean
+gst_vaapi_texture_glx_put_surface (GstVaapiTexture * texture,
+    GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect,
+    guint flags);
+
+static void
+destroy_objects (GstVaapiTextureGLXPrivate * texture)
+{
+  GLContextState old_cs;
+
+  if (texture->gl_context)
+    gl_set_current_context (texture->gl_context, &old_cs);
+
+  if (texture->fbo) {
+    gl_destroy_framebuffer_object (texture->fbo);
+    texture->fbo = NULL;
+  }
+
+  if (texture->pixo) {
+    gl_destroy_pixmap_object (texture->pixo);
+    texture->pixo = NULL;
+  }
+
+  if (texture->gl_context) {
+    gl_set_current_context (&old_cs, NULL);
+    gl_destroy_context (texture->gl_context);
+    texture->gl_context = NULL;
+  }
+}
+
+static void
+destroy_texture_unlocked (GstVaapiTextureGLXPrivate * texture_glx)
+{
+  GstVaapiTexture *texture = texture_glx->texture;
+  const guint texture_id = GST_VAAPI_TEXTURE_ID (texture);
+
+  destroy_objects (texture_glx);
+
+  if (texture_id) {
+    if (!texture->is_wrapped)
+      glDeleteTextures (1, &texture_id);
+    GST_VAAPI_TEXTURE_ID (texture) = 0;
+  }
+}
+
+static void
+gst_vaapi_texture_glx_destroy (GstVaapiTextureGLXPrivate * texture_glx)
+{
+  GstVaapiTexture *texture = texture_glx->texture;
+
+  GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  destroy_texture_unlocked (texture_glx);
+  GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+
+  g_free (texture_glx);
+}
+
+static gboolean
+create_objects (GstVaapiTexture * texture, guint texture_id)
+{
+  GstVaapiTextureGLXPrivate *texture_glx =
+      gst_vaapi_texture_get_private (texture);
+  Display *const dpy =
+      GST_VAAPI_DISPLAY_NATIVE (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  GLContextState old_cs;
+  gboolean success = FALSE;
+
+  gl_get_current_context (&old_cs);
+
+  texture_glx->gl_context =
+      gl_create_context (dpy, DefaultScreen (dpy), &old_cs);
+  if (!texture_glx->gl_context
+      || !gl_set_current_context (texture_glx->gl_context, NULL))
+    return FALSE;
+
+  texture_glx->pixo = gl_create_pixmap_object (dpy,
+      texture->width, texture->height);
+  if (!texture_glx->pixo) {
+    GST_ERROR ("failed to create GLX pixmap");
+    goto out_reset_context;
+  }
+
+  texture_glx->fbo = gl_create_framebuffer_object (texture->gl_target,
+      texture_id, texture->width, texture->height);
+  if (!texture_glx->fbo) {
+    GST_ERROR ("failed to create FBO");
+    goto out_reset_context;
+  }
+  success = TRUE;
+
+out_reset_context:
+  gl_set_current_context (&old_cs, NULL);
+  return success;
+}
+
+static gboolean
+create_texture_unlocked (GstVaapiTexture * texture)
+{
+  guint texture_id;
+
+  if (texture->is_wrapped)
+    texture_id = GST_VAAPI_TEXTURE_ID (texture);
+  else {
+    texture_id = gl_create_texture (texture->gl_target, texture->gl_format,
+        texture->width, texture->height);
+    if (!texture_id)
+      return FALSE;
+    GST_VAAPI_TEXTURE_ID (texture) = texture_id;
+  }
+  return create_objects (texture, texture_id);
+}
+
+static gboolean
+gst_vaapi_texture_glx_create (GstVaapiTexture * texture)
+{
+  gboolean success;
+
+  GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  success = create_texture_unlocked (texture);
+  GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  return success;
+}
+
+
+static GstVaapiTexture *
+gst_vaapi_texture_glx_new_internal (GstVaapiTexture * texture)
+{
+  GstVaapiTextureGLXPrivate *texture_glx;
+
+  texture->put_surface = gst_vaapi_texture_glx_put_surface;
+
+  texture_glx = g_malloc0 (sizeof (GstVaapiTextureGLXPrivate));
+  if (!texture_glx) {
+    gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture));
+    return NULL;
+  }
+  texture_glx->texture = texture;
+  gst_vaapi_texture_set_private (texture, texture_glx,
+      (GDestroyNotify) gst_vaapi_texture_glx_destroy);
+
+  if (!gst_vaapi_texture_glx_create (texture)) {
+    gst_mini_object_unref (GST_MINI_OBJECT_CAST (texture));
+    return NULL;
+  }
+
+  return texture;
+}
+
+/**
+ * gst_vaapi_texture_glx_new:
+ * @display: a #GstVaapiDisplay
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates a texture with the specified dimensions, @target and
+ * @format. Note that only GL_TEXTURE_2D @target and GL_RGBA or
+ * GL_BGRA formats are supported at this time.
+ *
+ * The application shall maintain the live GL context itself. That is,
+ * gst_vaapi_window_glx_make_current() must be called beforehand, or
+ * any other function like glXMakeCurrent() if the context is managed
+ * outside of this library.
+ *
+ * Return value: the newly created #GstVaapiTexture object
+ */
+GstVaapiTexture *
+gst_vaapi_texture_glx_new (GstVaapiDisplay * display, guint target,
+    guint format, guint width, guint height)
+{
+  GstVaapiTexture *texture;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_GLX (display), NULL);
+
+  texture = gst_vaapi_texture_new_internal (display, GST_VAAPI_ID_INVALID,
+      target, format, width, height);
+  if (!texture)
+    return NULL;
+
+  return gst_vaapi_texture_glx_new_internal (texture);
+}
+
+/* Can we assume that the vsink/app context API won't change ever? */
+GstVaapiGLApi
+gl_get_curent_api_once ()
+{
+  static GstVaapiGLApi cur_api = GST_VAAPI_GL_API_NONE;
+  static gsize _init = 0;
+
+  if (g_once_init_enter (&_init)) {
+    cur_api = gl_get_current_api (NULL, NULL);
+    g_once_init_leave (&_init, 1);
+  }
+
+  return cur_api;
+}
+
+/**
+ * gst_vaapi_texture_glx_new_wrapped:
+ * @display: a #GstVaapiDisplay
+ * @texture_id: the foreign GL texture name to use
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ *
+ * Creates a texture from an existing GL texture, with the specified
+ * @target and @format. Note that only GL_TEXTURE_2D @target and
+ * GL_RGBA or GL_BGRA formats are supported at this time. The
+ * dimensions will be retrieved from the @texture_id.
+ *
+ * The application shall maintain the live GL context itself. That is,
+ * gst_vaapi_window_glx_make_current() must be called beforehand, or
+ * any other function like glXMakeCurrent() if the context is managed
+ * outside of this library.
+ *
+ * Return value: the newly created #GstVaapiTexture object
+ */
+GstVaapiTexture *
+gst_vaapi_texture_glx_new_wrapped (GstVaapiDisplay * display,
+    guint texture_id, guint target, guint format)
+{
+  guint width, height, border_width = 0;
+  GLTextureState ts = { 0, };
+  gboolean success;
+  GstVaapiGLApi gl_api;
+  GstVaapiTexture *texture;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_GLX (display), NULL);
+  g_return_val_if_fail (texture_id != GL_NONE, NULL);
+  g_return_val_if_fail (target == GL_TEXTURE_2D, NULL);
+  g_return_val_if_fail (format == GL_RGBA || format == GL_BGRA, NULL);
+
+  gl_api = gl_get_curent_api_once ();
+  if (gl_api != GST_VAAPI_GL_API_OPENGL && gl_api != GST_VAAPI_GL_API_OPENGL3)
+    return NULL;
+
+  /* Check texture dimensions */
+  GST_VAAPI_DISPLAY_LOCK (display);
+  if (gl_api == GST_VAAPI_GL_API_OPENGL)
+    success = gl_bind_texture (&ts, target, texture_id);
+  else
+    success = gl3_bind_texture_2d (&ts, target, texture_id);
+
+  if (success) {
+    if (!gl_get_texture_param (target, GL_TEXTURE_WIDTH, &width) ||
+        !gl_get_texture_param (target, GL_TEXTURE_HEIGHT, &height))
+      success = FALSE;
+    if (success && gl_api == GST_VAAPI_GL_API_OPENGL)
+      success = gl_get_texture_param (target, GL_TEXTURE_BORDER, &border_width);
+    gl_unbind_texture (&ts);
+  }
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!success)
+    return NULL;
+
+  width -= 2 * border_width;
+  height -= 2 * border_width;
+  g_return_val_if_fail (width > 0, NULL);
+  g_return_val_if_fail (height > 0, NULL);
+
+  texture = gst_vaapi_texture_new_internal (display, texture_id, target,
+      format, width, height);
+  if (!texture)
+    return NULL;
+
+  return gst_vaapi_texture_glx_new_internal (texture);
+}
+
+/**
+ * gst_vaapi_texture_put_surface:
+ * @texture: a #GstVaapiTexture
+ * @surface: a #GstVaapiSurface
+ * @flags: postprocessing flags. See #GstVaapiTextureRenderFlags
+ *
+ * Renders the @surface into the àtexture. The @flags specify how
+ * de-interlacing (if needed), color space conversion, scaling and
+ * other postprocessing transformations are performed.
+ *
+ * Return value: %TRUE on success
+ */
+static gboolean
+gst_vaapi_texture_glx_put_surface_unlocked (GstVaapiTexture * texture,
+    GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags)
+{
+  GstVaapiTextureGLXPrivate *texture_glx =
+      gst_vaapi_texture_get_private (texture);
+  VAStatus status;
+  GLContextState old_cs;
+  gboolean success = FALSE;
+
+  const GLfloat *txc, *tyc;
+  static const GLfloat g_texcoords[2][2] = {
+    {0.0f, 1.0f},
+    {1.0f, 0.0f},
+  };
+
+  status = vaPutSurface (GST_VAAPI_DISPLAY_VADISPLAY (GST_VAAPI_TEXTURE_DISPLAY
+          (texture)), GST_VAAPI_SURFACE_ID (surface), texture_glx->pixo->pixmap,
+      crop_rect->x, crop_rect->y, crop_rect->width, crop_rect->height, 0, 0,
+      texture->width, texture->height, NULL, 0,
+      from_GstVaapiSurfaceRenderFlags (flags));
+  if (!vaapi_check_status (status, "vaPutSurface() [TFP]"))
+    return FALSE;
+
+  if (texture_glx->gl_context &&
+      !gl_set_current_context (texture_glx->gl_context, &old_cs))
+    return FALSE;
+
+  if (!gl_bind_framebuffer_object (texture_glx->fbo)) {
+    GST_ERROR ("failed to bind FBO");
+    goto out_reset_context;
+  }
+
+  if (!gst_vaapi_surface_sync (surface)) {
+    GST_ERROR ("failed to render surface to pixmap");
+    goto out_unbind_fbo;
+  }
+
+  if (!gl_bind_pixmap_object (texture_glx->pixo)) {
+    GST_ERROR ("could not bind GLX pixmap");
+    goto out_unbind_fbo;
+  }
+
+  flags = GST_MINI_OBJECT_FLAGS (texture);
+  txc = g_texcoords[! !(flags & GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED)];
+  tyc = g_texcoords[! !(flags & GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED)];
+
+  glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
+  glBegin (GL_QUADS);
+  {
+    glTexCoord2f (txc[0], tyc[0]);
+    glVertex2i (0, 0);
+    glTexCoord2f (txc[0], tyc[1]);
+    glVertex2i (0, texture->height);
+    glTexCoord2f (txc[1], tyc[1]);
+    glVertex2i (texture->width, texture->height);
+    glTexCoord2f (txc[1], tyc[0]);
+    glVertex2i (texture->width, 0);
+  }
+  glEnd ();
+
+  if (!gl_unbind_pixmap_object (texture_glx->pixo)) {
+    GST_ERROR ("failed to release GLX pixmap");
+    goto out_unbind_fbo;
+  }
+  success = TRUE;
+
+out_unbind_fbo:
+  if (!gl_unbind_framebuffer_object (texture_glx->fbo))
+    success = FALSE;
+out_reset_context:
+  if (texture_glx->gl_context && !gl_set_current_context (&old_cs, NULL))
+    success = FALSE;
+  return success;
+}
+
+static gboolean
+gst_vaapi_texture_glx_put_surface (GstVaapiTexture * texture,
+    GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags)
+{
+  gboolean success;
+
+  GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  success = gst_vaapi_texture_glx_put_surface_unlocked (texture, surface,
+      crop_rect, flags);
+  GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_TEXTURE_DISPLAY (texture));
+  return success;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_glx.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_glx.h
new file mode 100644 (file)
index 0000000..db8ddbb
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *  gstvaapitexture_glx.h - VA/GLX texture abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_TEXTURE_GLX_H
+#define GST_VAAPI_TEXTURE_GLX_H
+
+#include <gst/vaapi/gstvaapitexture.h>
+
+G_BEGIN_DECLS
+
+GstVaapiTexture *
+gst_vaapi_texture_glx_new (GstVaapiDisplay * display, guint target,
+    guint format, guint width, guint height);
+
+GstVaapiTexture *
+gst_vaapi_texture_glx_new_wrapped (GstVaapiDisplay * display, guint id,
+    guint target, guint format);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_TEXTURE_GLX_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexture_priv.h
new file mode 100644 (file)
index 0000000..e22df90
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *  gstvaapitexture_priv.h - VA texture abstraction (private definitions)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_TEXTURE_PRIV_H
+#define GST_VAAPI_TEXTURE_PRIV_H
+
+G_BEGIN_DECLS
+
+/**
+ * GST_VAAPI_TEXTURE_DISPLAY:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the @texture's display.
+ */
+#undef GST_VAAPI_TEXTURE_DISPLAY
+#define GST_VAAPI_TEXTURE_DISPLAY(texture) \
+  (GST_VAAPI_TEXTURE (texture)->display)
+
+/**
+ * GST_VAAPI_TEXTURE_ID:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture id associated with the @texture
+ */
+#undef  GST_VAAPI_TEXTURE_ID
+#define GST_VAAPI_TEXTURE_ID(texture) \
+  (GST_VAAPI_TEXTURE (texture)->object_id)
+
+/**
+ * GST_VAAPI_TEXTURE_TARGET:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture target associated with the @texture
+ */
+#undef  GST_VAAPI_TEXTURE_TARGET
+#define GST_VAAPI_TEXTURE_TARGET(texture) \
+  (GST_VAAPI_TEXTURE (texture)->gl_target)
+
+/**
+ * GST_VAAPI_TEXTURE_FORMAT:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture format associated with the @texture
+ */
+#undef  GST_VAAPI_TEXTURE_FORMAT
+#define GST_VAAPI_TEXTURE_FORMAT(texture) \
+  (GST_VAAPI_TEXTURE (texture)->gl_format)
+
+/**
+ * GST_VAAPI_TEXTURE_WIDTH:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture width associated with the @texture
+ */
+#undef  GST_VAAPI_TEXTURE_WIDTH
+#define GST_VAAPI_TEXTURE_WIDTH(texture) \
+  (GST_VAAPI_TEXTURE (texture)->width)
+
+/**
+ * GST_VAAPI_TEXTURE_HEIGHT:
+ * @texture: a #GstVaapiTexture
+ *
+ * Macro that evaluates to the GL texture height associated with the @texture
+ */
+#undef  GST_VAAPI_TEXTURE_HEIGHT
+#define GST_VAAPI_TEXTURE_HEIGHT(texture) \
+  (GST_VAAPI_TEXTURE (texture)->height)
+
+/* GstVaapiTextureClass hooks */
+typedef gboolean (*GstVaapiTexturePutSurfaceFunc) (GstVaapiTexture * texture,
+    GstVaapiSurface * surface, const GstVaapiRectangle * crop_rect, guint flags);
+
+/**
+ * GstVaapiTexture:
+ *
+ * Base class for API-dependent textures.
+ */
+struct _GstVaapiTexture {
+  /*< private >*/
+  GstMiniObject mini_object;
+  GstVaapiDisplay *display;
+  GstVaapiID object_id;
+
+  /*< protected >*/
+  GstVaapiTexturePutSurfaceFunc put_surface;
+  guint gl_target;
+  guint gl_format;
+  guint width;
+  guint height;
+  guint is_wrapped:1;
+};
+
+GstVaapiTexture *
+gst_vaapi_texture_new_internal (GstVaapiDisplay * display, GstVaapiID id,
+    guint target, guint format, guint width, guint height);
+
+gpointer
+gst_vaapi_texture_get_private (GstVaapiTexture * texture);
+
+void
+gst_vaapi_texture_set_private (GstVaapiTexture * texture, gpointer priv,
+    GDestroyNotify destroy);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_TEXTURE_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexturemap.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexturemap.c
new file mode 100644 (file)
index 0000000..1ca7638
--- /dev/null
@@ -0,0 +1,165 @@
+/*
+ *  gstvaapitexture.c - VA texture Hash map
+ *
+ *  Copyright (C) 2016 Intel Corporation
+ *  Copyright (C) 2016 Igalia S.L.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapitexturemap
+ * @short_description: VA/GLX/EGL texture hash map abstraction
+ */
+
+#include "gstvaapitexturemap.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/**
+ * GstVaapiTextureMap:
+ *
+ * Base class for API-dependent texture map.
+ */
+struct _GstVaapiTextureMap
+{
+  GstObject parent_instance;
+
+  /*< private > */
+  GHashTable *texture_map;
+};
+
+/**
+ * GstVaapiTextureMapClass:
+ *
+ * Base class for API-dependent texture map.
+ */
+struct _GstVaapiTextureMapClass
+{
+  GstObjectClass parent_class;
+};
+
+#define MAX_NUM_TEXTURE 10
+
+G_DEFINE_TYPE (GstVaapiTextureMap, gst_vaapi_texture_map, GST_TYPE_OBJECT);
+
+static void
+gst_vaapi_texture_map_init (GstVaapiTextureMap * map)
+{
+  map->texture_map =
+      g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL,
+      (GDestroyNotify) gst_mini_object_unref);
+}
+
+static void
+gst_vaapi_texture_map_finalize (GObject * object)
+{
+  GstVaapiTextureMap *map = GST_VAAPI_TEXTURE_MAP (object);
+
+  if (map->texture_map) {
+    g_hash_table_remove_all (map->texture_map);
+    g_hash_table_destroy (map->texture_map);
+  }
+
+  G_OBJECT_CLASS (gst_vaapi_texture_map_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_texture_map_class_init (GstVaapiTextureMapClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_texture_map_finalize;
+}
+
+/**
+ * gst_vaapi_texture_map_new:
+ *
+ * Creates a texture hash map.
+ *
+ * Return value: the newly created #GstVaapiTextureMap object
+ */
+GstVaapiTextureMap *
+gst_vaapi_texture_map_new (void)
+{
+  GstVaapiTextureMap *map;
+
+  map = g_object_new (GST_TYPE_VAAPI_TEXTURE_MAP, NULL);
+  return map;
+}
+
+/**
+ * gst_vaapi_texture_map_add:
+ * @map: a #GstVaapiTextureMap instance
+ * @texture: a #GstVaapiTexture instance to add
+ * @id: the id of the GLTexture
+ *
+ * Adds @texture into the @map table.
+ *
+ * Returns: %TRUE if @texture was inserted correctly.
+ **/
+gboolean
+gst_vaapi_texture_map_add (GstVaapiTextureMap * map, GstVaapiTexture * texture,
+    guint id)
+{
+  g_return_val_if_fail (map != NULL, FALSE);
+  g_return_val_if_fail (map->texture_map != NULL, FALSE);
+  g_return_val_if_fail (texture != NULL, FALSE);
+
+  if (g_hash_table_size (map->texture_map) > MAX_NUM_TEXTURE) {
+    GST_WARNING ("Texture map is full");
+    return FALSE;
+  }
+
+  g_hash_table_insert (map->texture_map, GUINT_TO_POINTER (id), texture);
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_texture_map_lookup:
+ * @map: a #GstVaapiTextureMap instance
+ * @id: the id of the GLTexture
+ *
+ * Search for the #GstVaapiTexture associated with the GLTexture @id
+ * in the @map.
+ *
+ * Returns: a pointer to #GstVaapiTexture if found; otherwise %NULL.
+ **/
+GstVaapiTexture *
+gst_vaapi_texture_map_lookup (GstVaapiTextureMap * map, guint id)
+{
+  g_return_val_if_fail (map != NULL, NULL);
+  g_return_val_if_fail (map->texture_map != NULL, NULL);
+
+  return g_hash_table_lookup (map->texture_map, GUINT_TO_POINTER (id));
+}
+
+/**
+ * gst_vaapi_texture_map_reset:
+ * @map: a #GstVaapiTextureMap instance
+ *
+ * Removes all the #GstVaapiTexture in the @map.
+ **/
+void
+gst_vaapi_texture_map_reset (GstVaapiTextureMap * map)
+{
+  g_return_if_fail (map != NULL);
+  g_return_if_fail (map->texture_map != NULL);
+
+  g_hash_table_remove_all (map->texture_map);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexturemap.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitexturemap.h
new file mode 100644 (file)
index 0000000..0e869bb
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  gstvaapitexturemap.h - VA texture Hash map
+ *
+ *  Copyright (C) 2016 Intel Corporation
+ *  Copyright (C) 2016 Igalia S.L.
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_TEXTURE_MAP_H
+#define GST_VAAPI_TEXTURE_MAP_H
+
+#include <gst/vaapi/gstvaapitexture.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiTextureMap GstVaapiTextureMap;
+typedef struct _GstVaapiTextureMapClass GstVaapiTextureMapClass;
+
+#define GST_TYPE_VAAPI_TEXTURE_MAP \
+  (gst_vaapi_texture_map_get_type ())
+#define GST_VAAPI_TEXTURE_MAP(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_TEXTURE_MAP, GstVaapiTextureMap))
+
+GstVaapiTextureMap *
+gst_vaapi_texture_map_new (void);
+
+gboolean
+gst_vaapi_texture_map_add (GstVaapiTextureMap * map,
+                           GstVaapiTexture * texture,
+                           guint id);
+
+GstVaapiTexture *
+gst_vaapi_texture_map_lookup (GstVaapiTextureMap * map,
+                              guint id);
+
+void
+gst_vaapi_texture_map_reset (GstVaapiTextureMap * map);
+
+GType
+gst_vaapi_texture_map_get_type (void) G_GNUC_CONST;
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiTextureMap, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_TEXTURE_MAP_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitypes.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapitypes.h
new file mode 100644 (file)
index 0000000..7bbcb4d
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *  gstvaapitypes.h - Basic types
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_TYPES_H
+#define GST_VAAPI_TYPES_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstVaapiID:
+ *
+ * An integer large enough to hold a generic VA id or a pointer
+ * wherever necessary.
+ */
+typedef gsize GstVaapiID;
+
+/**
+ * GST_VAAPI_ID:
+ * @id: an arbitrary integer value
+ *
+ * Macro that creates a #GstVaapiID from @id.
+ */
+#define GST_VAAPI_ID(id) ((GstVaapiID)(id))
+
+/**
+ * GST_VAAPI_ID_INVALID:
+ *
+ * Macro that evaluates to an invalid #GstVaapiID value.
+ */
+#define GST_VAAPI_ID_INVALID GST_VAAPI_ID((gssize)(gint32)-1)
+
+/**
+ * GST_VAAPI_ID_FORMAT:
+ *
+ * Can be used together with #GST_VAAPI_ID_ARGS to properly output an
+ * integer value in a printf()-style text message.
+ *
+ * ``` C
+ * printf("id: %" GST_VAAPI_ID_FORMAT "\n", GST_VAAPI_ID_ARGS(id));
+ * ```
+ */
+#define GST_VAAPI_ID_FORMAT "p"
+
+/**
+ * GST_VAAPI_ID_ARGS:
+ * @id: a #GstVaapiID
+ *
+ * Can be used together with #GST_VAAPI_ID_FORMAT to properly output
+ * an integer value in a printf()-style text message.
+ */
+#define GST_VAAPI_ID_ARGS(id) GSIZE_TO_POINTER(id)
+
+/**
+ * GstVaapiPoint:
+ * @x: X coordinate
+ * @y: Y coordinate
+ *
+ * A location within a surface.
+ */
+typedef struct _GstVaapiPoint GstVaapiPoint;
+struct _GstVaapiPoint {
+    guint32 x;
+    guint32 y;
+};
+
+/**
+ * GstVaapiRectangle:
+ * @x: X coordinate
+ * @y: Y coordinate
+ * @width: region width
+ * @height: region height
+ *
+ * A rectangle region within a surface.
+ */
+typedef struct _GstVaapiRectangle GstVaapiRectangle;
+struct _GstVaapiRectangle {
+    guint32 x;
+    guint32 y;
+    guint32 width;
+    guint32 height;
+};
+
+/**
+ * GstVaapiRenderMode:
+ * @GST_VAAPI_RENDER_MODE_OVERLAY: in this mode, the VA display
+ *   backend renders surfaces with an overlay engine. This means that
+ *   the surface that is currently displayed shall not be re-used
+ *   right away for decoding. i.e. it needs to be retained further,
+ *   until the next surface is to be displayed.
+ * @GST_VAAPI_RENDER_MODE_TEXTURE: in this modem the VA display
+ *   backend renders surfaces with a textured blit (GPU/3D engine).
+ *   This means that the surface is copied to some intermediate
+ *   backing store, or back buffer of a frame buffer, and is free to
+ *   be re-used right away for decoding.
+ */
+typedef enum {
+    GST_VAAPI_RENDER_MODE_OVERLAY = 1,
+    GST_VAAPI_RENDER_MODE_TEXTURE
+} GstVaapiRenderMode;
+
+/**
+ * GstVaapiRotation:
+ * @GST_VAAPI_ROTATION_0: the VA display is not rotated.
+ * @GST_VAAPI_ROTATION_90: the VA display is rotated by 90°, clockwise.
+ * @GST_VAAPI_ROTATION_180: the VA display is rotated by 180°, clockwise.
+ * @GST_VAAPI_ROTATION_270: the VA display is rotated by 270°, clockwise.
+ * @GST_VAAPI_ROTATION_AUTOMATIC: the VA display is rotated by image-orientating tag.
+ */
+typedef enum {
+    GST_VAAPI_ROTATION_0   = 0,
+    GST_VAAPI_ROTATION_90  = 90,
+    GST_VAAPI_ROTATION_180 = 180,
+    GST_VAAPI_ROTATION_270 = 270,
+    GST_VAAPI_ROTATION_AUTOMATIC = 360,
+} GstVaapiRotation;
+
+/**
+ * GstVaapiRateControl:
+ * @GST_VAAPI_RATECONTROL_NONE: No rate control performed by the
+ *   underlying driver
+ * @GST_VAAPI_RATECONTROL_CQP: Constant QP
+ * @GST_VAAPI_RATECONTROL_CBR: Constant bitrate
+ * @GST_VAAPI_RATECONTROL_VCM: Video conference mode
+ * @GST_VAAPI_RATECONTROL_VBR: Variable bitrate
+ * @GST_VAAPI_RATECONTROL_VBR_CONSTRAINED: Variable bitrate with peak
+ *   rate higher than average bitrate
+ * @GST_VAAPI_RATECONTROL_MB: Macroblock based rate control
+ * @GST_VAAPI_RATECONTROL_ICQ: Intelligent Constant QP, use
+ * quality_factor to improve subjective quality base on motion
+ * @GST_VAAPI_RATECONTROL_QVBR: Quality defined VBR, use
+ * quality_factor to get good enough quality and save bits
+ *
+ * The set of allowed rate control values for #GstVaapiRateControl.
+ * Note: this is only valid for encoders.
+ */
+typedef enum {
+    GST_VAAPI_RATECONTROL_NONE = 0,
+    GST_VAAPI_RATECONTROL_CQP,
+    GST_VAAPI_RATECONTROL_CBR,
+    GST_VAAPI_RATECONTROL_VCM,
+    GST_VAAPI_RATECONTROL_VBR,
+    GST_VAAPI_RATECONTROL_VBR_CONSTRAINED,
+    GST_VAAPI_RATECONTROL_MB,
+    GST_VAAPI_RATECONTROL_ICQ,
+    GST_VAAPI_RATECONTROL_QVBR,
+} GstVaapiRateControl;
+
+/* Define a mask for GstVaapiRateControl */
+#define GST_VAAPI_RATECONTROL_MASK(RC) \
+    (1U << G_PASTE(GST_VAAPI_RATECONTROL_,RC))
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_TYPES_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils.c
new file mode 100644 (file)
index 0000000..ebec319
--- /dev/null
@@ -0,0 +1,1030 @@
+/*
+ *  gstvaapiutils.c - VA-API utilities
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiutils.h"
+#include "gstvaapibufferproxy.h"
+#include "gstvaapifilter.h"
+#include "gstvaapisubpicture.h"
+#include "gstvaapisurface.h"
+#include <stdio.h>
+#include <stdarg.h>
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/* string case an enum */
+#define STRCASEP(p, x)  STRCASE(G_PASTE(p, x))
+#define STRCASE(x)      case x: return G_STRINGIFY(x)
+
+/* string case a macro */
+#define STRCASEM(p, x)  case G_PASTE(p, x): return G_STRINGIFY(x)
+
+#if VA_CHECK_VERSION (0,40,0)
+static gchar *
+strip_msg (const char *message)
+{
+  gchar *msg;
+
+  msg = g_strdup (message);
+  if (!msg)
+    return NULL;
+  return g_strstrip (msg);
+}
+
+#if VA_CHECK_VERSION (1,0,0)
+static void
+gst_vaapi_err (void *data, const char *message)
+{
+  gchar *msg;
+
+  msg = strip_msg (message);
+  if (!msg)
+    return;
+  GST_ERROR ("%s", msg);
+  g_free (msg);
+}
+
+static void
+gst_vaapi_warning (void *data, const char *message)
+{
+  gchar *msg;
+
+  msg = strip_msg (message);
+  if (!msg)
+    return;
+  GST_WARNING ("%s", msg);
+  g_free (msg);
+}
+#endif
+
+static void
+gst_vaapi_log (
+#if VA_CHECK_VERSION (1,0,0)
+    void *data,
+#endif
+    const char *message)
+{
+  gchar *msg;
+
+  msg = strip_msg (message);
+  if (!msg)
+    return;
+  GST_INFO ("%s", msg);
+  g_free (msg);
+}
+#endif
+
+gboolean
+vaapi_initialize (VADisplay dpy)
+{
+  gint major_version, minor_version;
+  VAStatus status;
+
+#if VA_CHECK_VERSION (1,0,0)
+  vaSetErrorCallback (dpy, gst_vaapi_warning, NULL);
+  vaSetInfoCallback (dpy, gst_vaapi_log, NULL);
+#elif VA_CHECK_VERSION (0,40,0)
+  vaSetInfoCallback (gst_vaapi_log);
+#endif
+
+  status = vaInitialize (dpy, &major_version, &minor_version);
+
+#if VA_CHECK_VERSION (1,0,0)
+  vaSetErrorCallback (dpy, gst_vaapi_err, NULL);
+#endif
+
+  if (!vaapi_check_status (status, "vaInitialize()"))
+    return FALSE;
+
+  GST_INFO ("VA-API version %d.%d", major_version, minor_version);
+  return TRUE;
+}
+
+/* Check VA status for success or print out an error */
+gboolean
+vaapi_check_status (VAStatus status, const gchar * msg)
+{
+  if (status != VA_STATUS_SUCCESS) {
+    GST_DEBUG ("%s: %s", msg, vaErrorStr (status));
+    return FALSE;
+  }
+  return TRUE;
+}
+
+/* Maps VA buffer */
+gpointer
+vaapi_map_buffer (VADisplay dpy, VABufferID buf_id)
+{
+  VAStatus status;
+  gpointer data = NULL;
+
+  status = vaMapBuffer (dpy, buf_id, &data);
+  if (!vaapi_check_status (status, "vaMapBuffer()"))
+    return NULL;
+  return data;
+}
+
+/* Unmaps VA buffer */
+void
+vaapi_unmap_buffer (VADisplay dpy, VABufferID buf_id, gpointer * pbuf)
+{
+  VAStatus status;
+
+  if (pbuf)
+    *pbuf = NULL;
+
+  status = vaUnmapBuffer (dpy, buf_id);
+  if (!vaapi_check_status (status, "vaUnmapBuffer()"))
+    return;
+}
+
+/* Creates and maps VA buffer */
+gboolean
+vaapi_create_buffer (VADisplay dpy, VAContextID ctx, int type, guint size,
+    gconstpointer buf, VABufferID * buf_id_ptr, gpointer * mapped_data)
+{
+  return vaapi_create_n_elements_buffer (dpy, ctx, type, size, buf, buf_id_ptr,
+      mapped_data, 1);
+}
+
+gboolean
+vaapi_create_n_elements_buffer (VADisplay dpy, VAContextID ctx, int type,
+    guint size, gconstpointer buf, VABufferID * buf_id_ptr,
+    gpointer * mapped_data, int num_elements)
+{
+  VABufferID buf_id;
+  VAStatus status;
+  gpointer data = (gpointer) buf;
+
+  status = vaCreateBuffer (dpy, ctx, type, size, num_elements, data, &buf_id);
+  if (!vaapi_check_status (status, "vaCreateBuffer()"))
+    return FALSE;
+
+  if (mapped_data) {
+    data = vaapi_map_buffer (dpy, buf_id);
+    if (!data)
+      goto error;
+    *mapped_data = data;
+  }
+
+  *buf_id_ptr = buf_id;
+  return TRUE;
+
+  /* ERRORS */
+error:
+  {
+    vaapi_destroy_buffer (dpy, &buf_id);
+    return FALSE;
+  }
+}
+
+/* Destroy VA buffer */
+void
+vaapi_destroy_buffer (VADisplay dpy, VABufferID * buf_id_ptr)
+{
+  if (!buf_id_ptr || *buf_id_ptr == VA_INVALID_ID)
+    return;
+
+  vaDestroyBuffer (dpy, *buf_id_ptr);
+  *buf_id_ptr = VA_INVALID_ID;
+}
+
+/* Return a string representation of a VAProfile */
+const gchar *
+string_of_VAProfile (VAProfile profile)
+{
+  switch (profile) {
+#define MAP(profile) \
+        STRCASEP(VAProfile, profile)
+      MAP (MPEG2Simple);
+      MAP (MPEG2Main);
+      MAP (MPEG4Simple);
+      MAP (MPEG4AdvancedSimple);
+      MAP (MPEG4Main);
+      MAP (JPEGBaseline);
+      MAP (H263Baseline);
+      MAP (H264ConstrainedBaseline);
+#if !VA_CHECK_VERSION(1,0,0)
+      MAP (H264Baseline);
+#endif
+      MAP (H264Main);
+      MAP (H264High);
+      MAP (H264MultiviewHigh);
+      MAP (H264StereoHigh);
+#if VA_CHECK_VERSION(1,2,0)
+      MAP (HEVCMain422_10);
+      MAP (HEVCMain444);
+      MAP (HEVCMain444_10);
+      MAP (HEVCSccMain);
+      MAP (HEVCSccMain10);
+      MAP (HEVCSccMain444);
+#endif
+#if VA_CHECK_VERSION(1,8,0)
+      MAP (HEVCSccMain444_10);
+#endif
+      MAP (HEVCMain);
+      MAP (HEVCMain10);
+      MAP (VC1Simple);
+      MAP (VC1Main);
+      MAP (VC1Advanced);
+      MAP (VP8Version0_3);
+      MAP (VP9Profile0);
+      MAP (VP9Profile1);
+      MAP (VP9Profile2);
+      MAP (VP9Profile3);
+#if VA_CHECK_VERSION(1,8,0)
+      MAP (AV1Profile0);
+      MAP (AV1Profile1);
+#endif
+#undef MAP
+    default:
+      break;
+  }
+  return "<unknown>";
+}
+
+/* Return a string representation of a VAEntrypoint */
+const gchar *
+string_of_VAEntrypoint (VAEntrypoint entrypoint)
+{
+  switch (entrypoint) {
+#define MAP(entrypoint) \
+        STRCASEP(VAEntrypoint, entrypoint)
+      MAP (VLD);
+      MAP (IZZ);
+      MAP (IDCT);
+      MAP (MoComp);
+      MAP (Deblocking);
+      MAP (EncSlice);
+      MAP (EncPicture);
+#if VA_CHECK_VERSION(0,39,1)
+      MAP (EncSliceLP);
+#endif
+      MAP (VideoProc);
+#if VA_CHECK_VERSION(1,0,0)
+      MAP (FEI);
+#endif
+#undef MAP
+    default:
+      break;
+  }
+  return "<unknown>";
+}
+
+/* Return a string representation of a VADisplayAttributeType */
+const gchar *
+string_of_VADisplayAttributeType (VADisplayAttribType attribute_type)
+{
+  switch (attribute_type) {
+#define MAP(attribute_type) \
+        STRCASEP(VADisplayAttrib, attribute_type)
+      MAP (Brightness);
+      MAP (Contrast);
+      MAP (Hue);
+      MAP (Saturation);
+      MAP (BackgroundColor);
+      MAP (Rotation);
+      MAP (OutofLoopDeblock);
+      MAP (CSCMatrix);
+      MAP (BlendColor);
+      MAP (OverlayAutoPaintColorKey);
+      MAP (OverlayColorKey);
+      MAP (RenderMode);
+      MAP (RenderDevice);
+      MAP (RenderRect);
+#undef MAP
+    default:
+      break;
+  }
+  return "<unknown>";
+}
+
+/* Return a string representation of a VA chroma format */
+const gchar *
+string_of_va_chroma_format (guint chroma_format)
+{
+  switch (chroma_format) {
+#define MAP(value) \
+        STRCASEM(VA_RT_FORMAT_, value)
+      MAP (YUV420);
+      MAP (YUV422);
+      MAP (YUV444);
+      MAP (YUV400);
+      MAP (RGB16);
+      MAP (RGB32);
+      MAP (RGBP);
+      MAP (YUV420_10BPP);
+#if VA_CHECK_VERSION(1,2,0)
+      MAP (YUV422_10);
+      MAP (YUV444_10);
+      MAP (YUV420_12);
+      MAP (YUV422_12);
+      MAP (YUV444_12);
+      MAP (RGB32_10);
+#endif
+#undef MAP
+    default:
+      break;
+  }
+  return "<unknown>";
+}
+
+const gchar *
+string_of_VARateControl (guint rate_control)
+{
+  switch (rate_control) {
+    case VA_RC_NONE:
+      return "None";
+    case VA_RC_CQP:
+      return "CQP";
+    case VA_RC_CBR:
+      return "CBR";
+    case VA_RC_VCM:
+      return "VCM";
+    case VA_RC_VBR:
+      return "VBR";
+    case VA_RC_VBR_CONSTRAINED:
+      return "VBR-Constrained";
+#if VA_CHECK_VERSION(0,39,1)
+    case VA_RC_MB:
+      return "MB";
+#endif
+#if VA_CHECK_VERSION(1,1,0)
+    case VA_RC_ICQ:
+      return "VA_RC_ICQ";
+#endif
+#if VA_CHECK_VERSION(1,3,0)
+    case VA_RC_QVBR:
+      return "VA_RC_QVBR";
+#endif
+    default:
+      break;
+  }
+  return "<unknown>";
+}
+
+/**
+ * to_GstVaapiChromaType:
+ * @va_rt_format: the value of VAConfigAttribRTFormat
+ *
+ * Converts the VA_RT_FORMAT_* to #GstVaapiChromaType
+ *
+ * Returns: the #GstVaapiChromaType associated to @va_rt_format or
+ * zero.
+ **/
+guint
+to_GstVaapiChromaType (guint va_rt_format)
+{
+  if (va_rt_format & VA_RT_FORMAT_YUV420)
+    return GST_VAAPI_CHROMA_TYPE_YUV420;
+  if (va_rt_format & VA_RT_FORMAT_YUV422)
+    return GST_VAAPI_CHROMA_TYPE_YUV422;
+  if (va_rt_format & VA_RT_FORMAT_YUV444)
+    return GST_VAAPI_CHROMA_TYPE_YUV444;
+  if (va_rt_format & VA_RT_FORMAT_YUV411)
+    return GST_VAAPI_CHROMA_TYPE_YUV411;
+  if (va_rt_format & VA_RT_FORMAT_YUV400)
+    return GST_VAAPI_CHROMA_TYPE_YUV400;
+  if (va_rt_format & VA_RT_FORMAT_RGB32)
+    return GST_VAAPI_CHROMA_TYPE_RGB32;
+  if (va_rt_format & VA_RT_FORMAT_RGB16)
+    return GST_VAAPI_CHROMA_TYPE_RGB16;
+  if (va_rt_format & VA_RT_FORMAT_RGBP)
+    return GST_VAAPI_CHROMA_TYPE_RGBP;
+  if (va_rt_format & VA_RT_FORMAT_YUV420_10BPP)
+    return GST_VAAPI_CHROMA_TYPE_YUV420_10BPP;
+#if VA_CHECK_VERSION(1,2,0)
+  if (va_rt_format & VA_RT_FORMAT_YUV422_10)
+    return GST_VAAPI_CHROMA_TYPE_YUV422_10BPP;
+  if (va_rt_format & VA_RT_FORMAT_YUV444_10)
+    return GST_VAAPI_CHROMA_TYPE_YUV444_10BPP;
+  if (va_rt_format & VA_RT_FORMAT_YUV420_12)
+    return GST_VAAPI_CHROMA_TYPE_YUV420_12BPP;
+  if (va_rt_format & VA_RT_FORMAT_YUV422_12)
+    return GST_VAAPI_CHROMA_TYPE_YUV422_12BPP;
+  if (va_rt_format & VA_RT_FORMAT_YUV444_12)
+    return GST_VAAPI_CHROMA_TYPE_YUV444_12BPP;
+  if (va_rt_format & VA_RT_FORMAT_RGB32_10)
+    return GST_VAAPI_CHROMA_TYPE_RGB32_10BPP;
+#endif
+  return 0;
+}
+
+/**
+ * from_GstVaapiChromaType:
+ * @chroma_type: the #GstVaapiChromaType
+ *
+ * Converts #GstVaapiChromaType to a chroma format suitable for
+ * vaCreateSurfaces().
+ */
+guint
+from_GstVaapiChromaType (guint chroma_type)
+{
+  guint format;
+
+  switch (chroma_type) {
+    case GST_VAAPI_CHROMA_TYPE_YUV420:
+      format = VA_RT_FORMAT_YUV420;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV422:
+      format = VA_RT_FORMAT_YUV422;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV444:
+      format = VA_RT_FORMAT_YUV444;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV411:
+      format = VA_RT_FORMAT_YUV411;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV400:
+      format = VA_RT_FORMAT_YUV400;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_RGB32:
+      format = VA_RT_FORMAT_RGB32;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_RGB16:
+      format = VA_RT_FORMAT_RGB16;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_RGBP:
+      format = VA_RT_FORMAT_RGBP;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV420_10BPP:
+      format = VA_RT_FORMAT_YUV420_10BPP;
+      break;
+#if VA_CHECK_VERSION(1,2,0)
+    case GST_VAAPI_CHROMA_TYPE_YUV422_10BPP:
+      format = VA_RT_FORMAT_YUV422_10;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV444_10BPP:
+      format = VA_RT_FORMAT_YUV444_10;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV420_12BPP:
+      format = VA_RT_FORMAT_YUV420_12;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV422_12BPP:
+      format = VA_RT_FORMAT_YUV422_12;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV444_12BPP:
+      format = VA_RT_FORMAT_YUV444_12;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_RGB32_10BPP:
+      format = VA_RT_FORMAT_RGB32_10;
+      break;
+#endif
+    default:
+      format = 0;
+      break;
+  }
+  return format;
+}
+
+/**
+ * from_GstVaapiSubpictureFlags:
+ * @flags: the #GstVaapiSubpictureFlags
+ *
+ * Converts #GstVaapiSubpictureFlags to flags suitable for
+ * vaAssociateSubpicture().
+ */
+guint
+from_GstVaapiSubpictureFlags (guint flags)
+{
+  guint va_flags = 0;
+
+  if (flags & GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA)
+    va_flags |= VA_SUBPICTURE_GLOBAL_ALPHA;
+#ifdef VA_SUBPICTURE_PREMULTIPLIED_ALPHA
+  if (flags & GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA)
+    flags |= VA_SUBPICTURE_PREMULTIPLIED_ALPHA;
+#endif
+  return va_flags;
+}
+
+/**
+ * to_GstVaapiSubpictureFlags:
+ * @flags: the #GstVaapiSubpictureFlags flags to translate
+ *
+ * Converts vaQuerySubpictureFormats() @flags to #GstVaapiSubpictureFlags
+ * flags.
+ *
+ * Return value: the #GstVaapiSubpictureFlags flags
+ */
+guint
+to_GstVaapiSubpictureFlags (guint va_flags)
+{
+  guint flags = 0;
+
+  if (va_flags & VA_SUBPICTURE_GLOBAL_ALPHA)
+    flags |= GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA;
+#ifdef VA_SUBPICTURE_PREMULTIPLIED_ALPHA
+  if (va_flags & VA_SUBPICTURE_PREMULTIPLIED_ALPHA)
+    flags |= GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA;
+#endif
+  return flags;
+}
+
+/**
+ * from_GstVideoOverlayFormatFlags:
+ * @flags: the #GstVideoOverlayFormatFlags flags to translate
+ *
+ * Converts #GstVaapiSubpictureFlags to #GstVaapiSubpictureFlags.
+ *
+ * Return value: the #GstVaapiSubpictureFlags flags
+ */
+guint
+from_GstVideoOverlayFormatFlags (guint ovl_flags)
+{
+  guint flags = 0;
+
+  if (ovl_flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA)
+    flags |= GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA;
+  if (ovl_flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)
+    flags |= GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA;
+  return flags;
+}
+
+/**
+ * to_GstVideoOverlayFormatFlags:
+ * @flags: the #GstVaapiSubpictureFlags flags to translate
+ *
+ * Converts #GstVaapiSubpictureFlags to #GstVideoOverlayFormatFlags.
+ *
+ * Return value: the #GstVideoOverlayFormatFlags flags
+ */
+guint
+to_GstVideoOverlayFormatFlags (guint flags)
+{
+  guint ovl_flags = 0;
+
+  if (flags & GST_VAAPI_SUBPICTURE_FLAG_PREMULTIPLIED_ALPHA)
+    ovl_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_PREMULTIPLIED_ALPHA;
+  if (flags & GST_VAAPI_SUBPICTURE_FLAG_GLOBAL_ALPHA)
+    ovl_flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA;
+  return ovl_flags;
+}
+
+/**
+ * from_GstVaapiSurfaceRenderFlags:
+ * @flags: the #GstVaapiSurfaceRenderFlags
+ *
+ * Converts #GstVaapiSurfaceRenderFlags to flags suitable for
+ * vaPutSurface().
+ */
+guint
+from_GstVaapiSurfaceRenderFlags (guint flags)
+{
+  guint va_fields, va_csc;
+
+  /* Picture structure */
+  switch (flags & GST_VAAPI_PICTURE_STRUCTURE_MASK) {
+    case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
+      va_fields = VA_TOP_FIELD;
+      break;
+    case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
+      va_fields = VA_BOTTOM_FIELD;
+      break;
+    default:
+      va_fields = VA_FRAME_PICTURE;
+      break;
+  }
+
+  /* Color standard */
+  switch (flags & GST_VAAPI_COLOR_STANDARD_MASK) {
+#ifdef VA_SRC_BT601
+    case GST_VAAPI_COLOR_STANDARD_ITUR_BT_601:
+      va_csc = VA_SRC_BT601;
+      break;
+#endif
+#ifdef VA_SRC_BT709
+    case GST_VAAPI_COLOR_STANDARD_ITUR_BT_709:
+      va_csc = VA_SRC_BT709;
+      break;
+#endif
+#ifdef VA_SRC_SMPTE_240
+    case GST_VAAPI_COLOR_STANDARD_SMPTE_240M:
+      va_csc = VA_SRC_SMPTE_240;
+      break;
+#endif
+    default:
+      va_csc = 0;
+      break;
+  }
+  return va_fields | va_csc;
+}
+
+/**
+ * to_GstVaapiSurfaceStatus:
+ * @flags: the #GstVaapiSurfaceStatus flags to translate
+ *
+ * Converts vaQuerySurfaceStatus() @flags to #GstVaapiSurfaceStatus
+ * flags.
+ *
+ * Return value: the #GstVaapiSurfaceStatus flags
+ */
+guint
+to_GstVaapiSurfaceStatus (guint va_flags)
+{
+  guint flags;
+  const guint va_flags_mask = (VASurfaceReady |
+      VASurfaceRendering | VASurfaceDisplaying);
+
+  /* Check for core status */
+  switch (va_flags & va_flags_mask) {
+    case VASurfaceReady:
+      flags = GST_VAAPI_SURFACE_STATUS_IDLE;
+      break;
+    case VASurfaceRendering:
+      flags = GST_VAAPI_SURFACE_STATUS_RENDERING;
+      break;
+    case VASurfaceDisplaying:
+      flags = GST_VAAPI_SURFACE_STATUS_DISPLAYING;
+      break;
+    default:
+      flags = 0;
+      break;
+  }
+
+  /* Check for encoder status */
+  if (va_flags & VASurfaceSkipped)
+    flags |= GST_VAAPI_SURFACE_STATUS_SKIPPED;
+  return flags;
+}
+
+/* Translate GstVaapiRotation value to VA-API rotation value */
+guint
+from_GstVaapiRotation (guint value)
+{
+  switch (value) {
+    case GST_VAAPI_ROTATION_0:
+      return VA_ROTATION_NONE;
+    case GST_VAAPI_ROTATION_90:
+      return VA_ROTATION_90;
+    case GST_VAAPI_ROTATION_180:
+      return VA_ROTATION_180;
+    case GST_VAAPI_ROTATION_270:
+      return VA_ROTATION_270;
+  }
+  GST_ERROR ("unsupported GstVaapiRotation value %d", value);
+  return VA_ROTATION_NONE;
+}
+
+/* Translate VA-API rotation value to GstVaapiRotation value */
+guint
+to_GstVaapiRotation (guint value)
+{
+  switch (value) {
+    case VA_ROTATION_NONE:
+      return GST_VAAPI_ROTATION_0;
+    case VA_ROTATION_90:
+      return GST_VAAPI_ROTATION_90;
+    case VA_ROTATION_180:
+      return GST_VAAPI_ROTATION_180;
+    case VA_ROTATION_270:
+      return GST_VAAPI_ROTATION_270;
+  }
+  GST_ERROR ("unsupported VA-API rotation value %d", value);
+  return GST_VAAPI_ROTATION_0;
+}
+
+guint
+from_GstVaapiRateControl (guint value)
+{
+  switch (value) {
+    case GST_VAAPI_RATECONTROL_NONE:
+      return VA_RC_NONE;
+    case GST_VAAPI_RATECONTROL_CQP:
+      return VA_RC_CQP;
+    case GST_VAAPI_RATECONTROL_CBR:
+      return VA_RC_CBR;
+    case GST_VAAPI_RATECONTROL_VCM:
+      return VA_RC_VCM;
+    case GST_VAAPI_RATECONTROL_VBR:
+      return VA_RC_VBR;
+    case GST_VAAPI_RATECONTROL_VBR_CONSTRAINED:
+      return VA_RC_VBR_CONSTRAINED;
+#if VA_CHECK_VERSION(0,39,1)
+    case GST_VAAPI_RATECONTROL_MB:
+      return VA_RC_MB;
+#endif
+#if VA_CHECK_VERSION(1,1,0)
+    case GST_VAAPI_RATECONTROL_ICQ:
+      return VA_RC_ICQ;
+#endif
+#if VA_CHECK_VERSION(1,3,0)
+    case GST_VAAPI_RATECONTROL_QVBR:
+      return VA_RC_QVBR;
+#endif
+  }
+  GST_ERROR ("unsupported GstVaapiRateControl value %u", value);
+  return VA_RC_NONE;
+}
+
+guint
+to_GstVaapiRateControl (guint value)
+{
+  switch (value) {
+    case VA_RC_NONE:
+      return GST_VAAPI_RATECONTROL_NONE;
+    case VA_RC_CQP:
+      return GST_VAAPI_RATECONTROL_CQP;
+    case VA_RC_CBR:
+      return GST_VAAPI_RATECONTROL_CBR;
+    case VA_RC_VCM:
+      return GST_VAAPI_RATECONTROL_VCM;
+    case VA_RC_VBR:
+      return GST_VAAPI_RATECONTROL_VBR;
+    case VA_RC_VBR_CONSTRAINED:
+      return GST_VAAPI_RATECONTROL_VBR_CONSTRAINED;
+#if VA_CHECK_VERSION(0,39,1)
+    case VA_RC_MB:
+      return GST_VAAPI_RATECONTROL_MB;
+#endif
+#if VA_CHECK_VERSION(1,1,0)
+    case VA_RC_ICQ:
+      return GST_VAAPI_RATECONTROL_ICQ;
+#endif
+#if VA_CHECK_VERSION(1,3,0)
+    case VA_RC_QVBR:
+      return GST_VAAPI_RATECONTROL_QVBR;
+#endif
+
+  }
+  GST_ERROR ("unsupported VA-API Rate Control value %u", value);
+  return GST_VAAPI_RATECONTROL_NONE;
+}
+
+/* VPP: translate GstVaapiDeinterlaceMethod to VA deinterlacing algorithm */
+guint
+from_GstVaapiDeinterlaceMethod (guint value)
+{
+  switch (value) {
+    case GST_VAAPI_DEINTERLACE_METHOD_NONE:
+      return 0;
+    case GST_VAAPI_DEINTERLACE_METHOD_BOB:
+      return VAProcDeinterlacingBob;
+    case GST_VAAPI_DEINTERLACE_METHOD_WEAVE:
+      return VAProcDeinterlacingWeave;
+    case GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE:
+      return VAProcDeinterlacingMotionAdaptive;
+    case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
+      return VAProcDeinterlacingMotionCompensated;
+  }
+  GST_ERROR ("unsupported GstVaapiDeinterlaceMethod value %d", value);
+  return 0;
+}
+
+/* VPP: translate GstVaapiDeinterlaceFlags into VA deinterlacing flags */
+guint
+from_GstVaapiDeinterlaceFlags (guint flags)
+{
+  guint va_flags = 0;
+
+  if (!(flags & GST_VAAPI_DEINTERLACE_FLAG_TFF))
+    va_flags |= VA_DEINTERLACING_BOTTOM_FIELD_FIRST;
+
+  if (flags & GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD)
+    va_flags |= VA_DEINTERLACING_ONE_FIELD;
+
+  if (!(flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD))
+    va_flags |= VA_DEINTERLACING_BOTTOM_FIELD;
+  return va_flags;
+}
+
+/* VPP: translate GstVaapiScaleMethod into VA scaling flags */
+guint
+from_GstVaapiScaleMethod (guint value)
+{
+  guint va_flags;
+
+  switch (value) {
+    case GST_VAAPI_SCALE_METHOD_DEFAULT:
+      va_flags = VA_FILTER_SCALING_DEFAULT;
+      break;
+    case GST_VAAPI_SCALE_METHOD_FAST:
+      va_flags = VA_FILTER_SCALING_FAST;
+      break;
+    case GST_VAAPI_SCALE_METHOD_HQ:
+      va_flags = VA_FILTER_SCALING_HQ;
+      break;
+    default:
+      va_flags = 0;
+      break;
+  }
+  return va_flags;
+}
+
+/* VPP: translate VA scaling flags into GstVaapiScale Method */
+guint
+to_GstVaapiScaleMethod (guint flags)
+{
+  GstVaapiScaleMethod method;
+
+  switch (flags) {
+    case VA_FILTER_SCALING_FAST:
+      method = GST_VAAPI_SCALE_METHOD_FAST;
+      break;
+    case VA_FILTER_SCALING_HQ:
+      method = GST_VAAPI_SCALE_METHOD_HQ;
+      break;
+    default:
+      method = GST_VAAPI_SCALE_METHOD_DEFAULT;
+      break;
+  }
+  return method;
+}
+
+/* VPP: translate GstVideoOrientationMethod into VA mirror/rotation flags */
+void
+from_GstVideoOrientationMethod (guint value, guint * va_mirror,
+    guint * va_rotation)
+{
+  *va_mirror = 0;
+  *va_rotation = 0;
+
+  switch (value) {
+#if VA_CHECK_VERSION(1,1,0)
+    case GST_VIDEO_ORIENTATION_IDENTITY:
+      *va_mirror = VA_MIRROR_NONE;
+      *va_rotation = VA_ROTATION_NONE;
+      break;
+    case GST_VIDEO_ORIENTATION_HORIZ:
+      *va_mirror = VA_MIRROR_HORIZONTAL;
+      *va_rotation = VA_ROTATION_NONE;
+      break;
+    case GST_VIDEO_ORIENTATION_VERT:
+      *va_mirror = VA_MIRROR_VERTICAL;
+      *va_rotation = VA_ROTATION_NONE;
+      break;
+    case GST_VIDEO_ORIENTATION_90R:
+      *va_mirror = VA_MIRROR_NONE;
+      *va_rotation = VA_ROTATION_90;
+      break;
+    case GST_VIDEO_ORIENTATION_180:
+      *va_mirror = VA_MIRROR_NONE;
+      *va_rotation = VA_ROTATION_180;
+      break;
+    case GST_VIDEO_ORIENTATION_90L:
+      *va_mirror = VA_MIRROR_NONE;
+      *va_rotation = VA_ROTATION_270;
+      break;
+    case GST_VIDEO_ORIENTATION_UL_LR:
+      *va_mirror = VA_MIRROR_HORIZONTAL;
+      *va_rotation = VA_ROTATION_90;
+      break;
+    case GST_VIDEO_ORIENTATION_UR_LL:
+      *va_mirror = VA_MIRROR_VERTICAL;
+      *va_rotation = VA_ROTATION_90;
+      break;
+#endif
+    default:
+      break;
+  }
+}
+
+/**
+ * from_GstVaapiBufferMemoryType:
+ * @type: a #GstVaapiBufferMemoryType
+ *
+ * Returns: the VA's memory type symbol
+ **/
+guint
+from_GstVaapiBufferMemoryType (guint type)
+{
+  guint va_type;
+
+  switch (type) {
+#if VA_CHECK_VERSION(1,1,0)
+    case GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2:
+      va_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2;
+      break;
+#endif
+    case GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF:
+      va_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
+      break;
+    case GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF:
+      va_type = VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM;
+      break;
+    case GST_VAAPI_BUFFER_MEMORY_TYPE_V4L2:
+      va_type = VA_SURFACE_ATTRIB_MEM_TYPE_V4L2;
+      break;
+    case GST_VAAPI_BUFFER_MEMORY_TYPE_USER_PTR:
+      va_type = VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR;
+      break;
+    default:
+      va_type = 0;
+      break;
+  }
+  return va_type;
+}
+
+/**
+ * to_GstVaapiBufferMemoryType:
+ * @va_type: a VA's memory type symbol
+ *
+ * It will return the first "supported" memory type from @va_type bit
+ * flag.
+ *
+ * Returns: a #GstVaapiBufferMemoryType or 0 if unknown.
+ **/
+guint
+to_GstVaapiBufferMemoryType (guint va_type)
+{
+#if VA_CHECK_VERSION(1,1,0)
+  if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2))
+    return GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2;
+#endif
+  if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME))
+    return GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF;
+  if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_KERNEL_DRM))
+    return GST_VAAPI_BUFFER_MEMORY_TYPE_GEM_BUF;
+  if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_V4L2))
+    return GST_VAAPI_BUFFER_MEMORY_TYPE_V4L2;
+  if ((va_type & VA_SURFACE_ATTRIB_MEM_TYPE_USER_PTR))
+    return GST_VAAPI_BUFFER_MEMORY_TYPE_USER_PTR;
+  return 0;
+}
+
+/**
+ * from_GstVideoColorimetry:
+ * @colorimetry: a #GstVideoColorimetry type
+ *
+ * VPP: maps the #GstVideoColorimetry type to the VAProcColorStandardType.  If
+ * @colorimetry is NULL or colorimetry->primaries are unknown, then returns
+ * VAProcColorStandardNone.  If there is no 1:1 correlation, then returns
+ * VAProcColorStandardExplicit.  Otherwise, the correlating
+ * VAProcColorStandardType is returned.
+ *
+ * Returns: a VAProcColorStandardType.
+ **/
+guint
+from_GstVideoColorimetry (const GstVideoColorimetry * const colorimetry)
+{
+#if VA_CHECK_VERSION(1,2,0)
+  if (!colorimetry
+      || colorimetry->primaries == GST_VIDEO_COLOR_PRIMARIES_UNKNOWN)
+    return VAProcColorStandardNone;
+  if (gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_BT709))
+    return VAProcColorStandardBT709;
+  /* NOTE: VAProcColorStandardBT2020 in VAAPI is the same as
+   * GST_VIDEO_COLORIMETRY_BT2020_10 in gstreamer. */
+  if (gst_video_colorimetry_matches (colorimetry,
+          GST_VIDEO_COLORIMETRY_BT2020_10) ||
+      gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_BT2020))
+    return VAProcColorStandardBT2020;
+  if (gst_video_colorimetry_matches (colorimetry, GST_VIDEO_COLORIMETRY_BT601))
+    return VAProcColorStandardBT601;
+  if (gst_video_colorimetry_matches (colorimetry,
+          GST_VIDEO_COLORIMETRY_SMPTE240M))
+    return VAProcColorStandardSMPTE240M;
+
+  return VAProcColorStandardExplicit;
+#else
+  return VAProcColorStandardNone;
+#endif
+}
+
+/**
+ * from_GstVideoColorRange:
+ * @value: a #GstVideoColorRange
+ *
+ * VPP: maps the #GstVideoColorRange to the VA value.
+ *
+ * Returns: the VA color range.
+ **/
+guint
+from_GstVideoColorRange (const GstVideoColorRange value)
+{
+#if VA_CHECK_VERSION(1,2,0)
+  switch (value) {
+    case GST_VIDEO_COLOR_RANGE_0_255:
+      return VA_SOURCE_RANGE_FULL;
+    case GST_VIDEO_COLOR_RANGE_16_235:
+      return VA_SOURCE_RANGE_REDUCED;
+    default:
+      return VA_SOURCE_RANGE_UNKNOWN;
+  }
+#else
+  return 0;
+#endif
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils.h
new file mode 100644 (file)
index 0000000..3159132
--- /dev/null
@@ -0,0 +1,178 @@
+/*
+ *  gstvaapiutils.h - VA-API utilities
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_H
+#define GST_VAAPI_UTILS_H
+
+#include <glib.h>
+#include <gst/video/video.h>
+#include <va/va.h>
+
+/** calls vaInitialize() redirecting the logging mechanism */
+G_GNUC_INTERNAL
+gboolean
+vaapi_initialize (VADisplay dpy);
+
+/** Check VA status for success or print out an error */
+G_GNUC_INTERNAL
+gboolean
+vaapi_check_status (VAStatus status, const gchar *msg);
+
+/** Maps VA buffer */
+G_GNUC_INTERNAL
+gpointer
+vaapi_map_buffer (VADisplay dpy, VABufferID buf_id);
+
+/** Unmaps VA buffer */
+G_GNUC_INTERNAL
+void
+vaapi_unmap_buffer (VADisplay dpy, VABufferID buf_id, void **pbuf);
+
+/** Creates and maps VA buffer */
+G_GNUC_INTERNAL
+gboolean
+vaapi_create_buffer (VADisplay dpy, VAContextID ctx, int type, guint size,
+    gconstpointer data, VABufferID * buf_id, gpointer * mapped_data);
+
+G_GNUC_INTERNAL
+gboolean
+vaapi_create_n_elements_buffer (VADisplay dpy, VAContextID ctx, int type,
+    guint size, gconstpointer data, VABufferID * buf_id, gpointer * mapped_data,
+    int num_elements);
+
+/** Destroy VA buffer */
+G_GNUC_INTERNAL
+void
+vaapi_destroy_buffer (VADisplay dpy, VABufferID * buf_id);
+
+/** Return a string representation of a VAProfile */
+G_GNUC_INTERNAL
+const gchar *
+string_of_VAProfile (VAProfile profile);
+
+/** Return a string representation of a VAEntrypoint */
+G_GNUC_INTERNAL
+const gchar *
+string_of_VAEntrypoint (VAEntrypoint entrypoint);
+
+/* Return a string representation of a VADisplayAttributeType */
+G_GNUC_INTERNAL
+const gchar *
+string_of_VADisplayAttributeType (VADisplayAttribType attribute_type);
+
+/* Return a string representation of a VA chroma format */
+G_GNUC_INTERNAL
+const gchar *
+string_of_va_chroma_format (guint chroma_format);
+
+G_GNUC_INTERNAL
+const gchar *
+string_of_VARateControl (guint rate_control);
+
+G_GNUC_INTERNAL
+guint
+to_GstVaapiChromaType (guint va_rt_format);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiChromaType (guint chroma_type);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiSubpictureFlags (guint flags);
+
+G_GNUC_INTERNAL
+guint
+to_GstVaapiSubpictureFlags (guint va_flags);
+
+G_GNUC_INTERNAL
+guint
+from_GstVideoOverlayFormatFlags (guint ovl_flags);
+
+G_GNUC_INTERNAL
+guint
+to_GstVideoOverlayFormatFlags (guint flags);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiSurfaceRenderFlags (guint flags);
+
+G_GNUC_INTERNAL
+guint
+to_GstVaapiSurfaceStatus (guint va_flags);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiRotation (guint value);
+
+G_GNUC_INTERNAL
+guint
+to_GstVaapiRotation (guint value);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiRateControl (guint value);
+
+G_GNUC_INTERNAL
+guint
+to_GstVaapiRateControl (guint value);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiDeinterlaceMethod (guint value);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiDeinterlaceFlags (guint flags);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiScaleMethod (guint value);
+
+G_GNUC_INTERNAL
+guint
+to_GstVaapiScaleMethod (guint flags);
+
+G_GNUC_INTERNAL
+void
+from_GstVideoOrientationMethod (guint value, guint * va_mirror,
+    guint * va_rotation);
+
+G_GNUC_INTERNAL
+guint
+from_GstVaapiBufferMemoryType (guint type);
+
+G_GNUC_INTERNAL
+guint
+to_GstVaapiBufferMemoryType (guint va_type);
+
+G_GNUC_INTERNAL
+guint
+from_GstVideoColorimetry (const GstVideoColorimetry *const colorimetry);
+
+G_GNUC_INTERNAL
+guint
+from_GstVideoColorRange (const GstVideoColorRange value);
+
+#endif /* GST_VAAPI_UTILS_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_core.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_core.c
new file mode 100644 (file)
index 0000000..7c98208
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *  gstvaapiutils_core.c - VA-API utilities (Core, MT-safe)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapiimage.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiutils_core.h"
+#include "gstvaapidisplay_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/**
+ * gst_vaapi_get_config_attribute:
+ * @display: a #GstVaapiDisplay
+ * @profile: a VA profile
+ * @entrypoint: a VA entrypoint
+ * @type: a VA config attribute type
+ * @out_value_ptr: return location for the config attribute value
+ *
+ * Determines the value for the VA config attribute @type and the
+ * given @profile/@entrypoint pair. If @out_value_ptr is %NULL, then
+ * this functions acts as a way to query whether the underlying VA
+ * driver supports the specified attribute @type, no matter the
+ * returned value.
+ *
+ * Note: this function only returns success if the VA driver does
+ * actually know about this config attribute type and that it returned
+ * a valid value for it.
+ *
+ * Return value: %TRUE if the VA driver knows about the requested
+ *   config attribute and returned a valid value, %FALSE otherwise
+ */
+gboolean
+gst_vaapi_get_config_attribute (GstVaapiDisplay * display, VAProfile profile,
+    VAEntrypoint entrypoint, VAConfigAttribType type, guint * out_value_ptr)
+{
+  VAConfigAttrib attrib;
+  VAStatus status;
+
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  attrib.type = type;
+  status = vaGetConfigAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      profile, entrypoint, &attrib, 1);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (status, "vaGetConfigAttributes()"))
+    return FALSE;
+  if (attrib.value == VA_ATTRIB_NOT_SUPPORTED)
+    return FALSE;
+
+  if (out_value_ptr)
+    *out_value_ptr = attrib.value;
+  return TRUE;
+}
+
+static VASurfaceAttrib *
+get_surface_attributes (GstVaapiDisplay * display, VAConfigID config,
+    guint * num_attribs)
+{
+  VASurfaceAttrib *surface_attribs = NULL;
+  guint num_surface_attribs = 0;
+  VAStatus va_status;
+
+  if (config == VA_INVALID_ID)
+    goto error;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  va_status = vaQuerySurfaceAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      config, NULL, &num_surface_attribs);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (va_status, "vaQuerySurfaceAttributes()"))
+    goto error;
+
+  surface_attribs = g_malloc (num_surface_attribs * sizeof (*surface_attribs));
+  if (!surface_attribs)
+    goto error;
+
+  GST_VAAPI_DISPLAY_LOCK (display);
+  va_status = vaQuerySurfaceAttributes (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      config, surface_attribs, &num_surface_attribs);
+  GST_VAAPI_DISPLAY_UNLOCK (display);
+  if (!vaapi_check_status (va_status, "vaQuerySurfaceAttributes()"))
+    goto error;
+
+  if (num_attribs)
+    *num_attribs = num_surface_attribs;
+  return surface_attribs;
+
+  /* ERRORS */
+error:
+  {
+    if (num_attribs)
+      *num_attribs = -1;
+    if (surface_attribs)
+      g_free (surface_attribs);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_config_surface_attribures_get:
+ * @display: a #GstVaapiDisplay
+ * @config: a #VAConfigID
+ *
+ * Retrieves the possible surface attributes for the supplied config.
+ *
+ * Returns: (transfer full): returns a #GstVaapiConfigSurfaceAttributes
+ **/
+GstVaapiConfigSurfaceAttributes *
+gst_vaapi_config_surface_attributes_get (GstVaapiDisplay * display,
+    VAConfigID config)
+{
+  VASurfaceAttrib *surface_attribs;
+  guint i, num_pixel_formats = 0, num_surface_attribs = 0;
+  GstVaapiConfigSurfaceAttributes *attribs = NULL;
+
+  surface_attribs =
+      get_surface_attributes (display, config, &num_surface_attribs);
+  if (!surface_attribs)
+    return NULL;
+
+  attribs = g_slice_new0 (GstVaapiConfigSurfaceAttributes);
+  if (!attribs)
+    goto error;
+
+  for (i = 0; i < num_surface_attribs; i++) {
+    const VASurfaceAttrib *const attrib = &surface_attribs[i];
+
+    switch (attrib->type) {
+      case VASurfaceAttribPixelFormat:
+        if ((attrib->flags & VA_SURFACE_ATTRIB_SETTABLE)) {
+          GstVideoFormat fmt;
+
+          fmt = gst_vaapi_video_format_from_va_fourcc (attrib->value.value.i);
+          if (fmt != GST_VIDEO_FORMAT_UNKNOWN)
+            num_pixel_formats++;
+        }
+        break;
+      case VASurfaceAttribMinWidth:
+        attribs->min_width = attrib->value.value.i;
+        break;
+      case VASurfaceAttribMinHeight:
+        attribs->min_height = attrib->value.value.i;
+        break;
+      case VASurfaceAttribMaxWidth:
+        attribs->max_width = attrib->value.value.i;
+        break;
+      case VASurfaceAttribMaxHeight:
+        attribs->max_height = attrib->value.value.i;
+        break;
+      case VASurfaceAttribMemoryType:
+        attribs->mem_types = attrib->value.value.i;
+        break;
+      default:
+        break;
+    }
+  }
+
+  if (num_pixel_formats == 0) {
+    attribs->formats = NULL;
+  } else {
+    attribs->formats = g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat),
+        num_pixel_formats);
+
+    for (i = 0; i < num_surface_attribs; i++) {
+      const VASurfaceAttrib *const attrib = &surface_attribs[i];
+      GstVideoFormat fmt;
+
+      if (attrib->type != VASurfaceAttribPixelFormat)
+        continue;
+      if (!(attrib->flags & VA_SURFACE_ATTRIB_SETTABLE))
+        continue;
+
+      fmt = gst_vaapi_video_format_from_va_fourcc (attrib->value.value.i);
+      if (fmt == GST_VIDEO_FORMAT_UNKNOWN)
+        continue;
+      g_array_append_val (attribs->formats, fmt);
+    }
+  }
+
+  g_free (surface_attribs);
+  return attribs;
+
+  /* ERRORS */
+error:
+  {
+    g_free (surface_attribs);
+    gst_vaapi_config_surface_attributes_free (attribs);
+    return NULL;
+  }
+}
+
+void
+gst_vaapi_config_surface_attributes_free (GstVaapiConfigSurfaceAttributes *
+    attribs)
+{
+  if (!attribs)
+    return;
+
+  if (attribs->formats)
+    g_array_unref (attribs->formats);
+  g_slice_free (GstVaapiConfigSurfaceAttributes, attribs);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_core.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_core.h
new file mode 100644 (file)
index 0000000..d900567
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  gstvaapiutils_core.h - VA-API utilities (Core, MT-safe)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_CORE_H
+#define GST_VAAPI_UTILS_CORE_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiConfigSurfaceAttributes GstVaapiConfigSurfaceAttributes;
+
+
+/**
+ * GstVaapiConfigSurfaceAttributes:
+ * @min_width: Minimal width in pixels.
+ * @min_height: Minimal height in pixels.
+ * @max_width: Maximal width in pixels.
+ * @max_height: Maximal height in pixels.
+ * @mem_types: Surface memory type expressed in bit fields.
+ * @formats: Array of avialable GstVideoFormats of a surface in a VAConfig.
+ *
+ * Represents the possible surface attributes for the supplied config.
+ **/
+struct _GstVaapiConfigSurfaceAttributes
+{
+  gint min_width;
+  gint min_height;
+  gint max_width;
+  gint max_height;
+  guint mem_types;
+  GArray *formats;
+};
+
+/* Gets attribute value for the supplied profile/entrypoint pair (MT-safe) */
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_get_config_attribute (GstVaapiDisplay * display, VAProfile profile,
+    VAEntrypoint entrypoint, VAConfigAttribType type, guint * out_value_ptr);
+
+G_GNUC_INTERNAL
+GstVaapiConfigSurfaceAttributes *
+gst_vaapi_config_surface_attributes_get (GstVaapiDisplay * display, VAConfigID config);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_config_surface_attributes_free (GstVaapiConfigSurfaceAttributes * attribs);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UTILS_CORE_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_egl.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_egl.c
new file mode 100644 (file)
index 0000000..99ae37d
--- /dev/null
@@ -0,0 +1,1485 @@
+/*
+ * gstvaapiutils_egl.c - EGL utilities
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *   Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiutils_egl.h"
+#if USE_GST_GL_HELPERS
+# include <gst/gl/gl.h>
+# if GST_GL_HAVE_PLATFORM_EGL
+#  include <gst/gl/egl/gstgldisplay_egl.h>
+# endif
+#endif
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+typedef struct egl_message_s EglMessage;
+struct egl_message_s
+{
+  EglObject base;
+  EglContextRunFunc func;
+  gpointer args;
+};
+
+static void
+egl_message_finalize (EglMessage * msg)
+{
+}
+
+/* ------------------------------------------------------------------------- */
+// Utility functions
+
+typedef struct gl_version_info_s GlVersionInfo;
+struct gl_version_info_s
+{
+  guint gles_version;
+  guint gl_api_bit;
+  guint gl_api;
+  const gchar *gl_api_name;
+};
+
+static const GlVersionInfo gl_version_info[] = {
+  {0, EGL_OPENGL_BIT, EGL_OPENGL_API, "OpenGL"},
+  {1, EGL_OPENGL_ES_BIT, EGL_OPENGL_ES_API, "OpenGL_ES"},
+  {2, EGL_OPENGL_ES2_BIT, EGL_OPENGL_ES_API, "OpenGL_ES2"},
+  {3, EGL_OPENGL_ES3_BIT_KHR, EGL_OPENGL_ES_API, "OpenGL_ES3"},
+  {0,}
+};
+
+static const GlVersionInfo *
+gl_version_info_lookup (guint gles_version)
+{
+  const GlVersionInfo *vinfo;
+
+  for (vinfo = gl_version_info; vinfo->gl_api_bit != 0; vinfo++) {
+    if (vinfo->gles_version == gles_version)
+      return vinfo;
+  }
+  return NULL;
+}
+
+static const GlVersionInfo *
+gl_version_info_lookup_by_api (guint api)
+{
+  const GlVersionInfo *vinfo;
+
+  for (vinfo = gl_version_info; vinfo->gl_api_bit != 0; vinfo++) {
+    if (api & vinfo->gl_api_bit)
+      return vinfo;
+  }
+  return NULL;
+}
+
+static const GlVersionInfo *
+gl_version_info_lookup_by_api_name (const gchar * name)
+{
+  const GlVersionInfo *vinfo;
+
+  for (vinfo = gl_version_info; vinfo->gl_api_bit != 0; vinfo++) {
+    if (g_strcmp0 (vinfo->gl_api_name, name) == 0)
+      return vinfo;
+  }
+  return NULL;
+}
+
+static gboolean
+g_strv_match_string (gchar ** extensions_list, const gchar * name)
+{
+  if (extensions_list) {
+    for (; *extensions_list != NULL; extensions_list++) {
+      if (g_strcmp0 (*extensions_list, name) == 0)
+        return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+static gboolean
+egl_find_attrib_value (const EGLint * attribs, EGLint type, EGLint * value_ptr)
+{
+  while (attribs[0] != EGL_NONE) {
+    if (attribs[0] == type) {
+      if (value_ptr)
+        *value_ptr = attribs[1];
+      return TRUE;
+    }
+    attribs += 2;
+  }
+  return FALSE;
+}
+
+/* ------------------------------------------------------------------------- */
+// Basic objects
+
+#define EGL_OBJECT(object) ((EglObject *)(object))
+#define EGL_OBJECT_CLASS(klass) ((EglObjectClass *)(klass))
+
+#define EGL_OBJECT_DEFINE_CLASS_WITH_CODE(TN, t_n, code)        \
+static void                                                     \
+G_PASTE(t_n,_finalize) (TN * object);                           \
+                                                                \
+static inline const EglObjectClass *                            \
+G_PASTE(t_n,_class) (void)                                      \
+{                                                               \
+  static G_PASTE(TN,Class) g_class;                             \
+  static gsize g_class_init = FALSE;                            \
+                                                                \
+  if (g_once_init_enter (&g_class_init)) {                      \
+    GstVaapiMiniObjectClass *const object_class =               \
+        GST_VAAPI_MINI_OBJECT_CLASS (&g_class);                 \
+    code;                                                       \
+    object_class->size = sizeof (TN);                           \
+    object_class->finalize = (GDestroyNotify)                   \
+      G_PASTE(t_n,_finalize);                                   \
+    g_once_init_leave (&g_class_init, TRUE);                    \
+  }                                                             \
+  return EGL_OBJECT_CLASS (&g_class);                           \
+}
+
+#define EGL_OBJECT_DEFINE_CLASS(TN, t_n) \
+  EGL_OBJECT_DEFINE_CLASS_WITH_CODE (TN, t_n, /**/)
+
+static inline gpointer
+egl_object_new (const EglObjectClass * klass)
+{
+  return gst_vaapi_mini_object_new (GST_VAAPI_MINI_OBJECT_CLASS (klass));
+}
+
+static inline gpointer
+egl_object_new0 (const EglObjectClass * klass)
+{
+  return gst_vaapi_mini_object_new0 (GST_VAAPI_MINI_OBJECT_CLASS (klass));
+}
+
+typedef struct egl_object_class_s EglMessageClass;
+typedef struct egl_object_class_s EglVTableClass;
+typedef struct egl_object_class_s EglDisplayClass;
+typedef struct egl_object_class_s EglConfigClass;
+typedef struct egl_object_class_s EglContextClass;
+typedef struct egl_object_class_s EglSurfaceClass;
+typedef struct egl_object_class_s EglProgramClass;
+typedef struct egl_object_class_s EglWindowClass;
+
+EGL_OBJECT_DEFINE_CLASS (EglMessage, egl_message);
+EGL_OBJECT_DEFINE_CLASS (EglVTable, egl_vtable);
+EGL_OBJECT_DEFINE_CLASS (EglDisplay, egl_display);
+EGL_OBJECT_DEFINE_CLASS (EglConfig, egl_config);
+EGL_OBJECT_DEFINE_CLASS (EglContext, egl_context);
+EGL_OBJECT_DEFINE_CLASS (EglSurface, egl_surface);
+EGL_OBJECT_DEFINE_CLASS (EglProgram, egl_program);
+EGL_OBJECT_DEFINE_CLASS (EglWindow, egl_window);
+
+/* ------------------------------------------------------------------------- */
+// Desktop OpenGL and OpenGL|ES dispatcher (vtable)
+
+static GMutex gl_vtables_lock;
+static EglVTable *gl_vtables[4];
+
+#if (USE_GLES_VERSION_MASK & (1U << 0))
+static const gchar *gl_library_names[] = {
+  "libGL.la",
+  "libGL.so.1",
+  NULL
+};
+#endif
+
+#if (USE_GLES_VERSION_MASK & (1U << 1))
+static const gchar *gles1_library_names[] = {
+  "libGLESv1_CM.la",
+  "libGLESv1_CM.so.1",
+  NULL
+};
+#endif
+
+#if (USE_GLES_VERSION_MASK & (1U << 2))
+static const gchar *gles2_library_names[] = {
+  "libGLESv2.la",
+  "libGLESv2.so.2",
+  NULL
+};
+#endif
+
+static const gchar **gl_library_names_group[] = {
+#if (USE_GLES_VERSION_MASK & (1U << 0))
+  gl_library_names,
+#endif
+  NULL
+};
+
+static const gchar **gles1_library_names_group[] = {
+#if (USE_GLES_VERSION_MASK & (1U << 1))
+  gles1_library_names,
+#endif
+  NULL
+};
+
+static const gchar **gles2_library_names_group[] = {
+#if (USE_GLES_VERSION_MASK & (1U << 2))
+  gles2_library_names,
+#endif
+  NULL
+};
+
+static const gchar **gles3_library_names_group[] = {
+#if (USE_GLES_VERSION_MASK & (1U << 3))
+  gles2_library_names,
+#endif
+  NULL
+};
+
+static const gchar ***
+egl_vtable_get_library_names_group (guint gles_version)
+{
+  const gchar ***library_names_group;
+
+  switch (gles_version) {
+    case 0:
+      library_names_group = gl_library_names_group;
+      break;
+    case 1:
+      library_names_group = gles1_library_names_group;
+      break;
+    case 2:
+      library_names_group = gles2_library_names_group;
+      break;
+    case 3:
+      library_names_group = gles3_library_names_group;
+      break;
+    default:
+      library_names_group = NULL;
+      break;
+  }
+  return library_names_group;
+}
+
+static gboolean
+egl_vtable_check_extension (EglVTable * vtable, EGLDisplay display,
+    gboolean is_egl, const gchar * group_name, guint * group_ptr)
+{
+  gchar ***extensions_list;
+  const gchar *extensions;
+
+  g_return_val_if_fail (group_name != NULL, FALSE);
+  g_return_val_if_fail (group_ptr != NULL, FALSE);
+
+  if (*group_ptr > 0)
+    return TRUE;
+
+  GST_DEBUG ("check for %s extension %s", is_egl ? "EGL" : "GL", group_name);
+
+  if (is_egl) {
+    if (!vtable->egl_extensions) {
+      extensions = eglQueryString (display, EGL_EXTENSIONS);
+      if (!extensions)
+        return FALSE;
+      GST_DEBUG ("EGL extensions: %s", extensions);
+      vtable->egl_extensions = g_strsplit (extensions, " ", 0);
+    }
+    extensions_list = &vtable->egl_extensions;
+  } else {
+    if (!vtable->gl_extensions) {
+      extensions = (const gchar *) vtable->glGetString (GL_EXTENSIONS);
+      if (!extensions)
+        return FALSE;
+      GST_DEBUG ("GL extensions: %s", extensions);
+      vtable->gl_extensions = g_strsplit (extensions, " ", 0);
+    }
+    extensions_list = &vtable->gl_extensions;
+  }
+  if (!g_strv_match_string (*extensions_list, group_name))
+    return FALSE;
+
+  GST_LOG ("  found %s extension %s", is_egl ? "EGL" : "GL", group_name);
+  (*group_ptr)++;
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_load_symbol (EglVTable * vtable, EGLDisplay display, gboolean is_egl,
+    const gchar * symbol_name, gpointer * symbol_ptr,
+    const gchar * group_name, guint * group_ptr)
+{
+  void (*symbol) (void);
+
+  if (group_ptr && !*group_ptr) {
+    if (!egl_vtable_check_extension (vtable, display, is_egl, group_name,
+            group_ptr))
+      return FALSE;
+  }
+
+  if (is_egl) {
+    symbol = eglGetProcAddress (symbol_name);
+  } else {
+    if (!g_module_symbol (vtable->base.handle.p, symbol_name,
+            (gpointer *) & symbol))
+      return FALSE;
+  }
+  if (!symbol)
+    return FALSE;
+
+  GST_LOG ("  found symbol %s", symbol_name);
+  if (symbol_ptr)
+    *symbol_ptr = symbol;
+  if (group_ptr)
+    (*group_ptr)++;
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_load_egl_symbols (EglVTable * vtable, EGLDisplay display)
+{
+  guint n = 0;
+
+#define EGL_DEFINE_EXTENSION(NAME) do {                         \
+      egl_vtable_check_extension (vtable, display, TRUE,        \
+          "EGL_" G_STRINGIFY (NAME),                            \
+          &vtable->GL_PROTO_GEN_CONCAT(has_EGL_,NAME));         \
+    } while (0);
+
+#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) do {             \
+      n += egl_vtable_load_symbol (vtable, display, TRUE,       \
+          G_STRINGIFY(GL_PROTO_GEN_CONCAT(egl,NAME)),           \
+          (gpointer *) &vtable->GL_PROTO_GEN_CONCAT(egl,NAME),  \
+          "EGL_" G_STRINGIFY(EXTENSION),                        \
+          &vtable->GL_PROTO_GEN_CONCAT(has_EGL_,EXTENSION));    \
+    } while (0);
+
+#include "egl_vtable.h"
+
+  vtable->num_egl_symbols = n;
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_load_gl_symbols (EglVTable * vtable, EGLDisplay display)
+{
+  guint n = 0;
+
+  vtable->has_GL_CORE_1_0 = 1;
+  vtable->has_GL_CORE_1_1 = 1;
+  vtable->has_GL_CORE_1_3 = 1;
+  vtable->has_GL_CORE_2_0 = 1;
+
+#define GL_DEFINE_EXTENSION(NAME) do {                          \
+      egl_vtable_check_extension (vtable, display, FALSE,       \
+          "GL_" G_STRINGIFY (NAME),                             \
+          &vtable->GL_PROTO_GEN_CONCAT(has_GL_,NAME));          \
+    } while (0);
+
+#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) do {              \
+      n += egl_vtable_load_symbol (vtable, display, FALSE,      \
+          G_STRINGIFY(GL_PROTO_GEN_CONCAT(gl,NAME)),            \
+          (gpointer *) &vtable->GL_PROTO_GEN_CONCAT(gl,NAME),   \
+          "GL_" G_STRINGIFY(EXTENSION),                         \
+          &vtable->GL_PROTO_GEN_CONCAT(has_GL_,EXTENSION));     \
+    } while (0);
+
+#include "egl_vtable.h"
+
+  --vtable->has_GL_CORE_1_0;
+  --vtable->has_GL_CORE_1_1;
+  --vtable->has_GL_CORE_1_3;
+  --vtable->has_GL_CORE_2_0;
+
+  vtable->num_gl_symbols = n;
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_try_load_library (EglVTable * vtable, const gchar * name)
+{
+  if (vtable->base.handle.p)
+    g_module_close (vtable->base.handle.p);
+  vtable->base.handle.p = g_module_open (name,
+      G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL);
+  if (!vtable->base.handle.p)
+    return FALSE;
+
+  GST_DEBUG ("loaded backend: %s", g_module_name (vtable->base.handle.p));
+  return TRUE;
+}
+
+static gboolean
+egl_vtable_find_library (EglVTable * vtable)
+{
+  const gchar ***library_names_ptr =
+      egl_vtable_get_library_names_group (vtable->gles_version);
+
+  if (!library_names_ptr)
+    return FALSE;
+
+  for (; *library_names_ptr != NULL; library_names_ptr++) {
+    const gchar **library_name_ptr = *library_names_ptr;
+    for (; *library_name_ptr != NULL; library_name_ptr++) {
+      if (egl_vtable_try_load_library (vtable, *library_name_ptr))
+        return TRUE;
+    }
+  }
+  return FALSE;
+}
+
+static gboolean
+egl_vtable_init (EglVTable * vtable, EGLDisplay display, guint gles_version)
+{
+  GST_DEBUG ("initialize for OpenGL|ES API version %d", gles_version);
+
+  vtable->gles_version = gles_version;
+  if (!egl_vtable_find_library (vtable))
+    return FALSE;
+  if (!egl_vtable_load_egl_symbols (vtable, display))
+    return FALSE;
+  return TRUE;
+}
+
+static void
+egl_vtable_finalize (EglVTable * vtable)
+{
+  g_strfreev (vtable->egl_extensions);
+  g_strfreev (vtable->gl_extensions);
+  if (vtable->base.handle.p)
+    g_module_close (vtable->base.handle.p);
+
+  if (vtable->base.is_wrapped) {
+    g_mutex_lock (&gl_vtables_lock);
+    gl_vtables[vtable->gles_version] = NULL;
+    g_mutex_unlock (&gl_vtables_lock);
+  }
+}
+
+static EglVTable *
+egl_vtable_new (EglDisplay * display, guint gles_version)
+{
+  EglVTable *vtable;
+
+  g_return_val_if_fail (display != NULL, NULL);
+
+  vtable = egl_object_new0 (egl_vtable_class ());
+  if (!vtable
+      || !egl_vtable_init (vtable, display->base.handle.p, gles_version))
+    goto error;
+  return vtable;
+
+  /* ERRORS */
+error:
+  {
+    egl_object_replace (&vtable, NULL);
+    return NULL;
+  }
+}
+
+static EglVTable *
+egl_vtable_new_cached (EglDisplay * display, guint gles_version)
+{
+  EglVTable *vtable, **vtable_ptr;
+
+  g_return_val_if_fail (gles_version < G_N_ELEMENTS (gl_vtables), NULL);
+
+  vtable_ptr = &gl_vtables[gles_version];
+
+  g_mutex_lock (&gl_vtables_lock);
+  vtable = *vtable_ptr;
+  if (vtable)
+    egl_object_ref (vtable);
+  else {
+    vtable = egl_vtable_new (display, gles_version);
+    if (vtable) {
+      vtable->base.is_wrapped = TRUE;
+      *vtable_ptr = vtable;
+    }
+  }
+  g_mutex_unlock (&gl_vtables_lock);
+  return vtable;
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Display
+
+static gboolean
+egl_display_run (EglDisplay * display, EglContextRunFunc func, gpointer args)
+{
+  EglMessage *msg;
+
+  if (display->gl_thread == g_thread_self ()) {
+    func (args);
+    return TRUE;
+  }
+
+  msg = egl_object_new0 (egl_message_class ());
+  if (!msg)
+    return FALSE;
+
+  msg->base.is_valid = TRUE;
+  msg->func = func;
+  msg->args = args;
+  g_async_queue_push (display->gl_queue, egl_object_ref (msg));
+
+  g_mutex_lock (&display->mutex);
+  while (msg->base.is_valid)
+    g_cond_wait (&display->gl_thread_ready, &display->mutex);
+  g_mutex_unlock (&display->mutex);
+  egl_object_unref (msg);
+  return TRUE;
+}
+
+static gpointer
+egl_get_display_from_native (guintptr native_display, guint gl_platform)
+{
+#if USE_GST_GL_HELPERS && GST_GL_HAVE_PLATFORM_EGL
+  EGLDisplay ret;
+  GstGLDisplayType display_type = GST_GL_DISPLAY_TYPE_ANY;
+
+  switch (gl_platform) {
+    case EGL_PLATFORM_X11:
+      display_type = GST_GL_DISPLAY_TYPE_X11;
+      break;
+    case EGL_PLATFORM_WAYLAND:
+      display_type = GST_GL_DISPLAY_TYPE_WAYLAND;
+      break;
+    default:
+      break;
+  }
+
+  ret = gst_gl_display_egl_get_from_native (display_type, native_display);
+  if (ret != EGL_NO_DISPLAY)
+    return ret;
+#endif
+  return eglGetDisplay ((EGLNativeDisplayType) native_display);
+}
+
+static gpointer
+egl_display_thread (gpointer data)
+{
+  EglDisplay *const display = data;
+  EGLDisplay gl_display = display->base.handle.p;
+  EGLint major_version, minor_version;
+  gchar **gl_apis, **gl_api;
+
+  g_mutex_lock (&display->mutex);
+  if (!display->base.is_wrapped) {
+    gl_display = display->base.handle.p =
+        egl_get_display_from_native (display->base.handle.u,
+        display->gl_platform);
+    if (!gl_display)
+      goto error;
+    if (!eglInitialize (gl_display, &major_version, &minor_version))
+      goto error;
+  }
+
+  display->gl_vendor_string =
+      g_strdup (eglQueryString (gl_display, EGL_VENDOR));
+  display->gl_version_string =
+      g_strdup (eglQueryString (gl_display, EGL_VERSION));
+  display->gl_apis_string =
+      g_strdup (eglQueryString (gl_display, EGL_CLIENT_APIS));
+
+  GST_INFO ("EGL vendor: %s", display->gl_vendor_string);
+  GST_INFO ("EGL version: %s", display->gl_version_string);
+  GST_INFO ("EGL client APIs: %s", display->gl_apis_string);
+
+  gl_apis = g_strsplit (display->gl_apis_string, " ", 0);
+  if (!gl_apis)
+    goto error;
+  for (gl_api = gl_apis; *gl_api != NULL; gl_api++) {
+    const GlVersionInfo *const vinfo =
+        gl_version_info_lookup_by_api_name (*gl_api);
+
+    if (vinfo)
+      display->gl_apis |= vinfo->gl_api_bit;
+  }
+  g_strfreev (gl_apis);
+  if (!display->gl_apis)
+    goto error;
+
+  display->base.is_valid = TRUE;
+  display->created = TRUE;
+  g_cond_broadcast (&display->gl_thread_ready);
+  g_mutex_unlock (&display->mutex);
+
+  while (!g_atomic_int_get (&display->gl_thread_cancel)) {
+    EglMessage *const msg =
+        g_async_queue_timeout_pop (display->gl_queue, 100000);
+
+    if (msg) {
+      if (msg->base.is_valid) {
+        msg->func (msg->args);
+        msg->base.is_valid = FALSE;
+        g_cond_broadcast (&display->gl_thread_ready);
+      }
+      egl_object_unref (msg);
+    }
+  }
+  g_mutex_lock (&display->mutex);
+
+done:
+  if (gl_display != EGL_NO_DISPLAY && !display->base.is_wrapped)
+    eglTerminate (gl_display);
+  display->base.handle.p = NULL;
+  g_cond_broadcast (&display->gl_thread_ready);
+  g_mutex_unlock (&display->mutex);
+  return NULL;
+
+  /* ERRORS */
+error:
+  {
+    display->created = TRUE;
+    display->base.is_valid = FALSE;
+    goto done;
+  }
+}
+
+static gboolean
+egl_display_init (EglDisplay * display)
+{
+  display->gl_queue =
+      g_async_queue_new_full ((GDestroyNotify) gst_vaapi_mini_object_unref);
+  if (!display->gl_queue)
+    return FALSE;
+
+  g_mutex_init (&display->mutex);
+  g_cond_init (&display->gl_thread_ready);
+  display->gl_thread = g_thread_try_new ("OpenGL Thread", egl_display_thread,
+      display, NULL);
+  if (!display->gl_thread)
+    return FALSE;
+
+  g_mutex_lock (&display->mutex);
+  while (!display->created)
+    g_cond_wait (&display->gl_thread_ready, &display->mutex);
+  g_mutex_unlock (&display->mutex);
+  return display->base.is_valid;
+}
+
+static void
+egl_display_finalize (EglDisplay * display)
+{
+  g_atomic_int_set (&display->gl_thread_cancel, TRUE);
+  g_thread_join (display->gl_thread);
+  g_cond_clear (&display->gl_thread_ready);
+  g_mutex_clear (&display->mutex);
+  g_async_queue_unref (display->gl_queue);
+
+  g_free (display->gl_vendor_string);
+  g_free (display->gl_version_string);
+  g_free (display->gl_apis_string);
+}
+
+static EglDisplay *
+egl_display_new_full (gpointer handle, gboolean is_wrapped, guint platform)
+{
+  EglDisplay *display;
+
+  display = egl_object_new0 (egl_display_class ());
+  if (!display)
+    return NULL;
+
+  display->base.handle.p = handle;
+  display->base.is_wrapped = is_wrapped;
+  display->gl_platform = platform;
+  if (!egl_display_init (display))
+    goto error;
+  return display;
+
+  /* ERRORS */
+error:
+  {
+    egl_object_unref (display);
+    return NULL;
+  }
+}
+
+EglDisplay *
+egl_display_new (gpointer native_display, guint platform)
+{
+  g_return_val_if_fail (native_display != NULL, NULL);
+
+  return egl_display_new_full (native_display, FALSE, platform);
+}
+
+EglDisplay *
+egl_display_new_wrapped (EGLDisplay gl_display)
+{
+  g_return_val_if_fail (gl_display != EGL_NO_DISPLAY, NULL);
+
+  return egl_display_new_full (gl_display, TRUE, EGL_PLATFORM_UNKNOWN);
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Config
+
+static gboolean
+egl_config_init (EglConfig * config, EglDisplay * display,
+    const EGLint * attribs)
+{
+  EGLDisplay const gl_display = display->base.handle.p;
+  const GlVersionInfo *vinfo;
+  EGLConfig gl_config;
+  EGLint v, gl_apis, num_configs;
+
+  egl_object_replace (&config->display, display);
+
+  if (!eglChooseConfig (gl_display, attribs, &gl_config, 1, &num_configs))
+    return FALSE;
+  if (num_configs != 1)
+    return FALSE;
+  config->base.handle.p = gl_config;
+
+  if (!eglGetConfigAttrib (gl_display, gl_config, EGL_CONFIG_ID, &v))
+    return FALSE;
+  config->config_id = v;
+
+  if (!eglGetConfigAttrib (gl_display, gl_config, EGL_NATIVE_VISUAL_ID, &v))
+    return FALSE;
+  config->visual_id = v;
+
+  if (!eglGetConfigAttrib (gl_display, gl_config, EGL_RENDERABLE_TYPE, &v))
+    return FALSE;
+  if (!egl_find_attrib_value (attribs, EGL_RENDERABLE_TYPE, &gl_apis))
+    return FALSE;
+  vinfo = gl_version_info_lookup_by_api (v & gl_apis);
+  if (!vinfo)
+    return FALSE;
+  config->gles_version = vinfo->gles_version;
+  config->gl_api = vinfo->gles_version > 0 ? EGL_OPENGL_ES_API : EGL_OPENGL_API;
+  return TRUE;
+}
+
+static void
+egl_config_finalize (EglConfig * config)
+{
+  egl_object_replace (&config->display, NULL);
+}
+
+EglConfig *
+egl_config_new (EglDisplay * display, guint gles_version, GstVideoFormat format)
+{
+  EGLint attribs[2 * 6 + 1], *attrib = attribs;
+  const GstVideoFormatInfo *finfo;
+  const GlVersionInfo *vinfo;
+
+  g_return_val_if_fail (display != NULL, NULL);
+
+  finfo = gst_video_format_get_info (format);
+  if (!finfo || !GST_VIDEO_FORMAT_INFO_IS_RGB (finfo))
+    return NULL;
+
+  vinfo = gl_version_info_lookup (gles_version);
+  if (!vinfo)
+    return NULL;
+
+  *attrib++ = EGL_COLOR_BUFFER_TYPE;
+  *attrib++ = EGL_RGB_BUFFER;
+  *attrib++ = EGL_RED_SIZE;
+  *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_R);
+  *attrib++ = EGL_GREEN_SIZE;
+  *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_G);
+  *attrib++ = EGL_BLUE_SIZE;
+  *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_B);
+  *attrib++ = EGL_ALPHA_SIZE;
+  *attrib++ = GST_VIDEO_FORMAT_INFO_DEPTH (finfo, GST_VIDEO_COMP_A);
+  *attrib++ = EGL_RENDERABLE_TYPE;
+  *attrib++ = vinfo->gl_api_bit;
+  *attrib++ = EGL_NONE;
+  g_assert (attrib - attribs <= G_N_ELEMENTS (attribs));
+
+  return egl_config_new_with_attribs (display, attribs);
+}
+
+EglConfig *
+egl_config_new_with_attribs (EglDisplay * display, const EGLint * attribs)
+{
+  EglConfig *config;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (attribs != NULL, NULL);
+
+  config = egl_object_new0 (egl_config_class ());
+  if (!config || !egl_config_init (config, display, attribs))
+    goto error;
+  return config;
+
+  /* ERRORS */
+error:
+  {
+    egl_object_replace (&config, NULL);
+    return NULL;
+  }
+}
+
+static EglConfig *
+egl_config_new_from_gl_context (EglDisplay * display, EGLContext gl_context)
+{
+  EGLDisplay const gl_display = display->base.handle.p;
+  EGLint attribs[3 * 2 + 1], *attrib = attribs;
+  EGLint config_id, api, v;
+  guint gles_version;
+  const GlVersionInfo *vinfo;
+
+  if (!eglQueryContext (gl_display, gl_context, EGL_CONFIG_ID, &config_id))
+    return NULL;
+  if (!eglQueryContext (gl_display, gl_context, EGL_CONTEXT_CLIENT_TYPE, &api))
+    return NULL;
+  if (!eglQueryContext (gl_display, gl_context, EGL_CONTEXT_CLIENT_VERSION, &v))
+    return NULL;
+
+  if (api == EGL_OPENGL_API)
+    gles_version = 0;
+  else if (api == EGL_OPENGL_ES_API)
+    gles_version = v;
+  else {
+    GST_ERROR ("unsupported EGL client API (%d)", api);
+    return NULL;
+  }
+
+  vinfo = gl_version_info_lookup (gles_version);
+  if (!vinfo)
+    return NULL;
+
+  *attrib++ = EGL_COLOR_BUFFER_TYPE;
+  *attrib++ = EGL_RGB_BUFFER;
+  *attrib++ = EGL_CONFIG_ID;
+  *attrib++ = config_id;
+  *attrib++ = EGL_RENDERABLE_TYPE;
+  *attrib++ = vinfo->gl_api_bit;
+  *attrib++ = EGL_NONE;
+  g_assert (attrib - attribs <= G_N_ELEMENTS (attribs));
+
+  return egl_config_new_with_attribs (display, attribs);
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Surface
+
+static void
+egl_surface_finalize (EglSurface * surface)
+{
+  if (surface->base.handle.p != EGL_NO_SURFACE && !surface->base.is_wrapped)
+    eglDestroySurface (surface->display->base.handle.p, surface->base.handle.p);
+  egl_object_replace (&surface->display, NULL);
+}
+
+static EglSurface *
+egl_surface_new_wrapped (EglDisplay * display, EGLSurface gl_surface)
+{
+  EglSurface *surface;
+
+  g_return_val_if_fail (display != NULL, NULL);
+
+  surface = egl_object_new (egl_surface_class ());
+  if (!surface)
+    return NULL;
+
+  surface->base.is_wrapped = TRUE;
+  surface->base.handle.p = gl_surface;
+  surface->display = egl_object_ref (display);
+  return surface;
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Context
+
+static void egl_context_state_get_current (EglContextState * cs);
+
+static gboolean
+egl_context_state_set_current (EglContextState * new_cs,
+    EglContextState * old_cs);
+
+static gboolean
+ensure_vtable (EglContext * ctx)
+{
+  if (!ctx->vtable) {
+    ctx->vtable = egl_vtable_new_cached (ctx->display,
+        ctx->config ? ctx->config->gles_version : 0);
+    if (!ctx->vtable)
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static gboolean
+ensure_context (EglContext * ctx, EGLContext gl_parent_context)
+{
+  EGLDisplay *const gl_display = ctx->display->base.handle.p;
+  EGLContext gl_context = ctx->base.handle.p;
+  EGLint gles_attribs[3], *attribs = NULL;
+
+  if (!gl_context) {
+    if (ctx->config->gles_version >= 2) {
+      attribs = gles_attribs;
+      attribs[0] = EGL_CONTEXT_CLIENT_VERSION;
+      attribs[1] = ctx->config->gles_version;
+      attribs[2] = EGL_NONE;
+    }
+
+    gl_context = eglCreateContext (gl_display, ctx->config->base.handle.p,
+        gl_parent_context, attribs);
+    if (!gl_context)
+      goto error_create_context;
+    ctx->base.handle.p = gl_context;
+  }
+  return TRUE;
+
+  /* ERRORS */
+error_create_context:
+  GST_ERROR ("failed to create EGL context");
+  return FALSE;
+}
+
+static inline gboolean
+ensure_gl_is_surfaceless (EglContext * ctx)
+{
+  return ctx->vtable->has_EGL_KHR_surfaceless_context ||
+      (ctx->read_surface && ctx->draw_surface);
+}
+
+static gboolean
+ensure_gl_scene (EglContext * ctx)
+{
+  EglVTable *vtable;
+
+  if (!ensure_gl_is_surfaceless (ctx))
+    return FALSE;
+
+  if (ctx->base.is_valid)
+    return TRUE;
+
+  vtable = egl_context_get_vtable (ctx, TRUE);
+  if (!vtable)
+    return FALSE;
+
+  vtable->glClearColor (0.0, 0.0, 0.0, 1.0);
+  if (ctx->config && ctx->config->gles_version == 0)
+    vtable->glEnable (GL_TEXTURE_2D);
+  vtable->glDisable (GL_BLEND);
+  vtable->glDisable (GL_DEPTH_TEST);
+
+  ctx->base.is_valid = TRUE;
+  return TRUE;
+}
+
+/**
+ * egl_context_state_get_current:
+ * @cs: return location to the current #EglContextState
+ *
+ * Retrieves the current EGL context, display and surface to pack into
+ * the #EglContextState struct.
+ */
+static void
+egl_context_state_get_current (EglContextState * cs)
+{
+  cs->display = eglGetCurrentDisplay ();
+  cs->context = eglGetCurrentContext ();
+  if (cs->context) {
+    cs->read_surface = eglGetCurrentSurface (EGL_READ);
+    cs->draw_surface = eglGetCurrentSurface (EGL_DRAW);
+  } else {
+    cs->read_surface = EGL_NO_SURFACE;
+    cs->draw_surface = EGL_NO_SURFACE;
+  }
+}
+
+/**
+ * egl_context_state_set_current:
+ * @new_cs: the requested new #EglContextState
+ * @old_cs: return location to the context that was previously current
+ *
+ * Makes the @new_cs EGL context the current EGL rendering context of
+ * the calling thread, replacing the previously current context if
+ * there was one.
+ *
+ * If @old_cs is non %NULL, the previously current EGL context and
+ * surface are recorded.
+ *
+ * Return value: %TRUE on success
+ */
+static gboolean
+egl_context_state_set_current (EglContextState * new_cs,
+    EglContextState * old_cs)
+{
+  /* If display is NULL, this could be that new_cs was retrieved from
+     egl_context_state_get_current() with none set previously. If that case,
+     the other fields are also NULL and we don't return an error */
+  if (!new_cs->display)
+    return !new_cs->context && !new_cs->read_surface && !new_cs->draw_surface;
+
+  if (old_cs) {
+    if (old_cs == new_cs)
+      return TRUE;
+    egl_context_state_get_current (old_cs);
+    if (old_cs->display == new_cs->display &&
+        old_cs->context == new_cs->context &&
+        old_cs->read_surface == new_cs->read_surface &&
+        old_cs->draw_surface == new_cs->draw_surface)
+      return TRUE;
+  }
+  return eglMakeCurrent (new_cs->display, new_cs->draw_surface,
+      new_cs->read_surface, new_cs->context);
+}
+
+static gboolean
+egl_context_init (EglContext * ctx, EglDisplay * display, EglConfig * config,
+    EGLContext gl_parent_context)
+{
+  egl_object_replace (&ctx->display, display);
+  egl_object_replace (&ctx->config, config);
+
+  if (config)
+    eglBindAPI (config->gl_api);
+
+  if (!ensure_vtable (ctx))
+    return FALSE;
+  if (!ensure_context (ctx, gl_parent_context))
+    return FALSE;
+  return TRUE;
+}
+
+static void
+egl_context_finalize (EglContext * ctx)
+{
+  if (ctx->base.handle.p && !ctx->base.is_wrapped)
+    eglDestroyContext (ctx->display->base.handle.p, ctx->base.handle.p);
+  egl_object_replace (&ctx->read_surface, NULL);
+  egl_object_replace (&ctx->draw_surface, NULL);
+  egl_object_replace (&ctx->config, NULL);
+  egl_object_replace (&ctx->display, NULL);
+  egl_object_replace (&ctx->vtable, NULL);
+}
+
+typedef struct
+{
+  EglDisplay *display;
+  EglConfig *config;
+  EGLContext gl_parent_context;
+  EglContext *context;          /* result */
+} CreateContextArgs;
+
+static void
+do_egl_context_new (CreateContextArgs * args)
+{
+  EglContext *ctx;
+
+  ctx = egl_object_new0 (egl_context_class ());
+  if (!ctx || !egl_context_init (ctx, args->display, args->config,
+          args->gl_parent_context))
+    goto error;
+  args->context = ctx;
+  return;
+
+  /* ERRORS */
+error:
+  {
+    egl_object_replace (&ctx, NULL);
+    args->context = NULL;
+  }
+}
+
+EglContext *
+egl_context_new (EglDisplay * display, EglConfig * config, EglContext * parent)
+{
+  CreateContextArgs args;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (config != NULL, NULL);
+
+  args.display = display;
+  args.config = config;
+  args.gl_parent_context = parent ? parent->base.handle.p : EGL_NO_CONTEXT;
+  if (!egl_display_run (display, (EglContextRunFunc) do_egl_context_new, &args))
+    return NULL;
+  return args.context;
+}
+
+EglContext *
+egl_context_new_wrapped (EglDisplay * display, EGLContext gl_context)
+{
+  CreateContextArgs args;
+  EglConfig *config;
+  gboolean success;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (gl_context != EGL_NO_CONTEXT, NULL);
+
+  config = egl_config_new_from_gl_context (display, gl_context);
+  if (!config)
+    return NULL;
+
+  args.display = display;
+  args.config = config;
+  args.gl_parent_context = gl_context;
+  args.context = NULL;
+  success = egl_display_run (display, (EglContextRunFunc) do_egl_context_new,
+      &args);
+  egl_object_unref (config);
+  if (!success)
+    return NULL;
+
+  return args.context;
+}
+
+EglVTable *
+egl_context_get_vtable (EglContext * ctx, gboolean need_gl_symbols)
+{
+  g_return_val_if_fail (ctx != NULL, NULL);
+  g_return_val_if_fail (ctx->display->gl_thread == g_thread_self (), NULL);
+
+  if (!ensure_vtable (ctx))
+    return NULL;
+
+  if (need_gl_symbols && !(ctx->vtable->num_gl_symbols > 0 ||
+          egl_vtable_load_gl_symbols (ctx->vtable,
+              ctx->display->base.handle.p)))
+    return NULL;
+  return ctx->vtable;
+}
+
+static void
+egl_context_set_surface (EglContext * ctx, EglSurface * surface)
+{
+  g_return_if_fail (ctx != NULL);
+  g_return_if_fail (surface != NULL);
+
+  egl_object_replace (&ctx->read_surface, surface);
+  egl_object_replace (&ctx->draw_surface, surface);
+}
+
+gboolean
+egl_context_set_current (EglContext * ctx, gboolean activate,
+    EglContextState * old_cs)
+{
+  EglContextState cs, *new_cs;
+
+  g_return_val_if_fail (ctx != NULL, FALSE);
+  g_return_val_if_fail (ctx->display->gl_thread == g_thread_self (), FALSE);
+
+  if (activate) {
+    new_cs = &cs;
+    new_cs->display = ctx->display->base.handle.p;
+    new_cs->context = ctx->base.handle.p;
+    new_cs->draw_surface = ctx->draw_surface ?
+        ctx->draw_surface->base.handle.p : EGL_NO_SURFACE;
+    new_cs->read_surface = ctx->read_surface ?
+        ctx->read_surface->base.handle.p : EGL_NO_SURFACE;
+  } else if (old_cs) {
+    new_cs = old_cs;
+    old_cs = NULL;
+  } else {
+    new_cs = &cs;
+    new_cs->display = ctx->display->base.handle.p;
+    new_cs->context = EGL_NO_CONTEXT;
+    new_cs->draw_surface = EGL_NO_SURFACE;
+    new_cs->read_surface = EGL_NO_SURFACE;
+    old_cs = NULL;
+  }
+
+  if (!egl_context_state_set_current (new_cs, old_cs))
+    return FALSE;
+  if (activate && !ensure_gl_scene (ctx))
+    return FALSE;
+  return TRUE;
+}
+
+gboolean
+egl_context_run (EglContext * ctx, EglContextRunFunc func, gpointer args)
+{
+  g_return_val_if_fail (ctx != NULL, FALSE);
+  g_return_val_if_fail (func != NULL, FALSE);
+
+  return egl_display_run (ctx->display, func, args);
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Program
+
+static GLuint
+egl_compile_shader (EglContext * ctx, GLenum type, const char *source)
+{
+  EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE);
+  GLuint shader;
+  GLint status;
+  char log[BUFSIZ];
+  GLsizei log_length;
+
+  shader = vtable->glCreateShader (type);
+  vtable->glShaderSource (shader, 1, &source, NULL);
+  vtable->glCompileShader (shader);
+  vtable->glGetShaderiv (shader, GL_COMPILE_STATUS, &status);
+  if (!status) {
+    GST_ERROR ("failed to compile %s shader",
+        type == GL_FRAGMENT_SHADER ? "fragment" :
+        type == GL_VERTEX_SHADER ? "vertex" : "<unknown>");
+
+    vtable->glGetShaderInfoLog (shader, sizeof (log), &log_length, log);
+    GST_ERROR ("info log: %s", log);
+    return 0;
+  }
+  return shader;
+}
+
+static void
+egl_program_finalize (EglProgram * program)
+{
+  EglVTable *const vtable = program->vtable;
+
+  if (program->base.handle.u)
+    vtable->glDeleteProgram (program->base.handle.u);
+  if (program->frag_shader)
+    vtable->glDeleteShader (program->frag_shader);
+  if (program->vert_shader)
+    vtable->glDeleteShader (program->vert_shader);
+  egl_object_replace (&program->vtable, NULL);
+}
+
+static gboolean
+egl_program_init (EglProgram * program, EglContext * ctx,
+    const gchar * frag_shader_text, const gchar * vert_shader_text)
+{
+  EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE);
+  GLuint prog_id;
+  char msg[BUFSIZ];
+  GLsizei msglen;
+  GLint status;
+
+  if (ctx->config->gles_version == 1)
+    goto error_unsupported_gles_version;
+
+  program->vtable = egl_object_ref (vtable);
+
+  program->frag_shader =
+      egl_compile_shader (ctx, GL_FRAGMENT_SHADER, frag_shader_text);
+  if (!program->frag_shader)
+    return FALSE;
+
+  program->vert_shader =
+      egl_compile_shader (ctx, GL_VERTEX_SHADER, vert_shader_text);
+  if (!program->vert_shader)
+    return FALSE;
+
+  prog_id = vtable->glCreateProgram ();
+  if (!prog_id)
+    return FALSE;
+  program->base.handle.u = prog_id;
+
+  vtable->glAttachShader (prog_id, program->frag_shader);
+  vtable->glAttachShader (prog_id, program->vert_shader);
+  vtable->glBindAttribLocation (prog_id, 0, "position");
+  vtable->glBindAttribLocation (prog_id, 1, "texcoord");
+  vtable->glLinkProgram (prog_id);
+
+  vtable->glGetProgramiv (prog_id, GL_LINK_STATUS, &status);
+  if (!status)
+    goto error_link_program;
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_gles_version:
+  GST_ERROR ("unsupported shader with OpenGL|ES version 1");
+  return FALSE;
+error_link_program:
+  vtable->glGetProgramInfoLog (prog_id, sizeof (msg), &msglen, msg);
+  GST_ERROR ("failed to link program: %s", msg);
+  return FALSE;
+}
+
+EglProgram *
+egl_program_new (EglContext * ctx, const gchar * frag_shader_text,
+    const gchar * vert_shader_text)
+{
+  EglProgram *program;
+
+  g_return_val_if_fail (ctx != NULL, NULL);
+  g_return_val_if_fail (frag_shader_text != NULL, NULL);
+  g_return_val_if_fail (vert_shader_text != NULL, NULL);
+
+  program = egl_object_new0 (egl_program_class ());
+  if (!program
+      || !egl_program_init (program, ctx, frag_shader_text, vert_shader_text))
+    goto error;
+  return program;
+
+  /* ERRORS */
+error:
+  {
+    egl_object_replace (&program, NULL);
+    return NULL;
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+// EGL Window
+
+static gboolean
+egl_window_init (EglWindow * window, EglContext * ctx, gpointer native_window)
+{
+  EGLSurface gl_surface;
+
+  window->context = egl_context_new (ctx->display, ctx->config, ctx);
+  if (!window->context)
+    return FALSE;
+  ctx = window->context;
+
+  gl_surface = eglCreateWindowSurface (ctx->display->base.handle.p,
+      ctx->config->base.handle.p, (EGLNativeWindowType) native_window, NULL);
+  if (!gl_surface)
+    return FALSE;
+
+  window->surface = egl_surface_new_wrapped (ctx->display, gl_surface);
+  if (!window->surface)
+    goto error_create_surface;
+  window->base.handle.p = gl_surface;
+  window->base.is_wrapped = FALSE;
+
+  egl_context_set_surface (ctx, window->surface);
+  return TRUE;
+
+  /* ERRORS */
+error_create_surface:
+  GST_ERROR ("failed to create EGL wrapper surface");
+  eglDestroySurface (ctx->display->base.handle.p, gl_surface);
+  return FALSE;
+}
+
+static void
+egl_window_finalize (EglWindow * window)
+{
+  if (window->context && window->base.handle.p)
+    eglDestroySurface (window->context->display->base.handle.p,
+        window->base.handle.p);
+
+  egl_object_replace (&window->surface, NULL);
+  egl_object_replace (&window->context, NULL);
+}
+
+EglWindow *
+egl_window_new (EglContext * ctx, gpointer native_window)
+{
+  EglWindow *window;
+
+  g_return_val_if_fail (ctx != NULL, NULL);
+  g_return_val_if_fail (native_window != NULL, NULL);
+
+  window = egl_object_new0 (egl_window_class ());
+  if (!window || !egl_window_init (window, ctx, native_window))
+    goto error;
+  return window;
+
+  /* ERRORS */
+error:
+  {
+    egl_object_replace (&window, NULL);
+    return NULL;
+  }
+}
+
+/* ------------------------------------------------------------------------- */
+// Misc utility functions
+
+void
+egl_matrix_set_identity (gfloat m[16])
+{
+#define MAT(m,r,c) (m)[(c) * 4 + (r)]
+  MAT (m, 0, 0) = 1.0;
+  MAT (m, 0, 1) = 0.0;
+  MAT (m, 0, 2) = 0.0;
+  MAT (m, 0, 3) = 0.0;
+  MAT (m, 1, 0) = 0.0;
+  MAT (m, 1, 1) = 1.0;
+  MAT (m, 1, 2) = 0.0;
+  MAT (m, 1, 3) = 0.0;
+  MAT (m, 2, 0) = 0.0;
+  MAT (m, 2, 1) = 0.0;
+  MAT (m, 2, 2) = 1.0;
+  MAT (m, 2, 3) = 0.0;
+  MAT (m, 3, 0) = 0.0;
+  MAT (m, 3, 1) = 0.0;
+  MAT (m, 3, 2) = 0.0;
+  MAT (m, 3, 3) = 1.0;
+#undef MAT
+}
+
+/**
+ * egl_create_texture:
+ * @ctx: the parent #EglContext object
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates a texture with the specified dimensions and @format. The
+ * internal format will be automatically derived from @format.
+ *
+ * Return value: the newly created texture name
+ */
+guint
+egl_create_texture (EglContext * ctx, guint target, guint format,
+    guint width, guint height)
+{
+  EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE);
+  guint internal_format, texture, bytes_per_component;
+
+  internal_format = format;
+  switch (format) {
+    case GL_LUMINANCE:
+      bytes_per_component = 1;
+      break;
+    case GL_LUMINANCE_ALPHA:
+      bytes_per_component = 2;
+      break;
+    case GL_RGBA:
+    case GL_BGRA_EXT:
+      internal_format = GL_RGBA;
+      bytes_per_component = 4;
+      break;
+    default:
+      bytes_per_component = 0;
+      break;
+  }
+  g_assert (bytes_per_component > 0);
+
+  vtable->glGenTextures (1, &texture);
+  vtable->glBindTexture (target, texture);
+
+  if (width > 0 && height > 0)
+    vtable->glTexImage2D (target, 0, internal_format, width, height, 0,
+        format, GL_UNSIGNED_BYTE, NULL);
+
+  vtable->glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  vtable->glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  vtable->glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  vtable->glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  vtable->glPixelStorei (GL_UNPACK_ALIGNMENT, bytes_per_component);
+
+  return texture;
+}
+
+/**
+ * egl_destroy_texture:
+ * @ctx: the parent #EglContext object
+ * @texture: the texture name to delete
+ *
+ * Destroys the supplied @texture name.
+ */
+void
+egl_destroy_texture (EglContext * ctx, guint texture)
+{
+  EglVTable *const vtable = egl_context_get_vtable (ctx, TRUE);
+
+  vtable->glDeleteTextures (1, &texture);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_egl.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_egl.h
new file mode 100644 (file)
index 0000000..20b553e
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ * gstvaapiutils_egl.h - EGL utilities
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *   Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301
+ */
+
+#ifndef GST_VAAPI_UTILS_EGL_H
+#define GST_VAAPI_UTILS_EGL_H
+
+#include <gmodule.h>
+#include <gst/gstinfo.h>
+#include <gst/video/video-format.h>
+#include "egl_compat.h"
+#include "gstvaapiminiobject.h"
+
+typedef union egl_handle_s                      EglHandle;
+typedef struct egl_object_s                     EglObject;
+typedef struct egl_object_class_s               EglObjectClass;
+typedef struct egl_vtable_s                     EglVTable;
+typedef struct egl_display_s                    EglDisplay;
+typedef struct egl_config_s                     EglConfig;
+typedef struct egl_context_state_s              EglContextState;
+typedef struct egl_context_s                    EglContext;
+typedef struct egl_surface_s                    EglSurface;
+typedef struct egl_program_s                    EglProgram;
+typedef struct egl_window_s                     EglWindow;
+
+#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \
+  typedef TYPE (*GL_PROTO_GEN_CONCAT3(Egl,NAME,Proc))
+#define EGL_PROTO_END()                         ;
+#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \
+  typedef TYPE (*GL_PROTO_GEN_CONCAT3(Gl,NAME,Proc))
+#define GL_PROTO_ARG_LIST(...)                  (__VA_ARGS__)
+#define GL_PROTO_ARG(NAME, TYPE)                TYPE NAME
+#define GL_PROTO_END()                          ;
+#include "egl_vtable.h"
+
+enum {
+  EGL_PLATFORM_UNKNOWN,
+  EGL_PLATFORM_X11,
+  EGL_PLATFORM_WAYLAND,
+};
+
+union egl_handle_s
+{
+  gpointer p;
+  guintptr u;
+  gintptr i;
+};
+
+struct egl_object_s
+{
+  /*< private >*/
+  GstVaapiMiniObject parent_instance;
+
+  EglHandle handle;
+  guint is_wrapped:1;
+  guint is_valid:1;
+};
+
+struct egl_object_class_s
+{
+  /*< private >*/
+  GstVaapiMiniObjectClass parent_class;
+};
+
+struct egl_vtable_s
+{
+  EglObject base;
+
+  gchar **egl_extensions;
+  guint num_egl_symbols;
+  gchar **gl_extensions;
+  guint num_gl_symbols;
+  guint gles_version;
+
+#define EGL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \
+  GL_PROTO_BEGIN_I(NAME, TYPE, EXTENSION, Egl, egl)
+#define GL_PROTO_BEGIN(NAME, TYPE, EXTENSION) \
+  GL_PROTO_BEGIN_I(NAME, TYPE, EXTENSION,  Gl,  gl)
+#define GL_PROTO_BEGIN_I(NAME, TYPE, EXTENSION, Prefix, prefix) \
+  GL_PROTO_GEN_CONCAT3(Prefix,NAME,Proc) GL_PROTO_GEN_CONCAT(prefix,NAME);
+#include "egl_vtable.h"
+
+#define EGL_DEFINE_EXTENSION(EXTENSION) \
+  GL_DEFINE_EXTENSION_I(EXTENSION, EGL)
+#define GL_DEFINE_EXTENSION(EXTENSION) \
+  GL_DEFINE_EXTENSION_I(EXTENSION,  GL)
+#define GL_DEFINE_EXTENSION_I(EXTENSION, PREFIX) \
+  guint GL_PROTO_GEN_CONCAT4(has_,PREFIX,_,EXTENSION);
+#include "egl_vtable.h"
+};
+
+struct egl_display_s
+{
+  EglObject base;
+
+  gchar *gl_vendor_string;
+  gchar *gl_version_string;
+  gchar *gl_apis_string;
+  guint gl_apis;                /* EGL_*_BIT mask */
+  guint gl_platform;
+
+  GMutex mutex;
+  GThread *gl_thread;
+  GCond gl_thread_ready;
+  gboolean gl_thread_cancel;
+  GAsyncQueue *gl_queue;
+  gboolean created;
+};
+
+struct egl_config_s
+{
+  EglObject base;
+
+  EglDisplay *display;
+  guint gl_api;                 /* EGL_*_API value */
+  guint gles_version;
+  gint config_id;
+  gint visual_id;
+};
+
+typedef void (*EglContextRunFunc) (gpointer args);
+
+struct egl_context_state_s
+{
+  EGLDisplay display;
+  EGLContext context;
+  EGLSurface read_surface;
+  EGLSurface draw_surface;
+};
+
+struct egl_context_s
+{
+  EglObject base;
+
+  EglVTable *vtable;
+  EglDisplay *display;
+  EglConfig *config;
+  EglSurface *read_surface;
+  EglSurface *draw_surface;
+};
+
+struct egl_surface_s
+{
+  EglObject base;
+
+  EglDisplay *display;
+};
+
+/* Defined to the maximum number of uniforms for a shader program */
+#define EGL_MAX_UNIFORMS 16
+
+struct egl_program_s
+{
+  EglObject base;
+
+  EglVTable *vtable;
+  guint frag_shader;
+  guint vert_shader;
+  gint uniforms[EGL_MAX_UNIFORMS];
+};
+
+struct egl_window_s
+{
+  EglObject base;
+
+  EglContext *context;
+  EglSurface *surface;
+};
+
+#define egl_object_ref(obj) \
+  ((gpointer)gst_vaapi_mini_object_ref ((GstVaapiMiniObject *)(obj)))
+#define egl_object_unref(obj) \
+  gst_vaapi_mini_object_unref ((GstVaapiMiniObject *)(obj))
+#define egl_object_replace(old_obj_ptr, new_obj) \
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **)(old_obj_ptr), \
+      (GstVaapiMiniObject *)(new_obj))
+
+G_GNUC_INTERNAL
+EglDisplay *
+egl_display_new (gpointer native_display, guint gl_platform);
+
+G_GNUC_INTERNAL
+EglDisplay *
+egl_display_new_wrapped (EGLDisplay gl_display);
+
+G_GNUC_INTERNAL
+EglConfig *
+egl_config_new (EglDisplay * display, guint gles_version,
+    GstVideoFormat format);
+
+G_GNUC_INTERNAL
+EglConfig *
+egl_config_new_with_attribs (EglDisplay * display, const EGLint * attribs);
+
+G_GNUC_INTERNAL
+EglContext *
+egl_context_new (EglDisplay * display, EglConfig * config, EglContext * parent);
+
+G_GNUC_INTERNAL
+EglContext *
+egl_context_new_wrapped (EglDisplay * display, EGLContext gl_context);
+
+G_GNUC_INTERNAL
+EglVTable *
+egl_context_get_vtable (EglContext * ctx, gboolean need_gl_symbols);
+
+G_GNUC_INTERNAL
+gboolean
+egl_context_set_current (EglContext * ctx, gboolean activate,
+    EglContextState * old_cs);
+
+G_GNUC_INTERNAL
+gboolean
+egl_context_run (EglContext * ctx, EglContextRunFunc func, gpointer args);
+
+G_GNUC_INTERNAL
+EglProgram *
+egl_program_new (EglContext * ctx, const gchar * frag_shader_text,
+    const gchar * vert_shader_text);
+
+G_GNUC_INTERNAL
+EglWindow *
+egl_window_new (EglContext * ctx, gpointer native_window);
+
+G_GNUC_INTERNAL
+guint
+egl_create_texture (EglContext * ctx, guint target, guint format,
+    guint width, guint height);
+
+G_GNUC_INTERNAL
+void
+egl_destroy_texture (EglContext * ctx, guint texture);
+
+G_GNUC_INTERNAL
+void
+egl_matrix_set_identity (gfloat m[16]);
+
+#endif /* GST_VAAPI_UTILS_EGL_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_glx.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_glx.c
new file mode 100644 (file)
index 0000000..f73106c
--- /dev/null
@@ -0,0 +1,1273 @@
+/*
+ *  gstvaapiutils_glx.c - GLX utilties
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2012 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE 1           /* RTLD_DEFAULT */
+#include "sysdeps.h"
+#include <math.h>
+#include <dlfcn.h>
+#include "gstvaapiutils_glx.h"
+#include "gstvaapiutils_x11.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+/** Lookup for substring NAME in string EXT using SEP as separators */
+static gboolean
+find_string (const gchar * name, const gchar * ext, const gchar * sep)
+{
+  const gchar *end;
+  int name_len, n;
+
+  if (!name || !ext)
+    return FALSE;
+
+  end = ext + strlen (ext);
+  name_len = strlen (name);
+  while (ext < end) {
+    n = strcspn (ext, sep);
+    if (n == name_len && strncmp (name, ext, n) == 0)
+      return TRUE;
+    ext += (n + 1);
+  }
+  return FALSE;
+}
+
+/**
+ * gl_get_error_string:
+ * @error: an OpenGL error enumeration
+ *
+ * Retrieves the string representation the OpenGL @error.
+ *
+ * Return error: the static string representing the OpenGL @error
+ */
+const gchar *
+gl_get_error_string (GLenum error)
+{
+  switch (error) {
+#define MAP(id, str) \
+        case id: return str " (" #id ")"
+      MAP (GL_NO_ERROR, "no error");
+      MAP (GL_INVALID_ENUM, "invalid enumerant");
+      MAP (GL_INVALID_VALUE, "invalid value");
+      MAP (GL_INVALID_OPERATION, "invalid operation");
+      MAP (GL_STACK_OVERFLOW, "stack overflow");
+      MAP (GL_STACK_UNDERFLOW, "stack underflow");
+      MAP (GL_OUT_OF_MEMORY, "out of memory");
+#ifdef GL_INVALID_FRAMEBUFFER_OPERATION_EXT
+      MAP (GL_INVALID_FRAMEBUFFER_OPERATION_EXT,
+          "invalid framebuffer operation");
+#endif
+#undef MAP
+    default:
+      break;
+  };
+  return "<unknown>";
+}
+
+/**
+ * gl_purge_errors:
+ *
+ * Purges all OpenGL errors. This function is generally useful to
+ * clear up the pending errors prior to calling gl_check_error().
+ */
+void
+gl_purge_errors (void)
+{
+  while (glGetError () != GL_NO_ERROR); /* nothing */
+}
+
+/**
+ * gl_check_error:
+ *
+ * Checks whether there is any OpenGL error pending.
+ *
+ * Return value: %TRUE if an error was encountered
+ */
+gboolean
+gl_check_error (void)
+{
+  GLenum error;
+  gboolean has_errors = FALSE;
+
+  while ((error = glGetError ()) != GL_NO_ERROR) {
+    GST_DEBUG ("glError: %s caught", gl_get_error_string (error));
+    has_errors = TRUE;
+  }
+  return has_errors;
+}
+
+/**
+ * gl_get_param:
+ * @param: the parameter name
+ * @pval: return location for the value
+ *
+ * This function is a wrapper around glGetIntegerv() that does extra
+ * error checking.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_get_param (GLenum param, guint * pval)
+{
+  GLint val;
+
+  gl_purge_errors ();
+  glGetIntegerv (param, &val);
+  if (gl_check_error ())
+    return FALSE;
+
+  if (pval)
+    *pval = val;
+  return TRUE;
+}
+
+/**
+ * gl_get_texture_param:
+ * @target: the target to which the texture is bound
+ * @param: the parameter name
+ * @pval: return location for the value
+ *
+ * This function is a wrapper around glGetTexLevelParameteriv() that
+ * does extra error checking.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_get_texture_param (GLenum target, GLenum param, guint * pval)
+{
+  GLint val;
+
+  gl_purge_errors ();
+  glGetTexLevelParameteriv (target, 0, param, &val);
+  if (gl_check_error ())
+    return FALSE;
+
+  if (pval)
+    *pval = val;
+  return TRUE;
+}
+
+/**
+ * gl_get_texture_binding:
+ * @target: a texture target
+ *
+ * Determines the texture binding type for the specified target.
+ *
+ * Return value: texture binding type for @target
+ */
+static GLenum
+gl_get_texture_binding (GLenum target)
+{
+  GLenum binding;
+
+  switch (target) {
+    case GL_TEXTURE_1D:
+      binding = GL_TEXTURE_BINDING_1D;
+      break;
+    case GL_TEXTURE_2D:
+      binding = GL_TEXTURE_BINDING_2D;
+      break;
+    case GL_TEXTURE_3D:
+      binding = GL_TEXTURE_BINDING_3D;
+      break;
+    case GL_TEXTURE_RECTANGLE_ARB:
+      binding = GL_TEXTURE_BINDING_RECTANGLE_ARB;
+      break;
+    default:
+      binding = 0;
+      break;
+  }
+  return binding;
+}
+
+/**
+ * gl_set_bgcolor:
+ * @color: the requested RGB color
+ *
+ * Sets background color to the RGB @color. This basically is a
+ * wrapper around glClearColor().
+ */
+void
+gl_set_bgcolor (guint32 color)
+{
+  glClearColor (
+      ((color >> 16) & 0xff) / 255.0f,
+      ((color >> 8) & 0xff) / 255.0f, (color & 0xff) / 255.0f, 1.0f);
+}
+
+/**
+ * gl_perspective:
+ * @fovy: the field of view angle, in degrees, in the y direction
+ * @aspect: the aspect ratio that determines the field of view in the
+ *   x direction.  The aspect ratio is the ratio of x (width) to y
+ *   (height)
+ * @zNear: the distance from the viewer to the near clipping plane
+ *   (always positive)
+ * @zFar: the distance from the viewer to the far clipping plane
+ *   (always positive)
+ *
+ * Specified a viewing frustum into the world coordinate system. This
+ * basically is the Mesa implementation of gluPerspective().
+ */
+static void
+gl_perspective (GLdouble fovy, GLdouble aspect, GLdouble near_val,
+    GLdouble far_val)
+{
+  GLdouble left, right, top, bottom;
+
+  /* Source (Q 9.085):
+     <http://www.opengl.org/resources/faq/technical/transformations.htm> */
+  top = tan (fovy * M_PI / 360.0) * near_val;
+  bottom = -top;
+  left = aspect * bottom;
+  right = aspect * top;
+  glFrustum (left, right, bottom, top, near_val, far_val);
+}
+
+/**
+ * gl_resize:
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Resizes the OpenGL viewport to the specified dimensions, using an
+ * orthogonal projection. (0,0) represents the top-left corner of the
+ * window.
+ */
+void
+gl_resize (guint width, guint height)
+{
+#define FOVY     60.0f
+#define ASPECT   1.0f
+#define Z_NEAR   0.1f
+#define Z_FAR    100.0f
+#define Z_CAMERA 0.869f
+
+  glViewport (0, 0, width, height);
+  glMatrixMode (GL_PROJECTION);
+  glLoadIdentity ();
+  gl_perspective (FOVY, ASPECT, Z_NEAR, Z_FAR);
+  glMatrixMode (GL_MODELVIEW);
+  glLoadIdentity ();
+
+  glTranslatef (-0.5f, -0.5f, -Z_CAMERA);
+  glScalef (1.0f / width, -1.0f / height, 1.0f / width);
+  glTranslatef (0.0f, -1.0f * height, 0.0f);
+}
+
+/**
+ * gl_create_context:
+ * @dpy: an X11 #Display
+ * @screen: the associated screen of @dpy
+ * @parent: the parent #GLContextState, or %NULL if none is to be used
+ *
+ * Creates a GLX context sharing textures and displays lists with
+ * @parent, if not %NULL.
+ *
+ * Return value: the newly created GLX context
+ */
+GLContextState *
+gl_create_context (Display * dpy, int screen, GLContextState * parent)
+{
+  GLContextState *cs;
+  GLXFBConfig *fbconfigs = NULL;
+  int fbconfig_id, val, n, n_fbconfigs;
+  Status status;
+
+  static GLint fbconfig_attrs[] = {
+    GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT,
+    GLX_RENDER_TYPE, GLX_RGBA_BIT,
+    GLX_DOUBLEBUFFER, True,
+    GLX_RED_SIZE, 8,
+    GLX_GREEN_SIZE, 8,
+    GLX_BLUE_SIZE, 8,
+    GLX_ALPHA_SIZE, 8,
+    None
+  };
+
+  const GLint rgba_colors[4] = {
+    GLX_RED_SIZE,
+    GLX_GREEN_SIZE,
+    GLX_BLUE_SIZE,
+    GLX_ALPHA_SIZE
+  };
+
+  cs = malloc (sizeof (*cs));
+  if (!cs)
+    goto error;
+
+  if (parent) {
+    cs->display = parent->display;
+    cs->window = parent->window;
+    screen = DefaultScreen (parent->display);
+  } else {
+    cs->display = dpy;
+    cs->window = None;
+  }
+  cs->visual = NULL;
+  cs->context = NULL;
+  cs->swapped_buffers = FALSE;
+
+  if (parent && parent->context) {
+    status = glXQueryContext (parent->display,
+        parent->context, GLX_FBCONFIG_ID, &fbconfig_id);
+    if (status != Success)
+      goto error;
+
+    if (fbconfig_id == GLX_DONT_CARE)
+      goto choose_fbconfig;
+
+    fbconfigs = glXGetFBConfigs (parent->display, screen, &n_fbconfigs);
+    if (!fbconfigs)
+      goto error;
+
+    /* Find out a 8 bit GLXFBConfig compatible with the parent context */
+    for (n = 0; n < n_fbconfigs; n++) {
+      gboolean sizes_correct = FALSE;
+      int cn;
+
+      status = glXGetFBConfigAttrib (parent->display,
+          fbconfigs[n], GLX_FBCONFIG_ID, &val);
+      if (status != Success)
+        goto error;
+      if (val != fbconfig_id)
+        continue;
+
+      /* Iterate over RGBA sizes in fbconfig */
+      for (cn = 0; cn < 4; cn++) {
+        int size = 0;
+
+        status = glXGetFBConfigAttrib (parent->display,
+            fbconfigs[n], rgba_colors[cn], &size);
+        if (status != Success)
+          goto error;
+
+        /* Last check is for alpha
+         * and alpha is optional */
+        if (cn == 3) {
+          if (size == 0 || size == 8) {
+            sizes_correct = TRUE;
+            break;
+          }
+        } else if (size != 8)
+          break;
+      }
+      if (sizes_correct)
+        break;
+    }
+    if (n == n_fbconfigs)
+      goto error;
+  } else {
+  choose_fbconfig:
+    fbconfigs = glXChooseFBConfig (cs->display,
+        screen, fbconfig_attrs, &n_fbconfigs);
+    if (!fbconfigs)
+      goto error;
+
+    /* Select the first one */
+    n = 0;
+  }
+
+  cs->visual = glXGetVisualFromFBConfig (cs->display, fbconfigs[n]);
+  cs->context = glXCreateNewContext (cs->display,
+      fbconfigs[n], GLX_RGBA_TYPE, parent ? parent->context : NULL, True);
+  if (!cs->context)
+    goto error;
+
+end:
+  if (fbconfigs)
+    XFree (fbconfigs);
+  return cs;
+
+  /* ERRORS */
+error:
+  {
+    gl_destroy_context (cs);
+    cs = NULL;
+    goto end;
+  }
+}
+
+/**
+ * gl_destroy_context:
+ * @cs: a #GLContextState
+ *
+ * Destroys the GLX context @cs
+ */
+void
+gl_destroy_context (GLContextState * cs)
+{
+  if (!cs)
+    return;
+
+  if (cs->visual) {
+    XFree (cs->visual);
+    cs->visual = NULL;
+  }
+
+  if (cs->display && cs->context) {
+    if (glXGetCurrentContext () == cs->context) {
+      /* XXX: if buffers were never swapped, the application
+         will crash later with the NVIDIA driver */
+      if (!cs->swapped_buffers)
+        gl_swap_buffers (cs);
+      glXMakeCurrent (cs->display, None, NULL);
+    }
+    glXDestroyContext (cs->display, cs->context);
+    cs->display = NULL;
+    cs->context = NULL;
+  }
+  free (cs);
+}
+
+/**
+ * gl_get_current_context:
+ * @cs: return location to the current #GLContextState
+ *
+ * Retrieves the current GLX context, display and drawable packed into
+ * the #GLContextState struct.
+ */
+void
+gl_get_current_context (GLContextState * cs)
+{
+  cs->display = glXGetCurrentDisplay ();
+  cs->window = glXGetCurrentDrawable ();
+  cs->context = glXGetCurrentContext ();
+}
+
+/**
+ * gl_set_current_context:
+ * @new_cs: the requested new #GLContextState
+ * @old_cs: return location to the context that was previously current
+ *
+ * Makes the @new_cs GLX context the current GLX rendering context of
+ * the calling thread, replacing the previously current context if
+ * there was one.
+ *
+ * If @old_cs is non %NULL, the previously current GLX context and
+ * window are recorded.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_set_current_context (GLContextState * new_cs, GLContextState * old_cs)
+{
+  /* If display is NULL, this could be that new_cs was retrieved from
+     gl_get_current_context() with none set previously. If that case,
+     the other fields are also NULL and we don't return an error */
+  if (!new_cs->display)
+    return !new_cs->window && !new_cs->context;
+
+  if (old_cs) {
+    if (old_cs == new_cs)
+      return TRUE;
+    gl_get_current_context (old_cs);
+    if (old_cs->display == new_cs->display &&
+        old_cs->window == new_cs->window && old_cs->context == new_cs->context)
+      return TRUE;
+  }
+  return glXMakeCurrent (new_cs->display, new_cs->window, new_cs->context);
+}
+
+/**
+ * gl_swap_buffers:
+ * @cs: a #GLContextState
+ *
+ * Promotes the contents of the back buffer of the @win window to
+ * become the contents of the front buffer. This simply is wrapper
+ * around glXSwapBuffers().
+ */
+void
+gl_swap_buffers (GLContextState * cs)
+{
+  glXSwapBuffers (cs->display, cs->window);
+  cs->swapped_buffers = TRUE;
+}
+
+static inline gboolean
+_init_texture_state (GLTextureState * ts, GLenum target, GLuint texture,
+    gboolean enabled)
+{
+  GLenum binding;
+
+  ts->target = target;
+
+  if (enabled) {
+    binding = gl_get_texture_binding (target);
+    if (!binding)
+      return FALSE;
+    if (!gl_get_param (binding, &ts->old_texture))
+      return FALSE;
+    ts->was_enabled = TRUE;
+    ts->was_bound = texture == ts->old_texture;
+  } else {
+    ts->old_texture = 0;
+    ts->was_enabled = FALSE;
+    ts->was_bound = FALSE;
+  }
+
+  return TRUE;
+}
+
+static inline gboolean
+_bind_enabled_texture (GLenum target, GLuint texture)
+{
+  gl_purge_errors ();
+  glBindTexture (target, texture);
+  if (gl_check_error ())
+    return FALSE;
+  return TRUE;
+}
+
+/**
+ * gl_bind_texture:
+ * @ts: a #GLTextureState
+ * @target: the target to which the texture is bound
+ * @texture: the name of a texture
+ *
+ * Binds @texture to the specified @target, while recording the
+ * previous state in @ts.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_bind_texture (GLTextureState * ts, GLenum target, GLuint texture)
+{
+  gboolean enabled;
+
+  enabled = (gboolean) glIsEnabled (target);
+  if (!_init_texture_state (ts, target, texture, enabled))
+    return FALSE;
+  if (ts->was_bound)
+    return TRUE;
+  if (!enabled)
+    glEnable (target);
+
+  return _bind_enabled_texture (target, texture);
+}
+
+/**
+ * gl3_bind_texture_2d:
+ * @ts: a #GLTextureState
+ * @target: the target to which the texture is bound
+ * @texture: the name of a texture
+ *
+ * Binds @texture to the specified @target, while recording the
+ * previous state in @ts.
+ *
+ * This function is for OpenGL3 API and for targets type GL_TEXTURE_2D.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl3_bind_texture_2d (GLTextureState * ts, GLenum target, GLuint texture)
+{
+  if (target != GL_TEXTURE_2D)
+    return FALSE;
+
+  if (!_init_texture_state (ts, target, texture, TRUE))
+    return FALSE;
+  if (ts->was_bound)
+    return TRUE;
+
+  return _bind_enabled_texture (target, texture);
+}
+
+/**
+ * gl_unbind_texture:
+ * @ts: a #GLTextureState
+ *
+ * Rebinds the texture that was previously bound and recorded in @ts.
+ */
+void
+gl_unbind_texture (GLTextureState * ts)
+{
+  if (!ts->was_bound && ts->old_texture)
+    glBindTexture (ts->target, ts->old_texture);
+  if (!ts->was_enabled)
+    glDisable (ts->target);
+}
+
+/**
+ * gl_create_texture:
+ * @target: the target to which the texture is bound
+ * @format: the format of the pixel data
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates a texture with the specified dimensions and @format. The
+ * internal format will be automatically derived from @format.
+ *
+ * Return value: the newly created texture name
+ */
+GLuint
+gl_create_texture (GLenum target, GLenum format, guint width, guint height)
+{
+  GLenum internal_format;
+  GLuint texture;
+  GLTextureState ts;
+  guint bytes_per_component;
+
+  internal_format = format;
+  switch (format) {
+    case GL_LUMINANCE:
+      bytes_per_component = 1;
+      break;
+    case GL_LUMINANCE_ALPHA:
+      bytes_per_component = 2;
+      break;
+    case GL_RGBA:
+    case GL_BGRA:
+      internal_format = GL_RGBA;
+      bytes_per_component = 4;
+      break;
+    default:
+      bytes_per_component = 0;
+      break;
+  }
+  g_assert (bytes_per_component > 0);
+
+  glGenTextures (1, &texture);
+  if (!gl_bind_texture (&ts, target, texture))
+    return 0;
+  glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+  glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+  glPixelStorei (GL_UNPACK_ALIGNMENT, bytes_per_component);
+  glTexImage2D (target,
+      0, internal_format, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
+  gl_unbind_texture (&ts);
+  return texture;
+}
+
+/**
+ * get_proc_address:
+ * @name: the name of the OpenGL extension function to lookup
+ *
+ * Returns the specified OpenGL extension function
+ *
+ * Return value: the OpenGL extension matching @name, or %NULL if none
+ *   was found
+ */
+typedef void (*GLFuncPtr) (void);
+typedef GLFuncPtr (*GLXGetProcAddressProc) (const gchar *);
+
+static GLFuncPtr
+get_proc_address_default (const gchar * name)
+{
+  return NULL;
+}
+
+static GLXGetProcAddressProc
+get_proc_address_func (void)
+{
+  GLXGetProcAddressProc get_proc_func;
+
+  dlerror ();
+  *(void **) (&get_proc_func) = dlsym (RTLD_DEFAULT, "glXGetProcAddress");
+  if (!dlerror ())
+    return get_proc_func;
+
+  *(void **) (&get_proc_func) = dlsym (RTLD_DEFAULT, "glXGetProcAddressARB");
+  if (!dlerror ())
+    return get_proc_func;
+
+  return get_proc_address_default;
+}
+
+static inline GLFuncPtr
+get_proc_address (const gchar * name)
+{
+  static GLXGetProcAddressProc get_proc_func = NULL;
+  if (!get_proc_func)
+    get_proc_func = get_proc_address_func ();
+  return get_proc_func (name);
+}
+
+/**
+ * gl_init_vtable:
+ *
+ * Initializes the global #GLVTable.
+ *
+ * Return value: the #GLVTable filled in with OpenGL extensions, or
+ *   %NULL on error.
+ */
+static GLVTable gl_vtable_static;
+
+static GLVTable *
+gl_init_vtable (void)
+{
+  GLVTable *const gl_vtable = &gl_vtable_static;
+  const gchar *gl_extensions = (const gchar *) glGetString (GL_EXTENSIONS);
+  gboolean has_extension;
+
+  /* GLX_EXT_texture_from_pixmap */
+  gl_vtable->glx_create_pixmap = (PFNGLXCREATEPIXMAPPROC)
+      get_proc_address ("glXCreatePixmap");
+  if (!gl_vtable->glx_create_pixmap)
+    return NULL;
+  gl_vtable->glx_destroy_pixmap = (PFNGLXDESTROYPIXMAPPROC)
+      get_proc_address ("glXDestroyPixmap");
+  if (!gl_vtable->glx_destroy_pixmap)
+    return NULL;
+  gl_vtable->glx_bind_tex_image = (PFNGLXBINDTEXIMAGEEXTPROC)
+      get_proc_address ("glXBindTexImageEXT");
+  if (!gl_vtable->glx_bind_tex_image)
+    return NULL;
+  gl_vtable->glx_release_tex_image = (PFNGLXRELEASETEXIMAGEEXTPROC)
+      get_proc_address ("glXReleaseTexImageEXT");
+  if (!gl_vtable->glx_release_tex_image)
+    return NULL;
+
+  /* GL_ARB_framebuffer_object */
+  has_extension = (find_string ("GL_ARB_framebuffer_object", gl_extensions, " ")
+      || find_string ("GL_EXT_framebuffer_object", gl_extensions, " ")
+      );
+  if (has_extension) {
+    gl_vtable->gl_gen_framebuffers = (PFNGLGENFRAMEBUFFERSEXTPROC)
+        get_proc_address ("glGenFramebuffersEXT");
+    if (!gl_vtable->gl_gen_framebuffers)
+      return NULL;
+    gl_vtable->gl_delete_framebuffers = (PFNGLDELETEFRAMEBUFFERSEXTPROC)
+        get_proc_address ("glDeleteFramebuffersEXT");
+    if (!gl_vtable->gl_delete_framebuffers)
+      return NULL;
+    gl_vtable->gl_bind_framebuffer = (PFNGLBINDFRAMEBUFFEREXTPROC)
+        get_proc_address ("glBindFramebufferEXT");
+    if (!gl_vtable->gl_bind_framebuffer)
+      return NULL;
+    gl_vtable->gl_gen_renderbuffers = (PFNGLGENRENDERBUFFERSEXTPROC)
+        get_proc_address ("glGenRenderbuffersEXT");
+    if (!gl_vtable->gl_gen_renderbuffers)
+      return NULL;
+    gl_vtable->gl_delete_renderbuffers = (PFNGLDELETERENDERBUFFERSEXTPROC)
+        get_proc_address ("glDeleteRenderbuffersEXT");
+    if (!gl_vtable->gl_delete_renderbuffers)
+      return NULL;
+    gl_vtable->gl_bind_renderbuffer = (PFNGLBINDRENDERBUFFEREXTPROC)
+        get_proc_address ("glBindRenderbufferEXT");
+    if (!gl_vtable->gl_bind_renderbuffer)
+      return NULL;
+    gl_vtable->gl_renderbuffer_storage = (PFNGLRENDERBUFFERSTORAGEEXTPROC)
+        get_proc_address ("glRenderbufferStorageEXT");
+    if (!gl_vtable->gl_renderbuffer_storage)
+      return NULL;
+    gl_vtable->gl_framebuffer_renderbuffer =
+        (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)
+        get_proc_address ("glFramebufferRenderbufferEXT");
+    if (!gl_vtable->gl_framebuffer_renderbuffer)
+      return NULL;
+    gl_vtable->gl_framebuffer_texture_2d = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)
+        get_proc_address ("glFramebufferTexture2DEXT");
+    if (!gl_vtable->gl_framebuffer_texture_2d)
+      return NULL;
+    gl_vtable->gl_check_framebuffer_status =
+        (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)
+        get_proc_address ("glCheckFramebufferStatusEXT");
+    if (!gl_vtable->gl_check_framebuffer_status)
+      return NULL;
+    gl_vtable->has_framebuffer_object = TRUE;
+  }
+  return gl_vtable;
+}
+
+/**
+ * gl_get_vtable:
+ *
+ * Retrieves a VTable for OpenGL extensions.
+ *
+ * Return value: VTable for OpenGL extensions
+ */
+GLVTable *
+gl_get_vtable (void)
+{
+  static gsize gl_vtable_init = FALSE;
+  static GLVTable *gl_vtable = NULL;
+
+  if (g_once_init_enter (&gl_vtable_init)) {
+    gl_vtable = gl_init_vtable ();
+    g_once_init_leave (&gl_vtable_init, TRUE);
+  }
+  return gl_vtable;
+}
+
+/**
+ * gl_create_pixmap_object:
+ * @dpy: an X11 #Display
+ * @width: the request width, in pixels
+ * @height: the request height, in pixels
+ *
+ * Creates a #GLPixmapObject of the specified dimensions. This
+ * requires the GLX_EXT_texture_from_pixmap extension.
+ *
+ * Return value: the newly created #GLPixmapObject object
+ */
+GLPixmapObject *
+gl_create_pixmap_object (Display * dpy, guint width, guint height)
+{
+  GLVTable *const gl_vtable = gl_get_vtable ();
+  GLPixmapObject *pixo;
+  GLXFBConfig *fbconfig;
+  int screen;
+  Window rootwin;
+  XWindowAttributes wattr;
+  int *attr;
+  int n_fbconfig_attrs;
+
+  int fbconfig_attrs[32] = {
+    GLX_DRAWABLE_TYPE, GLX_PIXMAP_BIT,
+    GLX_DOUBLEBUFFER, GL_FALSE,
+    GLX_RENDER_TYPE, GLX_RGBA_BIT,
+    GLX_X_RENDERABLE, GL_TRUE,
+    GLX_Y_INVERTED_EXT, GL_TRUE,
+    GLX_RED_SIZE, 8,
+    GLX_GREEN_SIZE, 8,
+    GLX_BLUE_SIZE, 8,
+    GLX_ALPHA_SIZE, 8,
+    GL_NONE,
+  };
+
+  int pixmap_attrs[10] = {
+    GLX_TEXTURE_TARGET_EXT, GLX_TEXTURE_2D_EXT,
+    GLX_MIPMAP_TEXTURE_EXT, GL_FALSE,
+    GL_NONE,
+  };
+
+  if (!gl_vtable)
+    return NULL;
+
+  screen = DefaultScreen (dpy);
+  rootwin = RootWindow (dpy, screen);
+
+  /* XXX: this won't work for different displays */
+  if (!gl_vtable->has_texture_from_pixmap) {
+    const gchar *glx_extensions = glXQueryExtensionsString (dpy, screen);
+    if (!glx_extensions)
+      return NULL;
+    if (!find_string ("GLX_EXT_texture_from_pixmap", glx_extensions, " "))
+      return NULL;
+    gl_vtable->has_texture_from_pixmap = TRUE;
+  }
+
+  pixo = calloc (1, sizeof (*pixo));
+  if (!pixo)
+    return NULL;
+
+  pixo->dpy = dpy;
+  pixo->width = width;
+  pixo->height = height;
+  pixo->pixmap = None;
+  pixo->glx_pixmap = None;
+  pixo->is_bound = FALSE;
+
+  XGetWindowAttributes (dpy, rootwin, &wattr);
+  pixo->pixmap = XCreatePixmap (dpy, rootwin, width, height, wattr.depth);
+  if (!pixo->pixmap)
+    goto error;
+
+  /* Initialize FBConfig attributes */
+  for (attr = fbconfig_attrs; *attr != GL_NONE; attr += 2);
+  if (wattr.depth == 32) {
+    *attr++ = GLX_ALPHA_SIZE;
+    *attr++ = 8;
+    *attr++ = GLX_BIND_TO_TEXTURE_RGBA_EXT;
+    *attr++ = GL_TRUE;
+  } else {
+    *attr++ = GLX_BIND_TO_TEXTURE_RGB_EXT;
+    *attr++ = GL_TRUE;
+  }
+  *attr++ = GL_NONE;
+
+  fbconfig = glXChooseFBConfig (dpy, screen, fbconfig_attrs, &n_fbconfig_attrs);
+  if (!fbconfig)
+    goto error;
+
+  /* Initialize GLX Pixmap attributes */
+  for (attr = pixmap_attrs; *attr != GL_NONE; attr += 2);
+  *attr++ = GLX_TEXTURE_FORMAT_EXT;
+  if (wattr.depth == 32)
+    *attr++ = GLX_TEXTURE_FORMAT_RGBA_EXT;
+  else
+    *attr++ = GLX_TEXTURE_FORMAT_RGB_EXT;
+  *attr++ = GL_NONE;
+
+  x11_trap_errors ();
+  pixo->glx_pixmap = gl_vtable->glx_create_pixmap (dpy,
+      fbconfig[0], pixo->pixmap, pixmap_attrs);
+  free (fbconfig);
+  if (x11_untrap_errors () != 0)
+    goto error;
+
+  pixo->target = GL_TEXTURE_2D;
+  glGenTextures (1, &pixo->texture);
+  if (!gl_bind_texture (&pixo->old_texture, pixo->target, pixo->texture))
+    goto error;
+  glTexParameteri (pixo->target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+  glTexParameteri (pixo->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+  gl_unbind_texture (&pixo->old_texture);
+  return pixo;
+
+  /* ERRORS */
+error:
+  {
+    gl_destroy_pixmap_object (pixo);
+    return NULL;
+  }
+}
+
+/**
+ * gl_destroy_pixmap_object:
+ * @pixo: a #GLPixmapObject
+ *
+ * Destroys the #GLPixmapObject object.
+ */
+void
+gl_destroy_pixmap_object (GLPixmapObject * pixo)
+{
+  GLVTable *const gl_vtable = gl_get_vtable ();
+
+  if (!pixo)
+    return;
+
+  gl_unbind_pixmap_object (pixo);
+
+  if (pixo->texture) {
+    glDeleteTextures (1, &pixo->texture);
+    pixo->texture = 0;
+  }
+
+  if (pixo->glx_pixmap) {
+    gl_vtable->glx_destroy_pixmap (pixo->dpy, pixo->glx_pixmap);
+    pixo->glx_pixmap = None;
+  }
+
+  if (pixo->pixmap) {
+    XFreePixmap (pixo->dpy, pixo->pixmap);
+    pixo->pixmap = None;
+  }
+  free (pixo);
+}
+
+/**
+ * gl_bind_pixmap_object:
+ * @pixo: a #GLPixmapObject
+ *
+ * Defines a two-dimensional texture image. The texture image is taken
+ * from the @pixo pixmap and need not be copied. The texture target,
+ * format and size are derived from attributes of the @pixo pixmap.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_bind_pixmap_object (GLPixmapObject * pixo)
+{
+  GLVTable *const gl_vtable = gl_get_vtable ();
+
+  if (pixo->is_bound)
+    return TRUE;
+
+  if (!gl_bind_texture (&pixo->old_texture, pixo->target, pixo->texture))
+    return FALSE;
+
+  x11_trap_errors ();
+  gl_vtable->glx_bind_tex_image (pixo->dpy,
+      pixo->glx_pixmap, GLX_FRONT_LEFT_EXT, NULL);
+  XSync (pixo->dpy, False);
+  if (x11_untrap_errors () != 0) {
+    GST_DEBUG ("failed to bind pixmap");
+    return FALSE;
+  }
+
+  pixo->is_bound = TRUE;
+  return TRUE;
+}
+
+/**
+ * gl_unbind_pixmap_object:
+ * @pixo: a #GLPixmapObject
+ *
+ * Releases a color buffers that is being used as a texture.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_unbind_pixmap_object (GLPixmapObject * pixo)
+{
+  GLVTable *const gl_vtable = gl_get_vtable ();
+
+  if (!pixo->is_bound)
+    return TRUE;
+
+  x11_trap_errors ();
+  gl_vtable->glx_release_tex_image (pixo->dpy,
+      pixo->glx_pixmap, GLX_FRONT_LEFT_EXT);
+  XSync (pixo->dpy, False);
+  if (x11_untrap_errors () != 0) {
+    GST_DEBUG ("failed to release pixmap");
+    return FALSE;
+  }
+
+  gl_unbind_texture (&pixo->old_texture);
+
+  pixo->is_bound = FALSE;
+  return TRUE;
+}
+
+/**
+ * gl_create_framebuffer_object:
+ * @target: the target to which the texture is bound
+ * @texture: the GL texture to hold the framebuffer
+ * @width: the requested width, in pixels
+ * @height: the requested height, in pixels
+ *
+ * Creates an FBO with the specified texture and size.
+ *
+ * Return value: the newly created #GLFramebufferObject, or %NULL if
+ *   an error occurred
+ */
+GLFramebufferObject *
+gl_create_framebuffer_object (GLenum target,
+    GLuint texture, guint width, guint height)
+{
+  GLVTable *const gl_vtable = gl_get_vtable ();
+  GLFramebufferObject *fbo;
+  GLenum status;
+
+  if (!gl_vtable || !gl_vtable->has_framebuffer_object)
+    return NULL;
+
+  /* XXX: we only support GL_TEXTURE_2D at this time */
+  if (target != GL_TEXTURE_2D)
+    return NULL;
+
+  fbo = calloc (1, sizeof (*fbo));
+  if (!fbo)
+    return NULL;
+
+  fbo->width = width;
+  fbo->height = height;
+  fbo->fbo = 0;
+  fbo->old_fbo = 0;
+  fbo->is_bound = FALSE;
+
+  gl_get_param (GL_FRAMEBUFFER_BINDING, &fbo->old_fbo);
+  gl_vtable->gl_gen_framebuffers (1, &fbo->fbo);
+  gl_vtable->gl_bind_framebuffer (GL_FRAMEBUFFER_EXT, fbo->fbo);
+  gl_vtable->gl_framebuffer_texture_2d (GL_FRAMEBUFFER_EXT,
+      GL_COLOR_ATTACHMENT0_EXT, target, texture, 0);
+
+  status = gl_vtable->gl_check_framebuffer_status (GL_DRAW_FRAMEBUFFER_EXT);
+  gl_vtable->gl_bind_framebuffer (GL_FRAMEBUFFER_EXT, fbo->old_fbo);
+  if (status != GL_FRAMEBUFFER_COMPLETE_EXT)
+    goto error;
+  return fbo;
+
+  /* ERRORS */
+error:
+  {
+    gl_destroy_framebuffer_object (fbo);
+    return NULL;
+  }
+}
+
+/**
+ * gl_destroy_framebuffer_object:
+ * @fbo: a #GLFramebufferObject
+ *
+ * Destroys the @fbo object.
+ */
+void
+gl_destroy_framebuffer_object (GLFramebufferObject * fbo)
+{
+  GLVTable *const gl_vtable = gl_get_vtable ();
+
+  if (!fbo)
+    return;
+
+  gl_unbind_framebuffer_object (fbo);
+
+  if (fbo->fbo) {
+    gl_vtable->gl_delete_framebuffers (1, &fbo->fbo);
+    fbo->fbo = 0;
+  }
+  free (fbo);
+}
+
+/**
+ * gl_bind_framebuffer_object:
+ * @fbo: a #GLFramebufferObject
+ *
+ * Binds @fbo object.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_bind_framebuffer_object (GLFramebufferObject * fbo)
+{
+  GLVTable *const gl_vtable = gl_get_vtable ();
+  const guint width = fbo->width;
+  const guint height = fbo->height;
+
+  const guint attribs = (GL_VIEWPORT_BIT |
+      GL_CURRENT_BIT | GL_ENABLE_BIT | GL_TEXTURE_BIT | GL_COLOR_BUFFER_BIT);
+
+  if (fbo->is_bound)
+    return TRUE;
+
+  gl_get_param (GL_FRAMEBUFFER_BINDING, &fbo->old_fbo);
+  gl_vtable->gl_bind_framebuffer (GL_FRAMEBUFFER_EXT, fbo->fbo);
+  glPushAttrib (attribs);
+  glMatrixMode (GL_PROJECTION);
+  glPushMatrix ();
+  glLoadIdentity ();
+  glMatrixMode (GL_MODELVIEW);
+  glPushMatrix ();
+  glLoadIdentity ();
+  glViewport (0, 0, width, height);
+  glTranslatef (-1.0f, -1.0f, 0.0f);
+  glScalef (2.0f / width, 2.0f / height, 1.0f);
+
+  fbo->is_bound = TRUE;
+  return TRUE;
+}
+
+/**
+ * gl_unbind_framebuffer_object:
+ * @fbo: a #GLFramebufferObject
+ *
+ * Releases @fbo object.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gl_unbind_framebuffer_object (GLFramebufferObject * fbo)
+{
+  GLVTable *const gl_vtable = gl_get_vtable ();
+
+  if (!fbo->is_bound)
+    return TRUE;
+
+  glPopAttrib ();
+  glMatrixMode (GL_PROJECTION);
+  glPopMatrix ();
+  glMatrixMode (GL_MODELVIEW);
+  glPopMatrix ();
+  gl_vtable->gl_bind_framebuffer (GL_FRAMEBUFFER_EXT, fbo->old_fbo);
+
+  fbo->is_bound = FALSE;
+  return TRUE;
+}
+
+/**
+ * gl_get_current_api:
+ * @major: (out): (allow-none): the GL major version
+ * @minor: (out): (allow-none): the GL minor version
+ *
+ * If an error occurs, @major and @minor aren't modified and
+ * %GST_VAAPI_GL_API_NONE is returned.
+ *
+ * This is an adaptation of gst_gl_context_get_current_gl_api() from GstGL.
+ *
+ * Returns: The version supported by the OpenGL context current in the calling
+ *          thread or %GST_VAAPI_GL_API_NONE
+ */
+GstVaapiGLApi
+gl_get_current_api (guint * major, guint * minor)
+{
+  const gchar *version;
+  gint maj, min, n, sret;
+  GstVaapiGLApi ret = (1 << 31);
+
+  while (ret != GST_VAAPI_GL_API_NONE) {
+    version = (const gchar *) glGetString (GL_VERSION);
+    if (!version)
+      goto next;
+
+    /* strlen (x.x) == 3 */
+    n = strlen (version);
+    if (n < 3)
+      goto next;
+
+    if (g_strstr_len (version, 9, "OpenGL ES")) {
+      /* strlen (OpenGL ES x.x) == 13 */
+      if (n < 13)
+        goto next;
+
+      sret = sscanf (&version[10], "%d.%d", &maj, &min);
+      if (sret != 2)
+        goto next;
+
+      if (maj <= 0 || min < 0)
+        goto next;
+
+      if (maj == 1) {
+        ret = GST_VAAPI_GL_API_GLES1;
+        break;
+      } else if (maj == 2 || maj == 3) {
+        ret = GST_VAAPI_GL_API_GLES2;
+        break;
+      }
+
+      goto next;
+    } else {
+      sret = sscanf (version, "%d.%d", &maj, &min);
+      if (sret != 2)
+        goto next;
+
+      if (maj <= 0 || min < 0)
+        goto next;
+
+      if (maj > 3 || (maj == 3 && min > 1)) {
+        GLuint context_flags = 0;
+
+        ret = GST_VAAPI_GL_API_NONE;
+        if (!gl_get_param (GL_CONTEXT_PROFILE_MASK, &context_flags))
+          break;
+
+        if (context_flags & GL_CONTEXT_CORE_PROFILE_BIT)
+          ret |= GST_VAAPI_GL_API_OPENGL3;
+        if (context_flags & GL_CONTEXT_COMPATIBILITY_PROFILE_BIT)
+          ret |= GST_VAAPI_GL_API_OPENGL;
+        break;
+      }
+
+      ret = GST_VAAPI_GL_API_OPENGL;
+      break;
+    }
+
+  next:
+    /* iterate through the apis */
+    ret >>= 1;
+  }
+
+  if (ret == GST_VAAPI_GL_API_NONE)
+    return GST_VAAPI_GL_API_NONE;
+
+  if (major)
+    *major = maj;
+  if (minor)
+    *minor = min;
+
+  return ret;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_glx.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_glx.h
new file mode 100644 (file)
index 0000000..f5c632c
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  gstvaapiutils_glx.h - GLX utilties
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_GLX_H
+#define GST_VAAPI_UTILS_GLX_H
+
+#include "config.h"
+#include <GL/gl.h>
+#include <GL/glx.h>
+#include <glib.h>
+
+#if GLX_GLXEXT_VERSION < 18
+typedef void (*PFNGLXBINDTEXIMAGEEXTPROC) (Display *, GLXDrawable, int,
+    const int *);
+typedef void (*PFNGLXRELEASETEXIMAGEEXTPROC) (Display *, GLXDrawable, int);
+#endif
+
+#if GLX_GLXEXT_VERSION < 27
+/* XXX: this is not exactly that version but this is the only means to
+   make sure we have the correct <GL/glx.h> with those signatures */
+typedef GLXPixmap (*PFNGLXCREATEPIXMAPPROC) (Display *, GLXFBConfig, Pixmap,
+    const int *);
+typedef void (*PFNGLXDESTROYPIXMAPPROC) (Display *, GLXPixmap);
+#endif
+
+#ifndef GL_FRAMEBUFFER_BINDING
+#define GL_FRAMEBUFFER_BINDING GL_FRAMEBUFFER_BINDING_EXT
+#endif
+
+G_GNUC_INTERNAL
+const gchar *
+gl_get_error_string (GLenum error);
+
+G_GNUC_INTERNAL
+void
+gl_purge_errors (void);
+
+G_GNUC_INTERNAL
+gboolean
+gl_check_error (void);
+
+G_GNUC_INTERNAL
+gboolean
+gl_get_param (GLenum param, guint * pval);
+
+G_GNUC_INTERNAL
+gboolean
+gl_get_texture_param (GLenum target, GLenum param, guint * pval);
+
+G_GNUC_INTERNAL
+void
+gl_set_bgcolor (guint32 color);
+
+G_GNUC_INTERNAL
+void
+gl_resize (guint width, guint height);
+
+typedef struct _GLContextState GLContextState;
+struct _GLContextState
+{
+  Display *display;
+  Window window;
+  XVisualInfo *visual;
+  GLXContext context;
+  guint swapped_buffers:1;
+};
+
+G_GNUC_INTERNAL
+GLContextState *
+gl_create_context (Display * dpy, int screen, GLContextState * parent);
+
+G_GNUC_INTERNAL
+void
+gl_destroy_context (GLContextState * cs);
+
+G_GNUC_INTERNAL
+void
+gl_get_current_context (GLContextState * cs);
+
+G_GNUC_INTERNAL
+gboolean
+gl_set_current_context (GLContextState * new_cs, GLContextState * old_cs);
+
+G_GNUC_INTERNAL
+void
+gl_swap_buffers (GLContextState * cs);
+
+typedef struct _GLTextureState GLTextureState;
+struct _GLTextureState
+{
+  GLenum target;
+  GLuint old_texture;
+  guint was_enabled:1;
+  guint was_bound:1;
+};
+
+G_GNUC_INTERNAL
+gboolean
+gl_bind_texture (GLTextureState * ts, GLenum target, GLuint texture);
+
+G_GNUC_INTERNAL
+gboolean
+gl3_bind_texture_2d (GLTextureState * ts, GLenum target, GLuint texture);
+
+G_GNUC_INTERNAL
+void
+gl_unbind_texture (GLTextureState * ts);
+
+G_GNUC_INTERNAL
+GLuint
+gl_create_texture (GLenum target, GLenum format, guint width, guint height);
+
+typedef struct _GLVTable GLVTable;
+struct _GLVTable
+{
+  PFNGLXCREATEPIXMAPPROC glx_create_pixmap;
+  PFNGLXDESTROYPIXMAPPROC glx_destroy_pixmap;
+  PFNGLXBINDTEXIMAGEEXTPROC glx_bind_tex_image;
+  PFNGLXRELEASETEXIMAGEEXTPROC glx_release_tex_image;
+  PFNGLGENFRAMEBUFFERSEXTPROC gl_gen_framebuffers;
+  PFNGLDELETEFRAMEBUFFERSEXTPROC gl_delete_framebuffers;
+  PFNGLBINDFRAMEBUFFEREXTPROC gl_bind_framebuffer;
+  PFNGLGENRENDERBUFFERSEXTPROC gl_gen_renderbuffers;
+  PFNGLDELETERENDERBUFFERSEXTPROC gl_delete_renderbuffers;
+  PFNGLBINDRENDERBUFFEREXTPROC gl_bind_renderbuffer;
+  PFNGLRENDERBUFFERSTORAGEEXTPROC gl_renderbuffer_storage;
+  PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC gl_framebuffer_renderbuffer;
+  PFNGLFRAMEBUFFERTEXTURE2DEXTPROC gl_framebuffer_texture_2d;
+  PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC gl_check_framebuffer_status;
+  guint has_texture_from_pixmap:1;
+  guint has_framebuffer_object:1;
+};
+
+G_GNUC_INTERNAL
+GLVTable *
+gl_get_vtable (void);
+
+typedef struct _GLPixmapObject GLPixmapObject;
+struct _GLPixmapObject
+{
+  Display *dpy;
+  GLenum target;
+  GLuint texture;
+  GLTextureState old_texture;
+  guint width;
+  guint height;
+  Pixmap pixmap;
+  GLXPixmap glx_pixmap;
+  guint is_bound:1;
+};
+
+G_GNUC_INTERNAL
+GLPixmapObject *
+gl_create_pixmap_object (Display * dpy, guint width, guint height);
+
+G_GNUC_INTERNAL
+void
+gl_destroy_pixmap_object (GLPixmapObject * pixo);
+
+G_GNUC_INTERNAL
+gboolean
+gl_bind_pixmap_object (GLPixmapObject * pixo);
+
+G_GNUC_INTERNAL
+gboolean
+gl_unbind_pixmap_object (GLPixmapObject * pixo);
+
+typedef struct _GLFramebufferObject GLFramebufferObject;
+struct _GLFramebufferObject
+{
+  guint width;
+  guint height;
+  GLuint fbo;
+  GLuint old_fbo;
+  guint is_bound:1;
+};
+
+G_GNUC_INTERNAL
+GLFramebufferObject *
+gl_create_framebuffer_object (GLenum target,
+    GLuint texture, guint width, guint height);
+
+G_GNUC_INTERNAL
+void
+gl_destroy_framebuffer_object (GLFramebufferObject * fbo);
+
+G_GNUC_INTERNAL
+gboolean
+gl_bind_framebuffer_object (GLFramebufferObject * fbo);
+
+G_GNUC_INTERNAL
+gboolean
+gl_unbind_framebuffer_object (GLFramebufferObject * fbo);
+
+typedef enum {
+  GST_VAAPI_GL_API_NONE = 0,
+  GST_VAAPI_GL_API_OPENGL = (1 << 0),
+  GST_VAAPI_GL_API_OPENGL3 = (1 << 1),
+  GST_VAAPI_GL_API_GLES1 = (1 << 15),
+  GST_VAAPI_GL_API_GLES2 = (1 << 16),
+
+  GST_VAAPI_GL_API_ANY = G_MAXUINT32
+} GstVaapiGLApi;
+
+G_GNUC_INTERNAL
+GstVaapiGLApi
+gl_get_current_api (guint * major, guint * minor);
+
+#endif /* GST_VAAPI_UTILS_GLX_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h264.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h264.c
new file mode 100644 (file)
index 0000000..0d01253
--- /dev/null
@@ -0,0 +1,409 @@
+/*
+ *  gstvaapiutils_h264.c - H.264 related utilities
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <gst/codecparsers/gsth264parser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiutils_h264_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+struct map
+{
+  guint value;
+  const gchar *name;
+};
+
+/* Profile string map */
+static const struct map gst_vaapi_h264_profile_map[] = {
+/* *INDENT-OFF* */
+  { GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE, "constrained-baseline" },
+  { GST_VAAPI_PROFILE_H264_BASELINE,             "baseline"             },
+  { GST_VAAPI_PROFILE_H264_MAIN,                 "main"                 },
+  { GST_VAAPI_PROFILE_H264_EXTENDED,             "extended"             },
+  { GST_VAAPI_PROFILE_H264_HIGH,                 "high"                 },
+  { GST_VAAPI_PROFILE_H264_HIGH10,               "high-10"              },
+  { GST_VAAPI_PROFILE_H264_HIGH_422,             "high-4:2:2"           },
+  { GST_VAAPI_PROFILE_H264_HIGH_444,             "high-4:4:4"           },
+  { GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE,    "scalable-baseline"    },
+  { GST_VAAPI_PROFILE_H264_SCALABLE_HIGH,        "scalable-high"        },
+  { GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH,       "multiview-high"       },
+  { GST_VAAPI_PROFILE_H264_STEREO_HIGH,          "stereo-high"          },
+  { 0, NULL }
+/* *INDENT-ON* */
+};
+
+/* Level string map */
+static const struct map gst_vaapi_h264_level_map[] = {
+/* *INDENT-OFF* */
+  { GST_VAAPI_LEVEL_H264_L1,    "1"     },
+  { GST_VAAPI_LEVEL_H264_L1b,   "1b"    },
+  { GST_VAAPI_LEVEL_H264_L1_1,  "1.1"   },
+  { GST_VAAPI_LEVEL_H264_L1_2,  "1.2"   },
+  { GST_VAAPI_LEVEL_H264_L1_3,  "1.3"   },
+  { GST_VAAPI_LEVEL_H264_L2,    "2"     },
+  { GST_VAAPI_LEVEL_H264_L2_1,  "2.1"   },
+  { GST_VAAPI_LEVEL_H264_L2_2,  "2.2"   },
+  { GST_VAAPI_LEVEL_H264_L3,    "3"     },
+  { GST_VAAPI_LEVEL_H264_L3_1,  "3.1"   },
+  { GST_VAAPI_LEVEL_H264_L3_2,  "3.2"   },
+  { GST_VAAPI_LEVEL_H264_L4,    "4"     },
+  { GST_VAAPI_LEVEL_H264_L4_1,  "4.1"   },
+  { GST_VAAPI_LEVEL_H264_L4_2,  "4.2"   },
+  { GST_VAAPI_LEVEL_H264_L5,    "5"     },
+  { GST_VAAPI_LEVEL_H264_L5_1,  "5.1"   },
+  { GST_VAAPI_LEVEL_H264_L5_2,  "5.2"   },
+  { GST_VAAPI_LEVEL_H264_L6,    "6"     },
+  { GST_VAAPI_LEVEL_H264_L6_1,  "6.1"   },
+  { GST_VAAPI_LEVEL_H264_L6_2,  "6.2"   },
+  { 0, NULL }
+/* *INDENT-ON* */
+};
+
+/* Table A-1 - Level limits */
+/* *INDENT-OFF* */
+static const GstVaapiH264LevelLimits gst_vaapi_h264_level_limits[] = {
+  /* level                     idc   MaxMBPS   MaxFS MaxDpbMbs  MaxBR MaxCPB  MinCr */
+  { GST_VAAPI_LEVEL_H264_L1,    10,     1485,     99,    396,     64,    175, 2 },
+  { GST_VAAPI_LEVEL_H264_L1b,   11,     1485,     99,    396,    128,    350, 2 },
+  { GST_VAAPI_LEVEL_H264_L1_1,  11,     3000,    396,    900,    192,    500, 2 },
+  { GST_VAAPI_LEVEL_H264_L1_2,  12,     6000,    396,   2376,    384,   1000, 2 },
+  { GST_VAAPI_LEVEL_H264_L1_3,  13,    11880,    396,   2376,    768,   2000, 2 },
+  { GST_VAAPI_LEVEL_H264_L2,    20,    11880,    396,   2376,   2000,   2000, 2 },
+  { GST_VAAPI_LEVEL_H264_L2_1,  21,    19800,    792,   4752,   4000,   4000, 2 },
+  { GST_VAAPI_LEVEL_H264_L2_2,  22,    20250,   1620,   8100,   4000,   4000, 2 },
+  { GST_VAAPI_LEVEL_H264_L3,    30,    40500,   1620,   8100,  10000,  10000, 2 },
+  { GST_VAAPI_LEVEL_H264_L3_1,  31,   108000,   3600,  18000,  14000,  14000, 4 },
+  { GST_VAAPI_LEVEL_H264_L3_2,  32,   216000,   5120,  20480,  20000,  20000, 4 },
+  { GST_VAAPI_LEVEL_H264_L4,    40,   245760,   8192,  32768,  20000,  25000, 4 },
+  { GST_VAAPI_LEVEL_H264_L4_1,  41,   245760,   8192,  32768,  50000,  62500, 2 },
+  { GST_VAAPI_LEVEL_H264_L4_2,  42,   522240,   8704,  34816,  50000,  62500, 2 },
+  { GST_VAAPI_LEVEL_H264_L5,    50,   589824,  22080, 110400, 135000, 135000, 2 },
+  { GST_VAAPI_LEVEL_H264_L5_1,  51,   983040,  36864, 184320, 240000, 240000, 2 },
+  { GST_VAAPI_LEVEL_H264_L5_2,  52,  2073600,  36864, 184320, 240000, 240000, 2 },
+  { GST_VAAPI_LEVEL_H264_L6,    60,  4177920, 139264, 696320, 240000, 240000, 2 },
+  { GST_VAAPI_LEVEL_H264_L6_1,  61,  8355840, 139264, 696320, 480000, 480000, 2 },
+  { GST_VAAPI_LEVEL_H264_L6_2,  62, 16711680, 139264, 696320, 800000, 800000, 2 },
+  { 0, }
+};
+/* *INDENT-ON* */
+
+/* Lookup value in map */
+static const struct map *
+map_lookup_value (const struct map *m, guint value)
+{
+  g_return_val_if_fail (m != NULL, NULL);
+
+  for (; m->name != NULL; m++) {
+    if (m->value == value)
+      return m;
+  }
+  return NULL;
+}
+
+/* Lookup name in map */
+static const struct map *
+map_lookup_name (const struct map *m, const gchar * name)
+{
+  g_return_val_if_fail (m != NULL, NULL);
+
+  if (!name)
+    return NULL;
+
+  for (; m->name != NULL; m++) {
+    if (strcmp (m->name, name) == 0)
+      return m;
+  }
+  return NULL;
+}
+
+/** Returns a relative score for the supplied GstVaapiProfile */
+guint
+gst_vaapi_utils_h264_get_profile_score (GstVaapiProfile profile)
+{
+  const struct map *const m =
+      map_lookup_value (gst_vaapi_h264_profile_map, profile);
+
+  return m ? 1 + (m - gst_vaapi_h264_profile_map) : 0;
+}
+
+/** Returns GstVaapiProfile from H.264 profile_idc value */
+GstVaapiProfile
+gst_vaapi_utils_h264_get_profile (guint8 profile_idc)
+{
+  GstVaapiProfile profile;
+
+  switch (profile_idc) {
+    case GST_H264_PROFILE_BASELINE:
+      profile = GST_VAAPI_PROFILE_H264_BASELINE;
+      break;
+    case GST_H264_PROFILE_MAIN:
+      profile = GST_VAAPI_PROFILE_H264_MAIN;
+      break;
+    case GST_H264_PROFILE_EXTENDED:
+      profile = GST_VAAPI_PROFILE_H264_EXTENDED;
+      break;
+    case GST_H264_PROFILE_HIGH:
+      profile = GST_VAAPI_PROFILE_H264_HIGH;
+      break;
+    case GST_H264_PROFILE_HIGH10:
+      profile = GST_VAAPI_PROFILE_H264_HIGH10;
+      break;
+    case GST_H264_PROFILE_HIGH_422:
+      profile = GST_VAAPI_PROFILE_H264_HIGH_422;
+      break;
+    case GST_H264_PROFILE_HIGH_444:
+      profile = GST_VAAPI_PROFILE_H264_HIGH_444;
+      break;
+    case GST_H264_PROFILE_SCALABLE_BASELINE:
+      profile = GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE;
+      break;
+    case GST_H264_PROFILE_SCALABLE_HIGH:
+      profile = GST_VAAPI_PROFILE_H264_SCALABLE_HIGH;
+      break;
+    case GST_H264_PROFILE_MULTIVIEW_HIGH:
+      profile = GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH;
+      break;
+    case GST_H264_PROFILE_STEREO_HIGH:
+      profile = GST_VAAPI_PROFILE_H264_STEREO_HIGH;
+      break;
+    default:
+      GST_DEBUG ("unsupported profile_idc value");
+      profile = GST_VAAPI_PROFILE_UNKNOWN;
+      break;
+  }
+  return profile;
+}
+
+/** Returns H.264 profile_idc value from GstVaapiProfile */
+guint8
+gst_vaapi_utils_h264_get_profile_idc (GstVaapiProfile profile)
+{
+  guint8 profile_idc;
+
+  switch (profile) {
+    case GST_VAAPI_PROFILE_H264_BASELINE:
+    case GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE:
+      profile_idc = GST_H264_PROFILE_BASELINE;
+      break;
+    case GST_VAAPI_PROFILE_H264_MAIN:
+      profile_idc = GST_H264_PROFILE_MAIN;
+      break;
+    case GST_VAAPI_PROFILE_H264_EXTENDED:
+      profile_idc = GST_H264_PROFILE_EXTENDED;
+      break;
+    case GST_VAAPI_PROFILE_H264_HIGH:
+      profile_idc = GST_H264_PROFILE_HIGH;
+      break;
+    case GST_VAAPI_PROFILE_H264_HIGH10:
+      profile_idc = GST_H264_PROFILE_HIGH10;
+      break;
+    case GST_VAAPI_PROFILE_H264_HIGH_422:
+      profile_idc = GST_H264_PROFILE_HIGH_422;
+      break;
+    case GST_VAAPI_PROFILE_H264_HIGH_444:
+      profile_idc = GST_H264_PROFILE_HIGH_444;
+      break;
+    case GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE:
+      profile_idc = GST_H264_PROFILE_SCALABLE_BASELINE;
+      break;
+    case GST_VAAPI_PROFILE_H264_SCALABLE_HIGH:
+      profile_idc = GST_H264_PROFILE_SCALABLE_HIGH;
+      break;
+    case GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH:
+      profile_idc = GST_H264_PROFILE_MULTIVIEW_HIGH;
+      break;
+    case GST_VAAPI_PROFILE_H264_STEREO_HIGH:
+      profile_idc = GST_H264_PROFILE_STEREO_HIGH;
+      break;
+    default:
+      GST_DEBUG ("unsupported GstVaapiProfile value");
+      profile_idc = 0;
+      break;
+  }
+  return profile_idc;
+}
+
+/** Returns GstVaapiProfile from a string representation */
+GstVaapiProfile
+gst_vaapi_utils_h264_get_profile_from_string (const gchar * str)
+{
+  const struct map *const m = map_lookup_name (gst_vaapi_h264_profile_map, str);
+
+  return m ? (GstVaapiProfile) m->value : GST_VAAPI_PROFILE_UNKNOWN;
+}
+
+/** Returns a string representation for the supplied H.264 profile */
+const gchar *
+gst_vaapi_utils_h264_get_profile_string (GstVaapiProfile profile)
+{
+  const struct map *const m =
+      map_lookup_value (gst_vaapi_h264_profile_map, profile);
+
+  return m ? m->name : NULL;
+}
+
+/** Returns GstVaapiLevelH264 from H.264 level_idc value */
+GstVaapiLevelH264
+gst_vaapi_utils_h264_get_level (guint8 level_idc)
+{
+  const GstVaapiH264LevelLimits *llp;
+
+  // Prefer Level 1.1 over level 1b
+  if (G_UNLIKELY (level_idc == 11))
+    return GST_VAAPI_LEVEL_H264_L1_1;
+
+  for (llp = gst_vaapi_h264_level_limits; llp->level != 0; llp++) {
+    if (llp->level_idc == level_idc)
+      return llp->level;
+  }
+  GST_DEBUG ("unsupported level_idc value");
+  return (GstVaapiLevelH264) 0;
+}
+
+/** Returns H.264 level_idc value from GstVaapiLevelH264 */
+guint8
+gst_vaapi_utils_h264_get_level_idc (GstVaapiLevelH264 level)
+{
+  const GstVaapiH264LevelLimits *const llp =
+      gst_vaapi_utils_h264_get_level_limits (level);
+
+  return llp ? llp->level_idc : 0;
+}
+
+/** Returns GstVaapiLevelH264 from a string representation */
+GstVaapiLevelH264
+gst_vaapi_utils_h264_get_level_from_string (const gchar * str)
+{
+  gint v, level_idc = 0;
+
+  if (!str || !str[0])
+    goto not_found;
+
+  v = g_ascii_digit_value (str[0]);
+  if (v < 0)
+    goto not_found;
+  level_idc = v * 10;
+
+  switch (str[1]) {
+    case '\0':
+      break;
+    case '.':
+      v = g_ascii_digit_value (str[2]);
+      if (v < 0 || str[3] != '\0')
+        goto not_found;
+      level_idc += v;
+      break;
+    case 'b':
+      if (level_idc == 10 && str[2] == '\0')
+        return GST_VAAPI_LEVEL_H264_L1b;
+      // fall-trough
+    default:
+      goto not_found;
+  }
+  return gst_vaapi_utils_h264_get_level (level_idc);
+
+not_found:
+  return (GstVaapiLevelH264) 0;
+}
+
+/** Returns a string representation for the supplied H.264 level */
+const gchar *
+gst_vaapi_utils_h264_get_level_string (GstVaapiLevelH264 level)
+{
+  if (level < GST_VAAPI_LEVEL_H264_L1 || level > GST_VAAPI_LEVEL_H264_L6_2)
+    return NULL;
+  return gst_vaapi_h264_level_map[level - GST_VAAPI_LEVEL_H264_L1].name;
+}
+
+/** Returns level limits as specified in Table A-1 of the H.264 standard */
+const GstVaapiH264LevelLimits *
+gst_vaapi_utils_h264_get_level_limits (GstVaapiLevelH264 level)
+{
+  if (level < GST_VAAPI_LEVEL_H264_L1 || level > GST_VAAPI_LEVEL_H264_L6_2)
+    return NULL;
+  return &gst_vaapi_h264_level_limits[level - GST_VAAPI_LEVEL_H264_L1];
+}
+
+/** Returns the Table A-1 specification */
+const GstVaapiH264LevelLimits *
+gst_vaapi_utils_h264_get_level_limits_table (guint * out_length_ptr)
+{
+  if (out_length_ptr)
+    *out_length_ptr = G_N_ELEMENTS (gst_vaapi_h264_level_limits) - 1;
+  return gst_vaapi_h264_level_limits;
+}
+
+/** Returns GstVaapiChromaType from H.264 chroma_format_idc value */
+GstVaapiChromaType
+gst_vaapi_utils_h264_get_chroma_type (guint chroma_format_idc)
+{
+  GstVaapiChromaType chroma_type;
+
+  switch (chroma_format_idc) {
+    case 0:
+      chroma_type = GST_VAAPI_CHROMA_TYPE_YUV400;
+      break;
+    case 1:
+      chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+      break;
+    case 2:
+      chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422;
+      break;
+    case 3:
+      chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444;
+      break;
+    default:
+      GST_DEBUG ("unsupported chroma_format_idc value");
+      chroma_type = (GstVaapiChromaType) 0;
+      break;
+  }
+  return chroma_type;
+}
+
+/** Returns H.264 chroma_format_idc value from GstVaapiChromaType */
+guint
+gst_vaapi_utils_h264_get_chroma_format_idc (GstVaapiChromaType chroma_type)
+{
+  guint chroma_format_idc;
+
+  switch (chroma_type) {
+    case GST_VAAPI_CHROMA_TYPE_YUV400:
+      chroma_format_idc = 0;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV420:
+      chroma_format_idc = 1;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV422:
+      chroma_format_idc = 2;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV444:
+      chroma_format_idc = 3;
+      break;
+    default:
+      GST_DEBUG ("unsupported GstVaapiChromaType value");
+      chroma_format_idc = 1;
+      break;
+  }
+  return chroma_format_idc;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h264.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h264.h
new file mode 100644 (file)
index 0000000..38d1341
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ *  gstvaapiutils_h264.h - H.264 related utilities
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_H264_H
+#define GST_VAAPI_UTILS_H264_H
+
+#include <gst/vaapi/gstvaapiprofile.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstVaapiLevelH264:
+ * @GST_VAAPI_LEVEL_H264_L1: H.264 level 1.
+ * @GST_VAAPI_LEVEL_H264_L1_1: H.264 level 1.1.
+ * @GST_VAAPI_LEVEL_H264_L1_2: H.264 level 1.2.
+ * @GST_VAAPI_LEVEL_H264_L1_3: H.264 level 1.3.
+ * @GST_VAAPI_LEVEL_H264_L2: H.264 level 2.
+ * @GST_VAAPI_LEVEL_H264_L2_1: H.264 level 2.1.
+ * @GST_VAAPI_LEVEL_H264_L2_2: H.264 level 2.2.
+ * @GST_VAAPI_LEVEL_H264_L3: H.264 level 3.
+ * @GST_VAAPI_LEVEL_H264_L3_1: H.264 level 3.1.
+ * @GST_VAAPI_LEVEL_H264_L3_2: H.264 level 3.2.
+ * @GST_VAAPI_LEVEL_H264_L4: H.264 level 4.
+ * @GST_VAAPI_LEVEL_H264_L4_1: H.264 level 4.1.
+ * @GST_VAAPI_LEVEL_H264_L4_2: H.264 level 4.2.
+ * @GST_VAAPI_LEVEL_H264_L5: H.264 level 5.
+ * @GST_VAAPI_LEVEL_H264_L5_1: H.264 level 5.1.
+ * @GST_VAAPI_LEVEL_H264_L5_2: H.264 level 5.2.
+ * @GST_VAAPI_LEVEL_H264_L6: H.264 level 6.
+ * @GST_VAAPI_LEVEL_H264_L6_1: H.264 level 6.1.
+ * @GST_VAAPI_LEVEL_H264_L6_2: H.264 level 6.2.
+ *
+ * The set of all levels for #GstVaapiLevelH264.
+ */
+typedef enum {
+  GST_VAAPI_LEVEL_H264_L1 = 1,
+  GST_VAAPI_LEVEL_H264_L1b,
+  GST_VAAPI_LEVEL_H264_L1_1,
+  GST_VAAPI_LEVEL_H264_L1_2,
+  GST_VAAPI_LEVEL_H264_L1_3,
+  GST_VAAPI_LEVEL_H264_L2,
+  GST_VAAPI_LEVEL_H264_L2_1,
+  GST_VAAPI_LEVEL_H264_L2_2,
+  GST_VAAPI_LEVEL_H264_L3,
+  GST_VAAPI_LEVEL_H264_L3_1,
+  GST_VAAPI_LEVEL_H264_L3_2,
+  GST_VAAPI_LEVEL_H264_L4,
+  GST_VAAPI_LEVEL_H264_L4_1,
+  GST_VAAPI_LEVEL_H264_L4_2,
+  GST_VAAPI_LEVEL_H264_L5,
+  GST_VAAPI_LEVEL_H264_L5_1,
+  GST_VAAPI_LEVEL_H264_L5_2,
+  GST_VAAPI_LEVEL_H264_L6,
+  GST_VAAPI_LEVEL_H264_L6_1,
+  GST_VAAPI_LEVEL_H264_L6_2,
+} GstVaapiLevelH264;
+
+/* Returns a relative score for the supplied GstVaapiProfile */
+guint
+gst_vaapi_utils_h264_get_profile_score (GstVaapiProfile profile);
+
+/* Returns GstVaapiProfile from a string representation */
+GstVaapiProfile
+gst_vaapi_utils_h264_get_profile_from_string (const gchar * str);
+
+/* Returns a string representation for the supplied H.264 profile */
+const gchar *
+gst_vaapi_utils_h264_get_profile_string (GstVaapiProfile profile);
+
+/* Returns GstVaapiLevelH264 from a string representation */
+GstVaapiLevelH264
+gst_vaapi_utils_h264_get_level_from_string (const gchar * str);
+
+/* Returns a string representation for the supplied H.264 level */
+const gchar *
+gst_vaapi_utils_h264_get_level_string (GstVaapiLevelH264 level);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UTILS_H264_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h264_priv.h
new file mode 100644 (file)
index 0000000..eb582f5
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *  gstvaapiutils_h264_priv.h - H.264 related utilities
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_H264_PRIV_H
+#define GST_VAAPI_UTILS_H264_PRIV_H
+
+#include "gstvaapiutils_h264.h"
+#include "gstvaapisurface.h"
+
+G_BEGIN_DECLS
+
+/**
+ * GstVaapiH264LevelLimits:
+ * @level: the #GstVaapiLevelH264
+ * @level_idc: the H.264 level_idc value
+ * @MaxMBPS: the maximum macroblock processing rate (MB/sec)
+ * @MaxFS: the maximum frame size (MBs)
+ * @MaxDpbMbs: the maxium decoded picture buffer size (MBs)
+ * @MaxBR: the maximum video bit rate (kbps)
+ * @MaxCPB: the maximum CPB size (kbits)
+ * @MinCR: the minimum Compression Ratio
+ *
+ * The data structure that describes the limits of an H.264 level.
+ */
+typedef struct {
+  GstVaapiLevelH264 level;
+  guint8 level_idc;
+  guint32 MaxMBPS;
+  guint32 MaxFS;
+  guint32 MaxDpbMbs;
+  guint32 MaxBR;
+  guint32 MaxCPB;
+  guint32 MinCR;
+} GstVaapiH264LevelLimits;
+
+/* Returns GstVaapiProfile from H.264 profile_idc value */
+G_GNUC_INTERNAL
+GstVaapiProfile
+gst_vaapi_utils_h264_get_profile (guint8 profile_idc);
+
+/* Returns H.264 profile_idc value from GstVaapiProfile */
+G_GNUC_INTERNAL
+guint8
+gst_vaapi_utils_h264_get_profile_idc (GstVaapiProfile profile);
+
+/* Returns GstVaapiLevelH264 from H.264 level_idc value */
+G_GNUC_INTERNAL
+GstVaapiLevelH264
+gst_vaapi_utils_h264_get_level (guint8 level_idc);
+
+/* Returns H.264 level_idc value from GstVaapiLevelH264 */
+G_GNUC_INTERNAL
+guint8
+gst_vaapi_utils_h264_get_level_idc (GstVaapiLevelH264 level);
+
+/* Returns level limits as specified in Table A-1 of the H.264 standard */
+G_GNUC_INTERNAL
+const GstVaapiH264LevelLimits *
+gst_vaapi_utils_h264_get_level_limits (GstVaapiLevelH264 level);
+
+/* Returns the Table A-1 specification */
+G_GNUC_INTERNAL
+const GstVaapiH264LevelLimits *
+gst_vaapi_utils_h264_get_level_limits_table (guint * out_length_ptr);
+
+/* Returns GstVaapiChromaType from H.264 chroma_format_idc value */
+G_GNUC_INTERNAL
+GstVaapiChromaType
+gst_vaapi_utils_h264_get_chroma_type (guint chroma_format_idc);
+
+/* Returns H.264 chroma_format_idc value from GstVaapiChromaType */
+G_GNUC_INTERNAL
+guint
+gst_vaapi_utils_h264_get_chroma_format_idc (GstVaapiChromaType chroma_type);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UTILS_H264_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h265.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h265.c
new file mode 100644 (file)
index 0000000..a419af8
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ *  gstvaapiutils_h265.c - H.265 related utilities
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <gst/codecparsers/gsth265parser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiutils_h265_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+struct map
+{
+  guint value;
+  const gchar *name;
+};
+
+/* Profile string map */
+static const struct map gst_vaapi_h265_profile_map[] = {
+/* *INDENT-OFF* */
+  { GST_VAAPI_PROFILE_H265_MAIN,                 "main"                 },
+  { GST_VAAPI_PROFILE_H265_MAIN10,               "main-10"              },
+  { GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE,   "main-still-picture"   },
+  { GST_VAAPI_PROFILE_H265_MAIN_444,             "main-444"             },
+  { GST_VAAPI_PROFILE_H265_MAIN_444_10,          "main-444-10"          },
+  { GST_VAAPI_PROFILE_H265_MAIN_422_10,          "main-422-10"          },
+  { GST_VAAPI_PROFILE_H265_MAIN12,               "main-12"              },
+  { GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN,        "screen-extended-main"       },
+  { GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10,     "screen-extended-main-10"    },
+  { GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444,    "screen-extended-main-444"   },
+  { GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10, "screen-extended-main-444-10"},
+  { 0, NULL }
+/* *INDENT-ON* */
+};
+
+/* Tier string map */
+static const struct map gst_vaapi_h265_tier_map[] = {
+/* *INDENT-OFF* */
+  { GST_VAAPI_TIER_H265_MAIN,    "main" },
+  { GST_VAAPI_TIER_H265_HIGH,    "high"},
+  { GST_VAAPI_TIER_H265_UNKNOWN, "unknown"}
+/* *INDENT-ON* */
+};
+
+/* Level string map */
+static const struct map gst_vaapi_h265_level_map[] = {
+/* *INDENT-OFF* */
+  { GST_VAAPI_LEVEL_H265_L1,    "1"     },
+  { GST_VAAPI_LEVEL_H265_L2,    "2"     },
+  { GST_VAAPI_LEVEL_H265_L2_1,  "2.1"   },
+  { GST_VAAPI_LEVEL_H265_L3,    "3"     },
+  { GST_VAAPI_LEVEL_H265_L3_1,  "3.1"   },
+  { GST_VAAPI_LEVEL_H265_L4,    "4"     },
+  { GST_VAAPI_LEVEL_H265_L4_1,  "4.1"   },
+  { GST_VAAPI_LEVEL_H265_L5,    "5"     },
+  { GST_VAAPI_LEVEL_H265_L5_1,  "5.1"   },
+  { GST_VAAPI_LEVEL_H265_L5_2,  "5.2"   },
+  { GST_VAAPI_LEVEL_H265_L6,    "6"     },
+  { GST_VAAPI_LEVEL_H265_L6_1,  "6.1"   },
+  { GST_VAAPI_LEVEL_H265_L6_2,  "6.2"   },
+  { 0, NULL }
+/* *INDENT-ON* */
+};
+
+/* Table A-1 - Level limits */
+/* *INDENT-OFF* */
+static const GstVaapiH265LevelLimits gst_vaapi_h265_level_limits[] = {
+  /* level                     idc   MaxLumaPs  MCPBMt  MCPBHt MSlSeg MTR MTC   MaxLumaSr   MBRMt   MBRHt MinCr*/
+  { GST_VAAPI_LEVEL_H265_L1,    30,     36864,    350,      0,    16,  1,  1,     552960,    128,      0,  2},
+  { GST_VAAPI_LEVEL_H265_L2,    60,    122880,   1500,      0,    16,  1,  1,    3686400,   1500,      0,  2},
+  { GST_VAAPI_LEVEL_H265_L2_1,  63,    245760,   3000,      0,    20,  1,  1,    7372800,   3000,      0,  2},
+  { GST_VAAPI_LEVEL_H265_L3,    90,    552960,   6000,      0,    30,  2,  2,   16588800,   6000,      0,  2},
+  { GST_VAAPI_LEVEL_H265_L3_1,  93,    983040,  10000,      0,    40,  3,  3,   33177600,  10000,      0,  2},
+  { GST_VAAPI_LEVEL_H265_L4,    120,  2228224,  12000,  30000,    75,  5,  5,   66846720,  12000,  30000,  4},
+  { GST_VAAPI_LEVEL_H265_L4_1,  123,  2228224,  20000,  50000,    75,  5,  5,  133693440,  20000,  50000,  4},
+  { GST_VAAPI_LEVEL_H265_L5,    150,  8912896,  25000, 100000,   200, 11, 10,  267386880,  25000, 100000,  6},
+  { GST_VAAPI_LEVEL_H265_L5_1,  153,  8912896,  40000, 160000,   200, 11, 10,  534773760,  40000, 160000,  8},
+  { GST_VAAPI_LEVEL_H265_L5_2,  156,  8912896,  60000, 240000,   200, 11, 10, 1069547520,  60000, 240000,  8},
+  { GST_VAAPI_LEVEL_H265_L6,    180, 35651584,  60000, 240000,   600, 22, 20, 1069547520,  60000, 240000,  8},
+  { GST_VAAPI_LEVEL_H265_L6_1,  183, 35651584, 120000, 480000,   600, 22, 20, 2139095040, 120000, 480000,  8},
+  { GST_VAAPI_LEVEL_H265_L6_2,  186, 35651584, 240000, 800000,   600, 22, 20, 4278190080, 240000, 800000,  6},
+  { 0, }
+};
+/* *INDENT-ON* */
+
+/* Lookup value in map */
+static const struct map *
+map_lookup_value (const struct map *m, guint value)
+{
+  g_return_val_if_fail (m != NULL, NULL);
+
+  for (; m->name != NULL; m++) {
+    if (m->value == value)
+      return m;
+  }
+  return NULL;
+}
+
+/* Lookup name in map */
+static const struct map *
+map_lookup_name (const struct map *m, const gchar * name)
+{
+  g_return_val_if_fail (m != NULL, NULL);
+
+  if (!name)
+    return NULL;
+
+  for (; m->name != NULL; m++) {
+    if (strcmp (m->name, name) == 0)
+      return m;
+  }
+  return NULL;
+}
+
+/** Returns a relative score for the supplied GstVaapiProfile */
+guint
+gst_vaapi_utils_h265_get_profile_score (GstVaapiProfile profile)
+{
+  const struct map *const m =
+      map_lookup_value (gst_vaapi_h265_profile_map, profile);
+
+  return m ? 1 + (m - gst_vaapi_h265_profile_map) : 0;
+}
+
+/** Returns GstVaapiProfile from H.265 profile_idc value */
+GstVaapiProfile
+gst_vaapi_utils_h265_get_profile (GstH265SPS * sps)
+{
+  GstVaapiProfile vaapi_profile;
+  GstH265Profile profile;
+
+  g_return_val_if_fail (sps != NULL, GST_VAAPI_PROFILE_UNKNOWN);
+
+  profile = gst_h265_get_profile_from_sps (sps);
+  switch (profile) {
+    case GST_H265_PROFILE_MAIN:
+      /* Main Intra, recognize it as MAIN */
+    case GST_H265_PROFILE_MAIN_INTRA:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN;
+      break;
+    case GST_H265_PROFILE_MAIN_10:
+      /* Main 10 Intra, recognize it as MAIN10 */
+    case GST_H265_PROFILE_MAIN_10_INTRA:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN10;
+      break;
+    case GST_H265_PROFILE_MAIN_12:
+      /* Main 12 Intra, recognize it as MAIN_12 */
+    case GST_H265_PROFILE_MAIN_12_INTRA:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN12;
+      break;
+    case GST_H265_PROFILE_MAIN_STILL_PICTURE:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE;
+      break;
+    case GST_H265_PROFILE_MAIN_422_10:
+      /* Main 422_10 Intra, recognize it as MAIN_422_10 */
+    case GST_H265_PROFILE_MAIN_422_10_INTRA:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_422_10;
+      break;
+    case GST_H265_PROFILE_MAIN_422_12:
+      /* Main 422_12 Intra, recognize it as MAIN_422_12 */
+    case GST_H265_PROFILE_MAIN_422_12_INTRA:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_422_12;
+      break;
+    case GST_H265_PROFILE_MAIN_444:
+      /* Main 444 Intra, recognize it as MAIN_444 */
+    case GST_H265_PROFILE_MAIN_444_INTRA:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_444;
+      break;
+    case GST_H265_PROFILE_MAIN_444_10:
+      /* Main 444_10 Intra, recognize it as MAIN_444_10 */
+    case GST_H265_PROFILE_MAIN_444_10_INTRA:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_444_10;
+      break;
+    case GST_H265_PROFILE_MAIN_444_12:
+      /* Main 444_12 Intra, recognize it as MAIN_444_12 */
+    case GST_H265_PROFILE_MAIN_444_12_INTRA:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_MAIN_444_12;
+      break;
+    case GST_H265_PROFILE_SCREEN_EXTENDED_MAIN:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN;
+      break;
+    case GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_10:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10;
+      break;
+    case GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444;
+      break;
+    case GST_H265_PROFILE_SCREEN_EXTENDED_MAIN_444_10:
+      vaapi_profile = GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10;
+      break;
+    default:
+      GST_DEBUG ("unsupported profile_idc value");
+      vaapi_profile = GST_VAAPI_PROFILE_UNKNOWN;
+      break;
+  }
+  return vaapi_profile;
+}
+
+/** Returns H.265 profile_idc value from GstVaapiProfile */
+guint8
+gst_vaapi_utils_h265_get_profile_idc (GstVaapiProfile profile)
+{
+  guint8 profile_idc;
+
+  switch (profile) {
+    case GST_VAAPI_PROFILE_H265_MAIN:
+      profile_idc = GST_H265_PROFILE_IDC_MAIN;
+      break;
+    case GST_VAAPI_PROFILE_H265_MAIN10:
+      profile_idc = GST_H265_PROFILE_IDC_MAIN_10;
+      break;
+    case GST_VAAPI_PROFILE_H265_MAIN_STILL_PICTURE:
+      profile_idc = GST_H265_PROFILE_IDC_MAIN_STILL_PICTURE;
+      break;
+    case GST_VAAPI_PROFILE_H265_MAIN_422_10:
+      /* Fall through */
+    case GST_VAAPI_PROFILE_H265_MAIN_444:
+      /* Fall through */
+    case GST_VAAPI_PROFILE_H265_MAIN_444_10:
+      /* Fall through */
+    case GST_VAAPI_PROFILE_H265_MAIN12:
+      profile_idc = GST_H265_PROFILE_IDC_FORMAT_RANGE_EXTENSION;
+      break;
+    case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN:
+      /* Fall through */
+    case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_10:
+      /* Fall through */
+    case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444:
+      /* Fall through */
+    case GST_VAAPI_PROFILE_H265_SCREEN_EXTENDED_MAIN_444_10:
+      profile_idc = GST_H265_PROFILE_IDC_SCREEN_CONTENT_CODING;
+      break;
+    default:
+      GST_DEBUG ("unsupported GstVaapiProfile value");
+      profile_idc = 0;
+      break;
+  }
+  return profile_idc;
+}
+
+/** Returns GstVaapiProfile from a string representation */
+GstVaapiProfile
+gst_vaapi_utils_h265_get_profile_from_string (const gchar * str)
+{
+  const struct map *const m = map_lookup_name (gst_vaapi_h265_profile_map, str);
+
+  return m ? (GstVaapiProfile) m->value : GST_VAAPI_PROFILE_UNKNOWN;
+}
+
+/** Returns a string representation for the supplied H.265 profile */
+const gchar *
+gst_vaapi_utils_h265_get_profile_string (GstVaapiProfile profile)
+{
+  const struct map *const m =
+      map_lookup_value (gst_vaapi_h265_profile_map, profile);
+
+  return m ? m->name : NULL;
+}
+
+/** Returns GstVaapiLevelH265 from H.265 level_idc value */
+GstVaapiLevelH265
+gst_vaapi_utils_h265_get_level (guint8 level_idc)
+{
+  const GstVaapiH265LevelLimits *llp;
+
+  for (llp = gst_vaapi_h265_level_limits; llp->level != 0; llp++) {
+    if (llp->level_idc == level_idc)
+      return llp->level;
+  }
+  GST_DEBUG ("unsupported level_idc value");
+  return (GstVaapiLevelH265) 0;
+}
+
+/** Returns H.265 level_idc value from GstVaapiLevelH265 */
+guint8
+gst_vaapi_utils_h265_get_level_idc (GstVaapiLevelH265 level)
+{
+  const GstVaapiH265LevelLimits *const llp =
+      gst_vaapi_utils_h265_get_level_limits (level);
+
+  return llp ? llp->level_idc : 0;
+}
+
+/** Returns GstVaapiLevelH265 from a string representation */
+GstVaapiLevelH265
+gst_vaapi_utils_h265_get_level_from_string (const gchar * str)
+{
+  gint v, level_idc = 0;
+
+  if (!str || !str[0])
+    goto not_found;
+
+  v = g_ascii_digit_value (str[0]);
+  if (v < 0)
+    goto not_found;
+  level_idc = v * 30;
+
+  switch (str[1]) {
+    case '\0':
+      break;
+    case '.':
+      v = g_ascii_digit_value (str[2]);
+      if (v < 0 || str[3] != '\0')
+        goto not_found;
+      level_idc += v;
+      break;
+    default:
+      goto not_found;
+  }
+  return gst_vaapi_utils_h265_get_level (level_idc);
+
+not_found:
+  return (GstVaapiLevelH265) 0;
+}
+
+/** Returns a string representation for the supplied H.265 level */
+const gchar *
+gst_vaapi_utils_h265_get_level_string (GstVaapiLevelH265 level)
+{
+  if (level < GST_VAAPI_LEVEL_H265_L1 || level > GST_VAAPI_LEVEL_H265_L6_2)
+    return NULL;
+  return gst_vaapi_h265_level_map[level - GST_VAAPI_LEVEL_H265_L1].name;
+}
+
+/** Returns level limits as specified in Table A-1 of the H.265 standard */
+const GstVaapiH265LevelLimits *
+gst_vaapi_utils_h265_get_level_limits (GstVaapiLevelH265 level)
+{
+  if (level < GST_VAAPI_LEVEL_H265_L1 || level > GST_VAAPI_LEVEL_H265_L6_2)
+    return NULL;
+  return &gst_vaapi_h265_level_limits[level - GST_VAAPI_LEVEL_H265_L1];
+}
+
+/** Returns the Table A-1 & A-2 specification */
+const GstVaapiH265LevelLimits *
+gst_vaapi_utils_h265_get_level_limits_table (guint * out_length_ptr)
+{
+  if (out_length_ptr)
+    *out_length_ptr = G_N_ELEMENTS (gst_vaapi_h265_level_limits) - 1;
+  return gst_vaapi_h265_level_limits;
+}
+
+/** Returns GstVaapiChromaType from H.265 chroma_format_idc value */
+GstVaapiChromaType
+gst_vaapi_utils_h265_get_chroma_type (guint chroma_format_idc,
+    guint luma_bit_depth, guint chroma_bit_depth)
+{
+  GstVaapiChromaType chroma_type = (GstVaapiChromaType) 0;
+  guint depth = 0;
+
+  if (luma_bit_depth < 8 || chroma_bit_depth < 8 ||
+      luma_bit_depth > 16 || chroma_bit_depth > 16) {
+    GST_WARNING ("invalid luma_bit_depth or chroma_bit_depth value");
+    return chroma_type;
+  }
+
+  depth = MAX (luma_bit_depth, chroma_bit_depth);
+
+  switch (chroma_format_idc) {
+    case 0:
+      chroma_type = GST_VAAPI_CHROMA_TYPE_YUV400;
+      break;
+    case 1:
+      if (depth == 8)
+        chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+      else if (depth > 8 && depth <= 10)
+        chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420_10BPP;
+      else if (depth > 10 && depth <= 12)
+        chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420_12BPP;
+      break;
+    case 2:
+      if (depth == 8)
+        chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422;
+      else if (depth > 8 && depth <= 10)
+        chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422_10BPP;
+      else if (depth > 10 && depth <= 12)
+        chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422_12BPP;
+      break;
+    case 3:
+      if (depth == 8)
+        chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444;
+      else if (depth > 8 && depth <= 10)
+        chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444_10BPP;
+      else if (depth > 10 && depth <= 12)
+        chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444_12BPP;
+      break;
+    default:
+      break;
+  }
+
+  if (chroma_type == (GstVaapiChromaType) 0)
+    GST_DEBUG ("unsupported chroma_format_idc value");
+
+  return chroma_type;
+}
+
+/** Returns H.265 chroma_format_idc value from GstVaapiChromaType */
+guint
+gst_vaapi_utils_h265_get_chroma_format_idc (GstVaapiChromaType chroma_type)
+{
+  guint chroma_format_idc;
+
+  switch (chroma_type) {
+    case GST_VAAPI_CHROMA_TYPE_YUV400:
+      chroma_format_idc = 0;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV420:
+    case GST_VAAPI_CHROMA_TYPE_YUV420_10BPP:
+    case GST_VAAPI_CHROMA_TYPE_YUV420_12BPP:
+      chroma_format_idc = 1;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV422:
+    case GST_VAAPI_CHROMA_TYPE_YUV422_10BPP:
+    case GST_VAAPI_CHROMA_TYPE_YUV422_12BPP:
+      chroma_format_idc = 2;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV444:
+    case GST_VAAPI_CHROMA_TYPE_YUV444_10BPP:
+    case GST_VAAPI_CHROMA_TYPE_YUV444_12BPP:
+      chroma_format_idc = 3;
+      break;
+    default:
+      GST_DEBUG ("unsupported GstVaapiChromaType value");
+      chroma_format_idc = 1;
+      break;
+  }
+  return chroma_format_idc;
+}
+
+/** Returns GstVaapiTierH265 from a string representation */
+GstVaapiTierH265
+gst_vaapi_utils_h265_get_tier_from_string (const gchar * str)
+{
+  const struct map *const m = map_lookup_name (gst_vaapi_h265_tier_map, str);
+
+  return m ? (GstVaapiTierH265) m->value : GST_VAAPI_TIER_H265_UNKNOWN;
+}
+
+/** Returns a string representation for the supplied H.265 tier */
+const gchar *
+gst_vaapi_utils_h265_get_tier_string (GstVaapiTierH265 tier)
+{
+  const struct map *const m = map_lookup_value (gst_vaapi_h265_tier_map, tier);
+
+  return m ? m->name : NULL;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h265.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h265.h
new file mode 100644 (file)
index 0000000..e3ac72e
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ *  gstvaapiutils_h265.h - H.265 related utilities
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_H265_H
+#define GST_VAAPI_UTILS_H265_H
+
+#include <gst/vaapi/gstvaapiprofile.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GST_VAAPI_H265_MAX_COL_TILES:
+ *
+ * The max tiles in column according to spec A1
+ *
+ */
+#define GST_VAAPI_H265_MAX_COL_TILES    20
+/**
+ * GST_VAAPI_H265_MAX_ROW_TILES:
+ *
+ * The max tiles in row according to spec A1
+ *
+ */
+#define GST_VAAPI_H265_MAX_ROW_TILES    22
+
+/**
+ * GstVaapiLevelH265:
+ * @GST_VAAPI_LEVEL_H265_L1: H.265 level 1.
+ * @GST_VAAPI_LEVEL_H265_L2: H.265 level 2.
+ * @GST_VAAPI_LEVEL_H265_L2_1: H.265 level 2.1.
+ * @GST_VAAPI_LEVEL_H265_L3: H.265 level 3.
+ * @GST_VAAPI_LEVEL_H265_L3_1: H.265 level 3.1.
+ * @GST_VAAPI_LEVEL_H265_L4: H.265 level 4.
+ * @GST_VAAPI_LEVEL_H265_L4_1: H.265 level 4.1.
+ * @GST_VAAPI_LEVEL_H265_L5: H.265 level 5.
+ * @GST_VAAPI_LEVEL_H265_L5_1: H.265 level 5.1.
+ * @GST_VAAPI_LEVEL_H265_L5_2: H.265 level 5.2.
+ * @GST_VAAPI_LEVEL_H265_L6: H.265 level 6.
+ * @GST_VAAPI_LEVEL_H265_L6_1: H.265 level 6.1.
+ * @GST_VAAPI_LEVEL_H265_L6_2: H.265 level 6.2.
+ *
+ * The set of all levels for #GstVaapiLevelH265.
+ */
+typedef enum {
+  GST_VAAPI_LEVEL_H265_L1 = 1,
+  GST_VAAPI_LEVEL_H265_L2,
+  GST_VAAPI_LEVEL_H265_L2_1,
+  GST_VAAPI_LEVEL_H265_L3,
+  GST_VAAPI_LEVEL_H265_L3_1,
+  GST_VAAPI_LEVEL_H265_L4,
+  GST_VAAPI_LEVEL_H265_L4_1,
+  GST_VAAPI_LEVEL_H265_L5,
+  GST_VAAPI_LEVEL_H265_L5_1,
+  GST_VAAPI_LEVEL_H265_L5_2,
+  GST_VAAPI_LEVEL_H265_L6,
+  GST_VAAPI_LEVEL_H265_L6_1,
+  GST_VAAPI_LEVEL_H265_L6_2,
+} GstVaapiLevelH265;
+
+/**
+ * GstVaapiTierH265:
+ * GST_VAAPI_TIER_H265_MAIN: H265 Tier 0
+ * GST_VAAPI_TIER_H265_HIGH: H265 Tier 1
+ * GST_VAAPI_TIER_H265_UNKNOWN: Unknown Tier
+ *
+ * The set of all Tier for #GstVaapiTierH265.
+ */
+typedef enum {
+  GST_VAAPI_TIER_H265_MAIN,
+  GST_VAAPI_TIER_H265_HIGH,
+  GST_VAAPI_TIER_H265_UNKNOWN = -1
+} GstVaapiTierH265;
+
+/* Returns a relative score for the supplied GstVaapiProfile */
+guint
+gst_vaapi_utils_h265_get_profile_score (GstVaapiProfile profile);
+
+/* Returns GstVaapiProfile from a string representation */
+GstVaapiProfile
+gst_vaapi_utils_h265_get_profile_from_string (const gchar * str);
+
+/* Returns a string representation for the supplied H.265 profile */
+const gchar *
+gst_vaapi_utils_h265_get_profile_string (GstVaapiProfile profile);
+
+/* Returns GstVaapiLevelH265 from a string representation */
+GstVaapiLevelH265
+gst_vaapi_utils_h265_get_level_from_string (const gchar * str);
+
+/* Returns a string representation for the supplied H.265 level */
+const gchar *
+gst_vaapi_utils_h265_get_level_string (GstVaapiLevelH265 level);
+
+/* Returns GstVaapiTierH265 from a string representation */
+GstVaapiTierH265
+gst_vaapi_utils_h265_get_tier_from_string (const gchar * str);
+
+/* Returns a string representation for the supplied H.265 Tier */
+const gchar *
+gst_vaapi_utils_h265_get_tier_string (GstVaapiTierH265 tier);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UTILS_H265_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h265_priv.h
new file mode 100644 (file)
index 0000000..88f7fda
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  gstvaapiutils_h265_priv.h - H.265 related utilities
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_H265_PRIV_H
+#define GST_VAAPI_UTILS_H265_PRIV_H
+
+#include "gstvaapiutils_h265.h"
+#include "gstvaapisurface.h"
+
+G_BEGIN_DECLS
+
+/**
+ * GstVaapiH265LevelLimits:
+ * @level: the #GstVaapiLevelH265
+ * @level_idc: the H.265 level_idc value
+ * @MaxLumaPs: the maximum luma picture size
+ * @MaxCPBTierMain: the maximum CPB size for Main tier(kbits)
+ * @MaxCPBTierHigh: the maximum CPB size for High tier(kbits)
+ * @MaxSliceSegPic: the maximum slice segments per picture
+ * @MaxTileRows: the maximum number of Tile Rows
+ * @MaxTileColumns: the maximum number of Tile Columns
+ * @MaxLumaSr: the maximum luma sample rate (samples/sec)
+ * @MaxBRTierMain: the maximum video bit rate for Main Tier(kbps)
+ * @MaxBRTierHigh: the maximum video bit rate for High Tier(kbps)
+ * @MinCr: the mimimum compression ratio
+ *
+ * The data structure that describes the limits of an H.265 level.
+ */
+typedef struct {
+  GstVaapiLevelH265 level;
+  guint8 level_idc;
+  guint32 MaxLumaPs;
+  guint32 MaxCPBTierMain;
+  guint32 MaxCPBTierHigh;
+  guint32 MaxSliceSegPic;
+  guint32 MaxTileRows;
+  guint32 MaxTileColumns;
+  guint32 MaxLumaSr;
+  guint32 MaxBRTierMain;
+  guint32 MaxBRTierHigh;
+  guint32 MinCr;
+} GstVaapiH265LevelLimits;
+
+/* Returns GstVaapiProfile from H.265 profile_idc value */
+G_GNUC_INTERNAL
+GstVaapiProfile
+gst_vaapi_utils_h265_get_profile (GstH265SPS * sps);
+
+/* Returns H.265 profile_idc value from GstVaapiProfile */
+G_GNUC_INTERNAL
+guint8
+gst_vaapi_utils_h265_get_profile_idc (GstVaapiProfile profile);
+
+/* Returns GstVaapiLevelH265 from H.265 level_idc value */
+G_GNUC_INTERNAL
+GstVaapiLevelH265
+gst_vaapi_utils_h265_get_level (guint8 level_idc);
+
+/* Returns H.265 level_idc value from GstVaapiLevelH265 */
+G_GNUC_INTERNAL
+guint8
+gst_vaapi_utils_h265_get_level_idc (GstVaapiLevelH265 level);
+
+/* Returns level limits as specified in Table A-1 of the H.265 standard */
+G_GNUC_INTERNAL
+const GstVaapiH265LevelLimits *
+gst_vaapi_utils_h265_get_level_limits (GstVaapiLevelH265 level);
+
+/* Returns the Table A-1 specification */
+G_GNUC_INTERNAL
+const GstVaapiH265LevelLimits *
+gst_vaapi_utils_h265_get_level_limits_table (guint * out_length_ptr);
+
+/* Returns GstVaapiChromaType from H.265 chroma_format_idc value */
+G_GNUC_INTERNAL
+GstVaapiChromaType
+gst_vaapi_utils_h265_get_chroma_type (guint chroma_format_idc,
+    guint luma_bit_depth, guint chroma_bit_depth);
+
+/* Returns H.265 chroma_format_idc value from GstVaapiChromaType */
+G_GNUC_INTERNAL
+guint
+gst_vaapi_utils_h265_get_chroma_format_idc (GstVaapiChromaType chroma_type);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UTILS_H265_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h26x.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h26x.c
new file mode 100644 (file)
index 0000000..4a679aa
--- /dev/null
@@ -0,0 +1,147 @@
+/*
+ *  gstvaapiutils_h26x.c - H.26x related utilities
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne
+ *  Copyright (C) 2017 Intel Corporation
+ *    Author: Hyunjun Ko <zzoon@igalia.com>
+ *    Author: Mark Thompson <sw@jkqxz.net>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstvaapiutils_h26x_priv.h"
+
+/* Write an unsigned integer Exp-Golomb-coded syntax element. i.e. ue(v) */
+gboolean
+bs_write_ue (GstBitWriter * bs, guint32 value)
+{
+  guint32 size_in_bits = 0;
+  guint32 tmp_value = ++value;
+
+  while (tmp_value) {
+    ++size_in_bits;
+    tmp_value >>= 1;
+  }
+  if (size_in_bits > 1
+      && !gst_bit_writer_put_bits_uint32 (bs, 0, size_in_bits - 1))
+    return FALSE;
+  if (!gst_bit_writer_put_bits_uint32 (bs, value, size_in_bits))
+    return FALSE;
+  return TRUE;
+}
+
+/* Write a signed integer Exp-Golomb-coded syntax element. i.e. se(v) */
+gboolean
+bs_write_se (GstBitWriter * bs, gint32 value)
+{
+  guint32 new_val;
+
+  if (value <= 0)
+    new_val = -(value << 1);
+  else
+    new_val = (value << 1) - 1;
+
+  if (!bs_write_ue (bs, new_val))
+    return FALSE;
+  return TRUE;
+}
+
+/* Copy from src to dst, applying emulation prevention bytes.
+ *
+ * This is copied from libavcodec written by Mark Thompson
+ * <sw@jkqxz.net> from
+ * http://git.videolan.org/?p=ffmpeg.git;a=commit;h=2c62fcdf5d617791a653d7957d449f75569eede0
+ */
+static gboolean
+gst_vaapi_utils_h26x_nal_unit_to_byte_stream (guint8 * dst, guint * dst_len,
+    guint8 * src, guint src_len)
+{
+  guint dp = 0, sp;
+  guint zero_run = 0;
+
+  for (sp = 0; sp < src_len; sp++) {
+    if (dp >= *dst_len)
+      goto fail;
+    if (zero_run < 2) {
+      if (src[sp] == 0)
+        ++zero_run;
+      else
+        zero_run = 0;
+    } else {
+      if ((src[sp] & ~3) == 0) {
+        /* emulation_prevention_byte: 0x03 */
+        dst[dp++] = 3;
+        if (dp >= *dst_len)
+          goto fail;
+      }
+      zero_run = src[sp] == 0;
+    }
+    dst[dp++] = src[sp];
+  }
+
+  *dst_len = dp;
+  return TRUE;
+
+fail:
+  *dst_len = 0;
+  return FALSE;
+}
+
+/**
+ * gst_vaapi_utils_h26x_write_nal_unit:
+ * @bs: a #GstBitWriter instance
+ * @nal: the NAL (Network Abstraction Layer) unit to write
+ * @nal_size: the size, in bytes, of @nal
+ *
+ * Writes in the @bs the @nal rewritten with the "emulation prevention
+ * bytes" if required.
+ *
+ * Returns: TRUE if the NAL unit could be coded applying the
+ * "emulation prevention bytes"; otherwise FALSE.
+ **/
+gboolean
+gst_vaapi_utils_h26x_write_nal_unit (GstBitWriter * bs, guint8 * nal,
+    guint nal_size)
+{
+  guint8 *byte_stream = NULL;
+  guint byte_stream_len;
+
+  byte_stream_len = nal_size + 10;
+  byte_stream = g_malloc (byte_stream_len);
+
+  if (!byte_stream)
+    return FALSE;
+
+  if (!gst_vaapi_utils_h26x_nal_unit_to_byte_stream (byte_stream,
+          &byte_stream_len, nal, nal_size)) {
+    g_free (byte_stream);
+    return FALSE;
+  }
+
+  WRITE_UINT32 (bs, byte_stream_len, 16);
+  gst_bit_writer_put_bytes (bs, byte_stream, byte_stream_len);
+  g_free (byte_stream);
+
+  return TRUE;
+
+bs_error:
+  {
+    GST_ERROR ("failed to write codec-data");
+    g_free (byte_stream);
+    return FALSE;
+  }
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_h26x_priv.h
new file mode 100644 (file)
index 0000000..23749ea
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *  gstvaapiutils_h26x_priv.h - H.26x related utilities
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne
+ *  Copyright (C) 2017 Intel Corporation
+ *    Author: Hyunjun Ko <zzoon@igalia.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_H26X_PRIV_H
+#define GST_VAAPI_UTILS_H26X_PRIV_H
+
+#include <gst/base/gstbitwriter.h>
+
+G_BEGIN_DECLS
+
+/* Default CPB length (in milliseconds) */
+#define DEFAULT_CPB_LENGTH 1500
+
+/* Scale factor for CPB size (HRD cpb_size_scale: min = 4) */
+#define SX_CPB_SIZE 4
+
+/* Scale factor for bitrate (HRD bit_rate_scale: min = 6) */
+#define SX_BITRATE 6
+
+/* Define default rate control mode ("constant-qp") */
+#define DEFAULT_RATECONTROL GST_VAAPI_RATECONTROL_CQP
+
+/* ------------------------------------------------------------------------- */
+/* --- H.264/265 Bitstream Writer                                            --- */
+/* ------------------------------------------------------------------------- */
+
+#define WRITE_UINT32(bs, val, nbits)                            \
+  G_STMT_START {                                                \
+    if (!gst_bit_writer_put_bits_uint32 (bs, val, nbits)) {     \
+      GST_WARNING ("failed to write uint32, nbits: %d", nbits); \
+      goto bs_error;                                            \
+    }                                                           \
+  } G_STMT_END
+
+#define WRITE_UE(bs, val)                       \
+  G_STMT_START {                                \
+    if (!bs_write_ue (bs, val)) {               \
+      GST_WARNING ("failed to write ue(v)");    \
+      goto bs_error;                            \
+    }                                           \
+  } G_STMT_END
+
+#define WRITE_SE(bs, val)                       \
+  G_STMT_START {                                \
+    if (!bs_write_se (bs, val)) {               \
+      GST_WARNING ("failed to write se(v)");    \
+      goto bs_error;                            \
+    }                                           \
+  } G_STMT_END
+
+G_GNUC_INTERNAL
+gboolean
+bs_write_ue (GstBitWriter * bs, guint32 value);
+
+G_GNUC_INTERNAL
+gboolean
+bs_write_se (GstBitWriter * bs, gint32 value);
+
+/* Write nal unit, applying emulation prevention bytes */
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_utils_h26x_write_nal_unit (GstBitWriter * bs, guint8 * nal, guint nal_size);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UTILS_H26X_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.c
new file mode 100644 (file)
index 0000000..04993c8
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ *  gstvaapiutils_mpeg2.c - MPEG-2 related utilities
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <gst/codecparsers/gstmpegvideoparser.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiutils_mpeg2_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+struct map
+{
+  guint value;
+  const gchar *name;
+};
+
+/* Profile string map */
+static const struct map gst_vaapi_mpeg2_profile_map[] = {
+/* *INDENT-OFF* */
+  { GST_VAAPI_PROFILE_MPEG2_SIMPLE,     "simple"        },
+  { GST_VAAPI_PROFILE_MPEG2_MAIN,       "main"          },
+  { GST_VAAPI_PROFILE_MPEG2_HIGH,       "high"          },
+  { 0, NULL }
+/* *INDENT-ON* */
+};
+
+/* Level string map */
+static const struct map gst_vaapi_mpeg2_level_map[] = {
+/* *INDENT-OFF* */
+  { GST_VAAPI_LEVEL_MPEG2_LOW,          "low"           },
+  { GST_VAAPI_LEVEL_MPEG2_MAIN,         "main"          },
+  { GST_VAAPI_LEVEL_MPEG2_HIGH_1440,    "high-1440"     },
+  { GST_VAAPI_LEVEL_MPEG2_HIGH,         "high"          },
+  { GST_VAAPI_LEVEL_MPEG2_HIGHP,        "highP"         },
+  { 0, NULL }
+/* *INDENT-ON* */
+};
+
+/* Table 8-10 to 8-13 (up to Main profile only) */
+/* *INDENT-OFF* */
+static const GstVaapiMPEG2LevelLimits gst_vaapi_mpeg2_level_limits[] = {
+  /* level      h_size  v_size  fps  samples     kbps  vbv_size */
+  { GST_VAAPI_LEVEL_MPEG2_LOW,
+    0x0a,        352,   288,   30,   3041280,   4000,   475136 },
+  { GST_VAAPI_LEVEL_MPEG2_MAIN,
+    0x08,        720,   576,   30,   1036800,  15000,  1835008 },
+  { GST_VAAPI_LEVEL_MPEG2_HIGH_1440,
+    0x06,       1440,  1152,   60,  47001600,  60000,  7340032 },
+  { GST_VAAPI_LEVEL_MPEG2_HIGH,
+    0x04,       1920,  1152,   60,  62668800,  80000,  9781248 },
+  /* Amendment 3: New level for 1080@50p/60p */
+  { GST_VAAPI_LEVEL_MPEG2_HIGHP,
+    0x02,       1920,  1152,   60, 125337600,  80000,  9781248 },
+  { 0, }
+};
+/* *INDENT-ON* */
+
+/* Lookup value in map */
+static const struct map *
+map_lookup_value (const struct map *m, guint value)
+{
+  g_return_val_if_fail (m != NULL, NULL);
+
+  for (; m->name != NULL; m++) {
+    if (m->value == value)
+      return m;
+  }
+  return NULL;
+}
+
+/* Lookup name in map */
+static const struct map *
+map_lookup_name (const struct map *m, const gchar * name)
+{
+  g_return_val_if_fail (m != NULL, NULL);
+
+  if (!name)
+    return NULL;
+
+  for (; m->name != NULL; m++) {
+    if (strcmp (m->name, name) == 0)
+      return m;
+  }
+  return NULL;
+}
+
+/** Returns a relative score for the supplied GstVaapiProfile */
+guint
+gst_vaapi_utils_mpeg2_get_profile_score (GstVaapiProfile profile)
+{
+  const struct map *const m =
+      map_lookup_value (gst_vaapi_mpeg2_profile_map, profile);
+
+  return m ? 1 + (m - gst_vaapi_mpeg2_profile_map) : 0;
+}
+
+/** Returns GstVaapiProfile from MPEG-2 profile_idc value */
+GstVaapiProfile
+gst_vaapi_utils_mpeg2_get_profile (guint8 profile_idc)
+{
+  GstVaapiProfile profile;
+
+  switch (profile_idc) {
+    case GST_MPEG_VIDEO_PROFILE_SIMPLE:
+      profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
+      break;
+    case GST_MPEG_VIDEO_PROFILE_MAIN:
+      profile = GST_VAAPI_PROFILE_MPEG2_MAIN;
+      break;
+    case GST_MPEG_VIDEO_PROFILE_HIGH:
+      profile = GST_VAAPI_PROFILE_MPEG2_HIGH;
+      break;
+    default:
+      GST_DEBUG ("unsupported profile_idc value");
+      profile = GST_VAAPI_PROFILE_UNKNOWN;
+      break;
+  }
+  return profile;
+}
+
+/** Returns MPEG-2 profile_idc value from GstVaapiProfile */
+guint8
+gst_vaapi_utils_mpeg2_get_profile_idc (GstVaapiProfile profile)
+{
+  guint8 profile_idc;
+
+  switch (profile) {
+    case GST_VAAPI_PROFILE_MPEG2_SIMPLE:
+      profile_idc = GST_MPEG_VIDEO_PROFILE_SIMPLE;
+      break;
+    case GST_VAAPI_PROFILE_MPEG2_MAIN:
+      profile_idc = GST_MPEG_VIDEO_PROFILE_MAIN;
+      break;
+    case GST_VAAPI_PROFILE_MPEG2_HIGH:
+      profile_idc = GST_MPEG_VIDEO_PROFILE_HIGH;
+      break;
+    default:
+      GST_DEBUG ("unsupported GstVaapiProfile value");
+      profile_idc = 0;
+      break;
+  }
+  return profile_idc;
+}
+
+/** Returns GstVaapiProfile from a string representation */
+GstVaapiProfile
+gst_vaapi_utils_mpeg2_get_profile_from_string (const gchar * str)
+{
+  const struct map *const m =
+      map_lookup_name (gst_vaapi_mpeg2_profile_map, str);
+
+  return m ? (GstVaapiProfile) m->value : GST_VAAPI_PROFILE_UNKNOWN;
+}
+
+/** Returns a string representation for the supplied MPEG-2 profile */
+const gchar *
+gst_vaapi_utils_mpeg2_get_profile_string (GstVaapiProfile profile)
+{
+  const struct map *const m =
+      map_lookup_value (gst_vaapi_mpeg2_profile_map, profile);
+
+  return m ? m->name : NULL;
+}
+
+/** Returns GstVaapiLevelMPEG2 from MPEG-2 level_idc value */
+GstVaapiLevelMPEG2
+gst_vaapi_utils_mpeg2_get_level (guint8 level_idc)
+{
+  const GstVaapiMPEG2LevelLimits *llp;
+
+  for (llp = gst_vaapi_mpeg2_level_limits; llp->level != 0; llp++) {
+    if (llp->level_idc == level_idc)
+      return llp->level;
+  }
+  GST_DEBUG ("unsupported level_idc value");
+  return (GstVaapiLevelMPEG2) 0;
+}
+
+/** Returns MPEG-2 level_idc value from GstVaapiLevelMPEG2 */
+guint8
+gst_vaapi_utils_mpeg2_get_level_idc (GstVaapiLevelMPEG2 level)
+{
+  const GstVaapiMPEG2LevelLimits *const llp =
+      gst_vaapi_utils_mpeg2_get_level_limits (level);
+
+  return llp ? llp->level_idc : 0;
+}
+
+/** Returns GstVaapiLevelMPEG2 from a string representation */
+GstVaapiLevelMPEG2
+gst_vaapi_utils_mpeg2_get_level_from_string (const gchar * str)
+{
+  const struct map *const m = map_lookup_name (gst_vaapi_mpeg2_level_map, str);
+
+  return (GstVaapiLevelMPEG2) (m ? m->value : 0);
+}
+
+/** Returns a string representation for the supplied MPEG-2 level */
+const gchar *
+gst_vaapi_utils_mpeg2_get_level_string (GstVaapiLevelMPEG2 level)
+{
+  if (level < GST_VAAPI_LEVEL_MPEG2_LOW || level > GST_VAAPI_LEVEL_MPEG2_HIGHP)
+    return NULL;
+  return gst_vaapi_mpeg2_level_map[level - GST_VAAPI_LEVEL_MPEG2_LOW].name;
+}
+
+/** Returns level limits as specified in Tables 8-10 to 8-13 of the
+    MPEG-2 standard */
+const GstVaapiMPEG2LevelLimits *
+gst_vaapi_utils_mpeg2_get_level_limits (GstVaapiLevelMPEG2 level)
+{
+  if (level < GST_VAAPI_LEVEL_MPEG2_LOW || level > GST_VAAPI_LEVEL_MPEG2_HIGHP)
+    return NULL;
+  return &gst_vaapi_mpeg2_level_limits[level - GST_VAAPI_LEVEL_MPEG2_LOW];
+}
+
+/** Returns Tables 8-10 to 8-13 from the specification (up to High profile) */
+const GstVaapiMPEG2LevelLimits *
+gst_vaapi_utils_mpeg2_get_level_limits_table (guint * out_length_ptr)
+{
+  if (out_length_ptr)
+    *out_length_ptr = G_N_ELEMENTS (gst_vaapi_mpeg2_level_limits) - 1;
+  return gst_vaapi_mpeg2_level_limits;
+}
+
+/** Returns GstVaapiChromaType from MPEG-2 chroma_format_idc value */
+GstVaapiChromaType
+gst_vaapi_utils_mpeg2_get_chroma_type (guint chroma_format_idc)
+{
+  GstVaapiChromaType chroma_type;
+
+  switch (chroma_format_idc) {
+    case GST_MPEG_VIDEO_CHROMA_420:
+      chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+      break;
+    case GST_MPEG_VIDEO_CHROMA_422:
+      chroma_type = GST_VAAPI_CHROMA_TYPE_YUV422;
+      break;
+    case GST_MPEG_VIDEO_CHROMA_444:
+      chroma_type = GST_VAAPI_CHROMA_TYPE_YUV444;
+      break;
+    default:
+      GST_DEBUG ("unsupported chroma_format_idc value");
+      chroma_type = (GstVaapiChromaType) 0;
+      break;
+  }
+  return chroma_type;
+}
+
+/** Returns MPEG-2 chroma_format_idc value from GstVaapiChromaType */
+guint
+gst_vaapi_utils_mpeg2_get_chroma_format_idc (GstVaapiChromaType chroma_type)
+{
+  guint chroma_format_idc;
+
+  switch (chroma_type) {
+    case GST_VAAPI_CHROMA_TYPE_YUV420:
+      chroma_format_idc = GST_MPEG_VIDEO_CHROMA_420;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV422:
+      chroma_format_idc = GST_MPEG_VIDEO_CHROMA_422;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV444:
+      chroma_format_idc = GST_MPEG_VIDEO_CHROMA_444;
+      break;
+    default:
+      GST_DEBUG ("unsupported GstVaapiChromaType value");
+      chroma_format_idc = 1;
+      break;
+  }
+  return chroma_format_idc;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_mpeg2.h
new file mode 100644 (file)
index 0000000..997011d
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ *  gstvaapiutils_mpeg2.h - MPEG-2 related utilities
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_MPEG2_H
+#define GST_VAAPI_UTILS_MPEG2_H
+
+#include <gst/vaapi/gstvaapiprofile.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstVaapiLevelMPEG2:
+ * @GST_VAAPI_LEVEL_MPEG2_LOW: Low level.
+ * @GST_VAAPI_LEVEL_MPEG2_MAIN: Main level.
+ * @GST_VAAPI_LEVEL_MPEG2_HIGH_1440: High-1440 level.
+ * @GST_VAAPI_LEVEL_MPEG2_HIGH: High level.
+ * @GST_VAAPI_LEVEL_MPEG2_HIGHP: HighP level.
+ *
+ * The set of all levels for #GstVaapiLevelMPEG2.
+ */
+typedef enum {
+  GST_VAAPI_LEVEL_MPEG2_LOW = 1,
+  GST_VAAPI_LEVEL_MPEG2_MAIN,
+  GST_VAAPI_LEVEL_MPEG2_HIGH_1440,
+  GST_VAAPI_LEVEL_MPEG2_HIGH,
+  GST_VAAPI_LEVEL_MPEG2_HIGHP,
+} GstVaapiLevelMPEG2;
+
+/* Returns a relative score for the supplied GstVaapiProfile */
+guint
+gst_vaapi_utils_mpeg2_get_profile_score (GstVaapiProfile profile);
+
+/* Returns GstVaapiProfile from a string representation */
+GstVaapiProfile
+gst_vaapi_utils_mpeg2_get_profile_from_string (const gchar * str);
+
+/* Returns a string representation for the supplied MPEG-2 profile */
+const gchar *
+gst_vaapi_utils_mpeg2_get_profile_string (GstVaapiProfile profile);
+
+/* Returns GstVaapiLevelMPEG2 from a string representation */
+GstVaapiLevelMPEG2
+gst_vaapi_utils_mpeg2_get_level_from_string (const gchar * str);
+
+/* Returns a string representation for the supplied MPEG-2 level */
+const gchar *
+gst_vaapi_utils_mpeg2_get_level_string (GstVaapiLevelMPEG2 level);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UTILS_MPEG2_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_mpeg2_priv.h
new file mode 100644 (file)
index 0000000..3ac65c5
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ *  gstvaapiutils_mpeg2_priv.h - MPEG-2 related utilities
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_MPEG2_PRIV_H
+#define GST_VAAPI_UTILS_MPEG2_PRIV_H
+
+#include "gstvaapiutils_mpeg2.h"
+#include "gstvaapisurface.h"
+
+G_BEGIN_DECLS
+
+/**
+ * GstVaapiMPEG2LevelLimits:
+ * @level: the #GstVaapiLevelMPEG2
+ * @level_idc: the MPEG-2 level indication value
+ * @horizontal_size_value: the maximum number of samples per line
+ * @vertical_size_value: the maximum number of lines per frame
+ * @frame_rate_value: the maximum number of frames per second
+ * @sample_rate: the maximum number of samples per second (for luminance)
+ * @bit_rate: the maximum bit rate (kbps)
+ * @vbv_buffer_size: the VBV buffer size requirements (bits)
+ *
+ * The data structure that describes the limits of an MPEG-2 level.
+ */
+typedef struct {
+  GstVaapiLevelMPEG2 level;
+  guint8 level_idc;
+  guint16 horizontal_size_value;
+  guint16 vertical_size_value;
+  guint32 frame_rate_value;
+  guint32 sample_rate;
+  guint32 bit_rate;
+  guint32 vbv_buffer_size;
+} GstVaapiMPEG2LevelLimits;
+
+/* Returns GstVaapiProfile from MPEG-2 profile_idc value */
+G_GNUC_INTERNAL
+GstVaapiProfile
+gst_vaapi_utils_mpeg2_get_profile (guint8 profile_idc);
+
+/* Returns MPEG-2 profile_idc value from GstVaapiProfile */
+G_GNUC_INTERNAL
+guint8
+gst_vaapi_utils_mpeg2_get_profile_idc (GstVaapiProfile profile);
+
+/* Returns GstVaapiLevelMPEG2 from MPEG-2 level_idc value */
+G_GNUC_INTERNAL
+GstVaapiLevelMPEG2
+gst_vaapi_utils_mpeg2_get_level (guint8 level_idc);
+
+/* Returns MPEG-2 level_idc value from GstVaapiLevelMPEG2 */
+G_GNUC_INTERNAL
+guint8
+gst_vaapi_utils_mpeg2_get_level_idc (GstVaapiLevelMPEG2 level);
+
+/* Returns level limits as specified in Table A-1 of the MPEG-2 standard */
+G_GNUC_INTERNAL
+const GstVaapiMPEG2LevelLimits *
+gst_vaapi_utils_mpeg2_get_level_limits (GstVaapiLevelMPEG2 level);
+
+/* Returns the Table A-1 specification */
+G_GNUC_INTERNAL
+const GstVaapiMPEG2LevelLimits *
+gst_vaapi_utils_mpeg2_get_level_limits_table (guint * out_length_ptr);
+
+/* Returns GstVaapiChromaType from MPEG-2 chroma_format_idc value */
+G_GNUC_INTERNAL
+GstVaapiChromaType
+gst_vaapi_utils_mpeg2_get_chroma_type (guint chroma_format_idc);
+
+/* Returns MPEG-2 chroma_format_idc value from GstVaapiChromaType */
+G_GNUC_INTERNAL
+guint
+gst_vaapi_utils_mpeg2_get_chroma_format_idc (GstVaapiChromaType chroma_type);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UTILS_MPEG2_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_vpx.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_vpx.c
new file mode 100644 (file)
index 0000000..d6bdd81
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ *  gstvaapiutils_vpx.c - vpx related utilities
+ *
+ *  Copyright (C) 2020 Intel Corporation
+ *    Author: He Junyan <junyan.he@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstvaapiutils_vpx.h"
+#include "gstvaapisurface.h"
+
+struct map
+{
+  guint value;
+  const gchar *name;
+};
+
+/* Profile string map */
+static const struct map gst_vaapi_vp9_profile_map[] = {
+  /* *INDENT-OFF* */
+  { GST_VAAPI_PROFILE_VP9_0, "0" },
+  { GST_VAAPI_PROFILE_VP9_1, "1" },
+  { GST_VAAPI_PROFILE_VP9_2, "2" },
+  { GST_VAAPI_PROFILE_VP9_3, "3" },
+  { 0, NULL }
+  /* *INDENT-ON* */
+};
+
+/* Lookup name in map */
+static const struct map *
+map_lookup_name (const struct map *m, const gchar * name)
+{
+  g_return_val_if_fail (m != NULL, NULL);
+
+  if (!name)
+    return NULL;
+
+  for (; m->name != NULL; m++) {
+    if (strcmp (m->name, name) == 0)
+      return m;
+  }
+  return NULL;
+}
+
+/* Lookup value in map */
+static const struct map *
+map_lookup_value (const struct map *m, guint value)
+{
+  g_return_val_if_fail (m != NULL, NULL);
+
+  for (; m->name != NULL; m++) {
+    if (m->value == value)
+      return m;
+  }
+  return NULL;
+}
+
+/** Returns GstVaapiProfile from a string representation */
+GstVaapiProfile
+gst_vaapi_utils_vp9_get_profile_from_string (const gchar * str)
+{
+  const struct map *const m = map_lookup_name (gst_vaapi_vp9_profile_map, str);
+
+  return m ? (GstVaapiProfile) m->value : GST_VAAPI_PROFILE_UNKNOWN;
+}
+
+/** Returns a string representation for the supplied VP9 profile */
+const gchar *
+gst_vaapi_utils_vp9_get_profile_string (GstVaapiProfile profile)
+{
+  const struct map *const m =
+      map_lookup_value (gst_vaapi_vp9_profile_map, profile);
+
+  return m ? m->name : NULL;
+}
+
+/** Returns VP9 chroma_format_idc value from GstVaapiChromaType */
+guint
+gst_vaapi_utils_vp9_get_chroma_format_idc (guint chroma_type)
+{
+  guint chroma_format_idc;
+
+  switch (chroma_type) {
+    case GST_VAAPI_CHROMA_TYPE_YUV400:
+      chroma_format_idc = 0;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV420:
+    case GST_VAAPI_CHROMA_TYPE_YUV420_10BPP:
+      chroma_format_idc = 1;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV422:
+    case GST_VAAPI_CHROMA_TYPE_YUV422_10BPP:
+      chroma_format_idc = 2;
+      break;
+    case GST_VAAPI_CHROMA_TYPE_YUV444:
+    case GST_VAAPI_CHROMA_TYPE_YUV444_10BPP:
+      chroma_format_idc = 3;
+      break;
+    default:
+      GST_DEBUG ("unsupported GstVaapiChromaType value");
+      chroma_format_idc = 1;
+      break;
+  }
+  return chroma_format_idc;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_vpx.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_vpx.h
new file mode 100644 (file)
index 0000000..acead5a
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ *  gstvaapiutils_vpx.h - vpx related utilities
+ *
+ *  Copyright (C) 2020 Intel Corporation
+ *    Author: He Junyan <junyan.he@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_VPX_H
+#define GST_VAAPI_UTILS_VPX_H
+
+#include <gst/vaapi/gstvaapiprofile.h>
+
+G_BEGIN_DECLS
+
+/** Returns GstVaapiProfile from a string representation */
+GstVaapiProfile
+gst_vaapi_utils_vp9_get_profile_from_string (const gchar * str);
+
+/** Returns a string representation for the supplied VP9 profile */
+const gchar *
+gst_vaapi_utils_vp9_get_profile_string (GstVaapiProfile profile);
+
+guint
+gst_vaapi_utils_vp9_get_chroma_format_idc (guint chroma_type);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_UTILS_VPX_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_x11.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_x11.c
new file mode 100644 (file)
index 0000000..741b9b3
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *  gstvaapiutils_x11.c - X11 utilties
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "sysdeps.h"
+#include <glib.h>
+#include <X11/Xutil.h>
+#include "gstvaapiutils_x11.h"
+
+// X error trap
+static int x11_error_code = 0;
+static int (*old_error_handler) (Display *, XErrorEvent *);
+
+static int
+error_handler (Display * dpy, XErrorEvent * error)
+{
+  x11_error_code = error->error_code;
+  return 0;
+}
+
+void
+x11_trap_errors (void)
+{
+  x11_error_code = 0;
+  old_error_handler = XSetErrorHandler (error_handler);
+}
+
+int
+x11_untrap_errors (void)
+{
+  XSetErrorHandler (old_error_handler);
+  return x11_error_code;
+}
+
+// X window management
+static const int x11_event_mask = (KeyPressMask | KeyReleaseMask
+    | ButtonPressMask | ButtonReleaseMask | PointerMotionMask
+    | EnterWindowMask | ExposureMask | StructureNotifyMask);
+
+/**
+ * x11_create_window:
+ * @dpy: an X11 #Display
+ * @w: the requested width, in pixels
+ * @h: the requested height, in pixels
+ * @vid: the requested visual id
+ * @cmap: the requested colormap
+ *
+ * Creates a border-less window with the specified dimensions. If @vid
+ * is zero, the default visual for @display will be used. If @cmap is
+ * %None, no specific colormap will be bound to the window. Also note
+ * the default background color is black.
+ *
+ * Return value: the newly created X Window.
+ */
+Window
+x11_create_window (Display * dpy, guint w, guint h, guint vid, Colormap cmap)
+{
+  Window rootwin, win;
+  int screen, depth;
+  XSetWindowAttributes xswa;
+  unsigned long xswa_mask;
+  XWindowAttributes wattr;
+  unsigned long black_pixel;
+  XVisualInfo visualInfo, *vi;
+  int num_visuals;
+
+  screen = DefaultScreen (dpy);
+  rootwin = RootWindow (dpy, screen);
+  black_pixel = BlackPixel (dpy, screen);
+
+  XGetWindowAttributes (dpy, rootwin, &wattr);
+  depth = wattr.depth;
+  if (depth != 15 && depth != 16 && depth != 24 && depth != 30 && depth != 32)
+    depth = 24;
+
+  xswa_mask = CWBorderPixel | CWBackPixel;
+  xswa.border_pixel = black_pixel;
+  xswa.background_pixel = black_pixel;
+
+  if (cmap) {
+    xswa_mask |= CWColormap;
+    xswa.colormap = cmap;
+  }
+
+  if (vid) {
+    visualInfo.visualid = vid;
+    vi = XGetVisualInfo (dpy, VisualIDMask, &visualInfo, &num_visuals);
+    if (!vi || num_visuals < 1)
+      goto error_create_visual;
+  } else {
+    vi = &visualInfo;
+    XMatchVisualInfo (dpy, screen, depth, TrueColor, vi);
+  }
+
+  win = XCreateWindow (dpy, rootwin, 0, 0, w, h, 0, depth, InputOutput,
+      vi->visual, xswa_mask, &xswa);
+  if (vi != &visualInfo)
+    XFree (vi);
+  if (!win)
+    goto error_create_window;
+
+  XSelectInput (dpy, win, x11_event_mask);
+  return win;
+
+  /* ERRORS */
+error_create_visual:
+  GST_ERROR ("failed to create X visual (id:%zu)", (gsize) visualInfo.visualid);
+  if (vi)
+    XFree (vi);
+  return None;
+error_create_window:
+  GST_ERROR ("failed to create X window of size %ux%u", w, h);
+  return None;
+}
+
+gboolean
+x11_get_geometry (Display * dpy, Drawable drawable, gint * px, gint * py,
+    guint * pwidth, guint * pheight, guint * pdepth)
+{
+  Window rootwin;
+  int x, y;
+  guint width, height, border_width, depth;
+
+  x11_trap_errors ();
+  XGetGeometry (dpy, drawable, &rootwin, &x, &y, &width, &height,
+      &border_width, &depth);
+  if (x11_untrap_errors ())
+    return FALSE;
+
+  if (px)
+    *px = x;
+  if (py)
+    *py = y;
+  if (pwidth)
+    *pwidth = width;
+  if (pheight)
+    *pheight = height;
+  if (pdepth)
+    *pdepth = depth;
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_x11.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiutils_x11.h
new file mode 100644 (file)
index 0000000..b205585
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ *  gstvaapiutils_x11.h - X11 utilties
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_UTILS_X11_H
+#define GST_VAAPI_UTILS_X11_H
+
+#include "config.h"
+#include <X11/Xlib.h>
+#include <glib.h>
+
+G_GNUC_INTERNAL
+void
+x11_trap_errors (void);
+
+G_GNUC_INTERNAL
+int
+x11_untrap_errors (void);
+
+G_GNUC_INTERNAL
+Window
+x11_create_window (Display * dpy, guint w, guint h, guint vid, Colormap cmap);
+
+G_GNUC_INTERNAL
+gboolean
+x11_get_geometry (Display * dpy, Drawable drawable, gint * px, gint * py,
+    guint * pwidth, guint * pheight, guint * pdepth);
+
+#endif /* GST_VAAPI_UTILS_X11_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivalue.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivalue.c
new file mode 100644 (file)
index 0000000..8a597b2
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ *  gstvaapivalue.c - GValue implementations specific to VA-API
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapivalue
+ * @short_description: GValue implementations specific to VA-API
+ */
+
+#include "sysdeps.h"
+#include <gobject/gvaluecollector.h>
+#include "gstvaapivalue.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+static gpointer
+default_copy_func (gpointer data)
+{
+  return data;
+}
+
+static void
+default_free_func (gpointer data)
+{
+}
+
+/* --- GstVaapiPoint --- */
+
+GType
+gst_vaapi_point_get_type (void)
+{
+  static gsize g_type = 0;
+
+  if (g_once_init_enter (&g_type)) {
+    GType type =
+        g_boxed_type_register_static (g_intern_static_string ("GstVaapiPoint"),
+        default_copy_func, default_free_func);
+    gst_type_mark_as_plugin_api (type, 0);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+/* --- GstVaapiRectangle --- */
+
+GType
+gst_vaapi_rectangle_get_type (void)
+{
+  static gsize g_type = 0;
+
+  if (g_once_init_enter (&g_type)) {
+    GType type =
+        g_boxed_type_register_static (g_intern_static_string
+        ("GstVaapiRectangle"),
+        default_copy_func, default_free_func);
+    gst_type_mark_as_plugin_api (type, 0);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+/* --- GstVaapiRenderMode --- */
+
+GType
+gst_vaapi_render_mode_get_type (void)
+{
+  static gsize g_type = 0;
+
+  static const GEnumValue render_modes[] = {
+    {GST_VAAPI_RENDER_MODE_OVERLAY,
+        "Overlay render mode", "overlay"},
+    {GST_VAAPI_RENDER_MODE_TEXTURE,
+        "Textured-blit render mode", "texture"},
+    {0, NULL, NULL}
+  };
+
+  if (g_once_init_enter (&g_type)) {
+    GType type = g_enum_register_static ("GstVaapiRenderMode", render_modes);
+    gst_type_mark_as_plugin_api (type, 0);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+/* --- GstVaapiRotation --- */
+
+GType
+gst_vaapi_rotation_get_type (void)
+{
+  static gsize g_type = 0;
+
+  static const GEnumValue rotation_values[] = {
+    {GST_VAAPI_ROTATION_0,
+        "Unrotated mode", "0"},
+    {GST_VAAPI_ROTATION_90,
+        "Rotated by 90°, clockwise", "90"},
+    {GST_VAAPI_ROTATION_180,
+        "Rotated by 180°, clockwise", "180"},
+    {GST_VAAPI_ROTATION_270,
+        "Rotated by 270°, clockwise", "270"},
+    {GST_VAAPI_ROTATION_AUTOMATIC,
+        "Rotated by image-orientating tag°", "Automatic"},
+    {0, NULL, NULL},
+  };
+
+  if (g_once_init_enter (&g_type)) {
+    GType type = g_enum_register_static ("GstVaapiRotation", rotation_values);
+    gst_type_mark_as_plugin_api (type, 0);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+/* --- GstVaapiRateControl --- */
+
+GType
+gst_vaapi_rate_control_get_type (void)
+{
+  static gsize g_type = 0;
+
+  static const GEnumValue rate_control_values[] = {
+    {GST_VAAPI_RATECONTROL_NONE,
+        "None", "none"},
+    {GST_VAAPI_RATECONTROL_CQP,
+        "Constant QP", "cqp"},
+    {GST_VAAPI_RATECONTROL_CBR,
+        "Constant bitrate", "cbr"},
+    {GST_VAAPI_RATECONTROL_VCM,
+        "Video conference", "vcm"},
+    {GST_VAAPI_RATECONTROL_VBR,
+        "Variable bitrate", "vbr"},
+    {GST_VAAPI_RATECONTROL_VBR_CONSTRAINED,
+        "Variable bitrate - Constrained", "vbr_constrained"},
+    {GST_VAAPI_RATECONTROL_MB,
+        "Macroblock based rate control", "mb"},
+    {GST_VAAPI_RATECONTROL_ICQ,
+        "Constant QP - Intelligent", "icq"},
+    {GST_VAAPI_RATECONTROL_QVBR,
+        "Variable bitrate - Quality defined", "qvbr"},
+    {0, NULL, NULL},
+  };
+
+  if (g_once_init_enter (&g_type)) {
+    GType type = g_enum_register_static ("GstVaapiRateControl",
+        rate_control_values);
+    gst_type_mark_as_plugin_api (type, 0);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+static gboolean
+build_enum_subset_values_from_mask (GstVaapiEnumSubset * subset, guint32 mask)
+{
+  GEnumClass *enum_class;
+  const GEnumValue *value;
+  guint i, n;
+
+  enum_class = g_type_class_ref (subset->parent_type);
+  if (!enum_class)
+    return FALSE;
+
+  for (i = 0, n = 0; i < 32 && n < subset->num_values; i++) {
+    if (!(mask & (1U << i)))
+      continue;
+    value = g_enum_get_value (enum_class, i);
+    if (!value)
+      continue;
+    subset->values[n++] = *value;
+  }
+  g_type_class_unref (enum_class);
+  if (n != subset->num_values - 1)
+    goto error_invalid_num_values;
+  return TRUE;
+
+  /* ERRORS */
+error_invalid_num_values:
+  {
+    GST_ERROR ("invalid number of static values for `%s'", subset->type_name);
+    return FALSE;
+  }
+}
+
+GType
+gst_vaapi_type_define_enum_subset_from_mask (GstVaapiEnumSubset * subset,
+    guint32 mask)
+{
+  if (g_once_init_enter (&subset->type)) {
+    GType type;
+
+    build_enum_subset_values_from_mask (subset, mask);
+    memset (&subset->type_info, 0, sizeof (subset->type_info));
+    g_enum_complete_type_info (subset->parent_type, &subset->type_info,
+        subset->values);
+
+    type = g_type_register_static (G_TYPE_ENUM, subset->type_name,
+        &subset->type_info, 0);
+    g_once_init_leave (&subset->type, type);
+  }
+  return subset->type;
+}
+
+/**
+ * gst_vaapi_enum_type_get_nick:
+ * @type: an enum #GType
+ * @value: the value to get its nick
+ *
+ * Returns: (transfer none); the string associated with
+ *   @value. Otherwise "<unknown>"
+ **/
+const gchar *
+gst_vaapi_enum_type_get_nick (GType type, gint value)
+{
+  gpointer const klass = g_type_class_peek (type);
+  GEnumValue *const e = g_enum_get_value (klass, value);
+
+  if (e)
+    return e->value_nick;
+  return "<unknown>";
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivalue.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivalue.h
new file mode 100644 (file)
index 0000000..f462671
--- /dev/null
@@ -0,0 +1,166 @@
+/*
+ *  gstvaapivalue.h - GValue implementations specific to VA-API
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VALUE_H
+#define GST_VAAPI_VALUE_H
+
+#include <glib-object.h>
+#include <gst/vaapi/gstvaapitypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GST_VAAPI_TYPE_POINT:
+ *
+ * A #GstVaapiPoint type that represents a 2D point coordinates.
+ *
+ * Return value: the GType of #GstVaapiPoint
+ */
+#define GST_VAAPI_TYPE_POINT gst_vaapi_point_get_type()
+
+/**
+ * GST_VAAPI_TYPE_RECTANGLE:
+ *
+ * A #GstVaapiRectangle type that represents a 2D rectangle position
+ * and size.
+ *
+ * Return value: the GType of #GstVaapiRectangle
+ */
+#define GST_VAAPI_TYPE_RECTANGLE gst_vaapi_rectangle_get_type()
+
+/**
+ * GST_VAAPI_TYPE_RENDER_MODE:
+ *
+ * A #GstVaapiRenderMode type that represents the VA display backend
+ * rendering mode: overlay (2D engine) or textured-blit (3D engine).
+ *
+ * Return value: the #GType of GstVaapiRenderMode
+ */
+#define GST_VAAPI_TYPE_RENDER_MODE gst_vaapi_render_mode_get_type()
+
+/**
+ * GST_VAAPI_TYPE_ROTATION:
+ *
+ * A type that represents the VA display rotation.
+ *
+ * Return value: the #GType of GstVaapiRotation
+ */
+#define GST_VAAPI_TYPE_ROTATION gst_vaapi_rotation_get_type()
+
+/**
+ * GST_VAAPI_TYPE_RATE_CONTROL:
+ *
+ * A type that represents the VA rate control.
+ *
+ * Return value: the #GType of GstVaapiRateControl
+ */
+#define GST_VAAPI_TYPE_RATE_CONTROL gst_vaapi_rate_control_get_type()
+
+GType
+gst_vaapi_point_get_type(void) G_GNUC_CONST;
+
+GType
+gst_vaapi_rectangle_get_type(void) G_GNUC_CONST;
+
+GType
+gst_vaapi_render_mode_get_type(void) G_GNUC_CONST;
+
+GType
+gst_vaapi_rotation_get_type(void) G_GNUC_CONST;
+
+GType
+gst_vaapi_rate_control_get_type(void) G_GNUC_CONST;
+
+/**
+ * GST_VAAPI_POPCOUNT32:
+ * @x: the value from which to compute population count
+ *
+ * Computes the number of bits set in the supplied 32-bit value @x.
+ *
+ * Return value: the number of bits set in @x
+ */
+#define GST_VAAPI_POPCOUNT32(x) \
+    GST_VAAPI_POPCOUNT32_0(x)
+#define GST_VAAPI_POPCOUNT32_0(x) \
+    GST_VAAPI_POPCOUNT32_1((x) - (((x) >> 1) & 0x55555555))
+#define GST_VAAPI_POPCOUNT32_1(x) \
+    GST_VAAPI_POPCOUNT32_2(((x) & 0x33333333) + (((x) >> 2) & 0x33333333))
+#define GST_VAAPI_POPCOUNT32_2(x) \
+    GST_VAAPI_POPCOUNT32_3((x) + ((x) >> 4))
+#define GST_VAAPI_POPCOUNT32_3(x) \
+    GST_VAAPI_POPCOUNT32_4((x) & 0x0f0f0f0f)
+#define GST_VAAPI_POPCOUNT32_4(x) \
+    (((x) * 0x01010101) >> 24)
+
+/* --- GstVaapiEnumSubset --- */
+
+/**
+ * GstVaapiEnumSubset:
+ * @name: name of the enum subset
+ * @parent_type: parent enum type
+ * @type: registered #GType
+ * @type_info: #GTypeInfo used to build the @type
+ * @values: pointer to a static array of #GEnumValue elements
+ * @num_values: number of elements in the @values array, including the
+ *   terminator
+ *
+ * Structure that holds the required information to build a GEnum
+ * subset from the supplied @parent_type, i.e. a subset of its values.
+ */
+typedef struct {
+    GType parent_type;
+    GType type;
+    GTypeInfo type_info;
+    const gchar *type_name;
+    GEnumValue *values;
+    guint num_values;
+} GstVaapiEnumSubset;
+
+G_GNUC_INTERNAL
+GType
+gst_vaapi_type_define_enum_subset_from_mask(GstVaapiEnumSubset *subset,
+    guint32 mask);
+
+#define GST_VAAPI_TYPE_DEFINE_ENUM_SUBSET_FROM_MASK(NAME, name, TYPE, MASK) \
+static GType                                                            \
+G_PASTE(name,_get_type)(void)                                           \
+{                                                                       \
+    static GEnumValue enum_values[GST_VAAPI_POPCOUNT32(MASK) + 1];      \
+    static GstVaapiEnumSubset subset = {                                \
+        .type_name = G_STRINGIFY(NAME),                                 \
+        .values = enum_values,                                          \
+        .num_values = G_N_ELEMENTS(enum_values),                        \
+    };                                                                  \
+    if (g_once_init_enter(&subset.parent_type))                         \
+        g_once_init_leave(&subset.parent_type, TYPE);                   \
+    return gst_vaapi_type_define_enum_subset_from_mask(&subset, MASK);  \
+}
+
+G_GNUC_INTERNAL
+const gchar *
+gst_vaapi_enum_type_get_nick (GType type, gint value);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_VALUE_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivideopool.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivideopool.c
new file mode 100644 (file)
index 0000000..8c9c10e
--- /dev/null
@@ -0,0 +1,423 @@
+/*
+ *  gstvaapivideopool.c - Video object pool abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapivideopool
+ * @short_description: Video object pool abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapivideopool.h"
+#include "gstvaapivideopool_priv.h"
+
+#define DEBUG 1
+#include "gstvaapidebug.h"
+
+#define GST_VAAPI_VIDEO_POOL_GET_CLASS(obj) \
+  gst_vaapi_video_pool_get_class (GST_VAAPI_VIDEO_POOL (obj))
+
+static inline const GstVaapiVideoPoolClass *
+gst_vaapi_video_pool_get_class (GstVaapiVideoPool * pool)
+{
+  return GST_VAAPI_VIDEO_POOL_CLASS (GST_VAAPI_MINI_OBJECT_GET_CLASS (pool));
+}
+
+static inline gpointer
+gst_vaapi_video_pool_alloc_object (GstVaapiVideoPool * pool)
+{
+  return GST_VAAPI_VIDEO_POOL_GET_CLASS (pool)->alloc_object (pool);
+}
+
+void
+gst_vaapi_video_pool_init (GstVaapiVideoPool * pool, GstVaapiDisplay * display,
+    GstVaapiVideoPoolObjectType object_type)
+{
+  pool->object_type = object_type;
+  pool->display = gst_object_ref (display);
+  pool->used_objects = NULL;
+  pool->used_count = 0;
+  pool->capacity = 0;
+
+  g_queue_init (&pool->free_objects);
+  g_mutex_init (&pool->mutex);
+}
+
+void
+gst_vaapi_video_pool_finalize (GstVaapiVideoPool * pool)
+{
+  g_list_free_full (pool->used_objects, (GDestroyNotify) gst_mini_object_unref);
+  g_queue_foreach (&pool->free_objects, (GFunc) gst_mini_object_unref, NULL);
+  g_queue_clear (&pool->free_objects);
+  gst_vaapi_display_replace (&pool->display, NULL);
+  g_mutex_clear (&pool->mutex);
+}
+
+/**
+ * gst_vaapi_video_pool_ref:
+ * @pool: a #GstVaapiVideoPool
+ *
+ * Atomically increases the reference count of the given @pool by one.
+ *
+ * Returns: The same @pool argument
+ */
+GstVaapiVideoPool *
+gst_vaapi_video_pool_ref (GstVaapiVideoPool * pool)
+{
+  return (GstVaapiVideoPool *)
+      gst_vaapi_mini_object_ref (GST_VAAPI_MINI_OBJECT (pool));
+}
+
+/**
+ * gst_vaapi_video_pool_unref:
+ * @pool: a #GstVaapiVideoPool
+ *
+ * Atomically decreases the reference count of the @pool by one. If
+ * the reference count reaches zero, the pool will be free'd.
+ */
+void
+gst_vaapi_video_pool_unref (GstVaapiVideoPool * pool)
+{
+  gst_vaapi_mini_object_unref (GST_VAAPI_MINI_OBJECT (pool));
+}
+
+/**
+ * gst_vaapi_video_pool_replace:
+ * @old_pool_ptr: a pointer to a #GstVaapiVideoPool
+ * @new_pool: a #GstVaapiVideoPool
+ *
+ * Atomically replaces the pool pool held in @old_pool_ptr with
+ * @new_pool. This means that @old_pool_ptr shall reference a valid
+ * pool. However, @new_pool can be NULL.
+ */
+void
+gst_vaapi_video_pool_replace (GstVaapiVideoPool ** old_pool_ptr,
+    GstVaapiVideoPool * new_pool)
+{
+  gst_vaapi_mini_object_replace ((GstVaapiMiniObject **) (old_pool_ptr),
+      GST_VAAPI_MINI_OBJECT (new_pool));
+}
+
+/**
+ * gst_vaapi_video_pool_get_display:
+ * @pool: a #GstVaapiVideoPool
+ *
+ * Retrieves the #GstVaapiDisplay the @pool is bound to. The @pool
+ * owns the returned object and it shall not be unref'ed.
+ *
+ * Return value: the #GstVaapiDisplay the @pool is bound to
+ */
+GstVaapiDisplay *
+gst_vaapi_video_pool_get_display (GstVaapiVideoPool * pool)
+{
+  g_return_val_if_fail (pool != NULL, NULL);
+
+  return pool->display;
+}
+
+/**
+ * gst_vaapi_video_pool_get_object_type:
+ * @pool: a #GstVaapiVideoPool
+ *
+ * Retrieves the type of objects the video @pool supports.
+ *
+ * Return value: the #GstVaapiVideoPoolObjectType of the underlying pool
+ *   objects
+ */
+GstVaapiVideoPoolObjectType
+gst_vaapi_video_pool_get_object_type (GstVaapiVideoPool * pool)
+{
+  g_return_val_if_fail (pool != NULL, (GstVaapiVideoPoolObjectType) 0);
+
+  return pool->object_type;
+}
+
+/**
+ * gst_vaapi_video_pool_get_object:
+ * @pool: a #GstVaapiVideoPool
+ *
+ * Retrieves a new object from the @pool, or allocates a new one if
+ * none was found. The @pool holds a reference on the returned object
+ * and thus shall be released through gst_vaapi_video_pool_put_object()
+ * when it's no longer needed.
+ *
+ * Return value: a possibly newly allocated object, or %NULL on error
+ */
+static gpointer
+gst_vaapi_video_pool_get_object_unlocked (GstVaapiVideoPool * pool)
+{
+  gpointer object;
+
+  if (pool->capacity && pool->used_count >= pool->capacity)
+    return NULL;
+
+  object = g_queue_pop_head (&pool->free_objects);
+  if (!object) {
+    g_mutex_unlock (&pool->mutex);
+    object = gst_vaapi_video_pool_alloc_object (pool);
+    g_mutex_lock (&pool->mutex);
+    if (!object)
+      return NULL;
+
+    /* Others already allocated a new one before us during we
+       release the mutex */
+    if (pool->capacity && pool->used_count >= pool->capacity) {
+      gst_mini_object_unref (object);
+      return NULL;
+    }
+  }
+
+  ++pool->used_count;
+  pool->used_objects = g_list_prepend (pool->used_objects, object);
+  return gst_mini_object_ref (object);
+}
+
+gpointer
+gst_vaapi_video_pool_get_object (GstVaapiVideoPool * pool)
+{
+  gpointer object;
+
+  g_return_val_if_fail (pool != NULL, NULL);
+
+  g_mutex_lock (&pool->mutex);
+  object = gst_vaapi_video_pool_get_object_unlocked (pool);
+  g_mutex_unlock (&pool->mutex);
+  return object;
+}
+
+/**
+ * gst_vaapi_video_pool_put_object:
+ * @pool: a #GstVaapiVideoPool
+ * @object: the object to add back to the pool
+ *
+ * Pushes the @object back into the pool. The @object shall be
+ * obtained from the @pool through gst_vaapi_video_pool_get_object().
+ * Calling this function with an arbitrary object yields undefined
+ * behaviour.
+ */
+static void
+gst_vaapi_video_pool_put_object_unlocked (GstVaapiVideoPool * pool,
+    gpointer object)
+{
+  GList *elem;
+
+  elem = g_list_find (pool->used_objects, object);
+  if (!elem)
+    return;
+
+  gst_mini_object_unref (object);
+  --pool->used_count;
+  pool->used_objects = g_list_delete_link (pool->used_objects, elem);
+  g_queue_push_tail (&pool->free_objects, object);
+}
+
+void
+gst_vaapi_video_pool_put_object (GstVaapiVideoPool * pool, gpointer object)
+{
+  g_return_if_fail (pool != NULL);
+  g_return_if_fail (object != NULL);
+
+  g_mutex_lock (&pool->mutex);
+  gst_vaapi_video_pool_put_object_unlocked (pool, object);
+  g_mutex_unlock (&pool->mutex);
+}
+
+/**
+ * gst_vaapi_video_pool_add_object:
+ * @pool: a #GstVaapiVideoPool
+ * @object: the object to add to the pool
+ *
+ * Adds the @object to the pool. The pool then holds a reference on
+ * the @object. This operation does not change the capacity of the
+ * pool.
+ *
+ * Return value: %TRUE on success.
+ */
+static inline gboolean
+gst_vaapi_video_pool_add_object_unlocked (GstVaapiVideoPool * pool,
+    gpointer object)
+{
+  g_queue_push_tail (&pool->free_objects, gst_mini_object_ref (object));
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_video_pool_add_object (GstVaapiVideoPool * pool, gpointer object)
+{
+  gboolean success;
+
+  g_return_val_if_fail (pool != NULL, FALSE);
+  g_return_val_if_fail (object != NULL, FALSE);
+
+  g_mutex_lock (&pool->mutex);
+  success = gst_vaapi_video_pool_add_object_unlocked (pool, object);
+  g_mutex_unlock (&pool->mutex);
+  return success;
+}
+
+/**
+ * gst_vaapi_video_pool_add_objects:
+ * @pool: a #GstVaapiVideoPool
+ * @objects: a #GPtrArray of objects
+ *
+ * Adds the @objects to the pool. The pool then holds a reference on
+ * the @objects. This operation does not change the capacity of the
+ * pool and is just a wrapper around gst_vaapi_video_pool_add_object().
+ *
+ * Return value: %TRUE on success.
+ */
+static gboolean
+gst_vaapi_video_pool_add_objects_unlocked (GstVaapiVideoPool * pool,
+    GPtrArray * objects)
+{
+  guint i;
+
+  for (i = 0; i < objects->len; i++) {
+    gpointer const object = g_ptr_array_index (objects, i);
+    if (!gst_vaapi_video_pool_add_object_unlocked (pool, object))
+      return FALSE;
+  }
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_video_pool_add_objects (GstVaapiVideoPool * pool, GPtrArray * objects)
+{
+  gboolean success;
+
+  g_return_val_if_fail (pool != NULL, FALSE);
+
+  g_mutex_lock (&pool->mutex);
+  success = gst_vaapi_video_pool_add_objects_unlocked (pool, objects);
+  g_mutex_unlock (&pool->mutex);
+  return success;
+}
+
+/**
+ * gst_vaapi_video_pool_get_size:
+ * @pool: a #GstVaapiVideoPool
+ *
+ * Returns the number of free objects available in the pool.
+ *
+ * Return value: number of free objects in the pool
+ */
+guint
+gst_vaapi_video_pool_get_size (GstVaapiVideoPool * pool)
+{
+  guint size;
+
+  g_return_val_if_fail (pool != NULL, 0);
+
+  g_mutex_lock (&pool->mutex);
+  size = g_queue_get_length (&pool->free_objects);
+  g_mutex_unlock (&pool->mutex);
+  return size;
+}
+
+static gboolean
+gst_vaapi_video_pool_reserve_unlocked (GstVaapiVideoPool * pool, guint n)
+{
+  guint i, num_allocated;
+
+  num_allocated = g_queue_get_length (&pool->free_objects) + pool->used_count;
+  if (n <= num_allocated)
+    return TRUE;
+
+  n = MIN (n, pool->capacity);
+  for (i = num_allocated; i < n; i++) {
+    gpointer object;
+
+    g_mutex_unlock (&pool->mutex);
+    object = gst_vaapi_video_pool_alloc_object (pool);
+    g_mutex_lock (&pool->mutex);
+    if (!object)
+      return FALSE;
+    g_queue_push_tail (&pool->free_objects, object);
+  }
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_video_pool_reserve:
+ * @pool: a #GstVaapiVideoPool
+ * @n: the number of objects to pre-allocate
+ *
+ * Pre-allocates up to @n objects in the pool. If @n is less than or
+ * equal to the number of free and used objects in the pool, this call
+ * has no effect. Otherwise, it is a request for allocation of
+ * additional objects.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_video_pool_reserve (GstVaapiVideoPool * pool, guint n)
+{
+  gboolean success;
+
+  g_return_val_if_fail (pool != NULL, 0);
+
+  g_mutex_lock (&pool->mutex);
+  success = gst_vaapi_video_pool_reserve_unlocked (pool, n);
+  g_mutex_unlock (&pool->mutex);
+  return success;
+}
+
+/**
+ * gst_vaapi_video_pool_get_capacity:
+ * @pool: a #GstVaapiVideoPool
+ *
+ * Returns the maximum number of objects in the pool. i.e. the maximum
+ * number of objects that can be returned by gst_vaapi_video_pool_get_object().
+ *
+ * Return value: the capacity of the pool
+ */
+guint
+gst_vaapi_video_pool_get_capacity (GstVaapiVideoPool * pool)
+{
+  guint capacity;
+
+  g_return_val_if_fail (pool != NULL, 0);
+
+  g_mutex_lock (&pool->mutex);
+  capacity = pool->capacity;
+  g_mutex_unlock (&pool->mutex);
+
+  return capacity;
+}
+
+/**
+ * gst_vaapi_video_pool_set_capacity:
+ * @pool: a #GstVaapiVideoPool
+ * @capacity: the maximal capacity of the pool
+ *
+ * Sets the maximum number of objects that can be allocated in the pool.
+ */
+void
+gst_vaapi_video_pool_set_capacity (GstVaapiVideoPool * pool, guint capacity)
+{
+  g_return_if_fail (pool != NULL);
+
+  g_mutex_lock (&pool->mutex);
+  pool->capacity = capacity;
+  g_mutex_unlock (&pool->mutex);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivideopool.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivideopool.h
new file mode 100644 (file)
index 0000000..393de7b
--- /dev/null
@@ -0,0 +1,96 @@
+/*
+ *  gstvaapivideopool.h - Video object pool abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VIDEO_POOL_H
+#define GST_VAAPI_VIDEO_POOL_H
+
+#include <glib.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_VIDEO_POOL(obj) \
+  ((GstVaapiVideoPool *)(obj))
+
+typedef struct _GstVaapiVideoPool GstVaapiVideoPool;
+
+/**
+ * GstVaapiVideoPoolObjectType:
+ * @GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE: #GstVaapiImage objects.
+ * @GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_SURFACE: #GstVaapiSurface objects.
+ * @GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_CODED_BUFFER: #GstVaapiCodedBuffer objects.
+ *
+ * The set of all supported #GstVaapiVideoPool object types.
+ */
+typedef enum
+{
+  GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE = 1,
+  GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_SURFACE,
+  GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_CODED_BUFFER
+} GstVaapiVideoPoolObjectType;
+
+GstVaapiVideoPool *
+gst_vaapi_video_pool_ref (GstVaapiVideoPool * pool);
+
+void
+gst_vaapi_video_pool_unref (GstVaapiVideoPool * pool);
+
+void
+gst_vaapi_video_pool_replace (GstVaapiVideoPool ** old_pool_ptr,
+    GstVaapiVideoPool * new_pool);
+
+GstVaapiDisplay *
+gst_vaapi_video_pool_get_display (GstVaapiVideoPool * pool);
+
+GstVaapiVideoPoolObjectType
+gst_vaapi_video_pool_get_object_type (GstVaapiVideoPool * pool);
+
+gpointer
+gst_vaapi_video_pool_get_object (GstVaapiVideoPool * pool);
+
+void
+gst_vaapi_video_pool_put_object (GstVaapiVideoPool * pool, gpointer object);
+
+gboolean
+gst_vaapi_video_pool_add_object (GstVaapiVideoPool * pool, gpointer object);
+
+gboolean
+gst_vaapi_video_pool_add_objects (GstVaapiVideoPool * pool,
+    GPtrArray * objects);
+
+guint
+gst_vaapi_video_pool_get_size (GstVaapiVideoPool * pool);
+
+gboolean
+gst_vaapi_video_pool_reserve (GstVaapiVideoPool * pool, guint n);
+
+guint
+gst_vaapi_video_pool_get_capacity (GstVaapiVideoPool * pool);
+
+void
+gst_vaapi_video_pool_set_capacity (GstVaapiVideoPool * pool, guint capacity);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_VIDEO_POOL_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivideopool_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapivideopool_priv.h
new file mode 100644 (file)
index 0000000..1d5115a
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *  gstvaapivideopool_priv.h - Video object pool abstraction (private defs)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VIDEO_POOL_PRIV_H
+#define GST_VAAPI_VIDEO_POOL_PRIV_H
+
+#include "gstvaapiminiobject.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_VIDEO_POOL_CLASS(klass) \
+  ((GstVaapiVideoPoolClass *)(klass))
+#define GST_VAAPI_IS_VIDEO_POOL_CLASS(klass)    \
+  ((klass) != NULL)
+
+typedef struct _GstVaapiVideoPoolClass GstVaapiVideoPoolClass;
+
+/**
+ * GstVaapiVideoPool:
+ *
+ * A pool of lazily allocated video objects. e.g. surfaces, images.
+ */
+struct _GstVaapiVideoPool
+{
+  /*< private >*/
+  GstVaapiMiniObject parent_instance;
+
+  guint object_type;
+  GstVaapiDisplay *display;
+  GQueue free_objects;
+  GList *used_objects;
+  guint used_count;
+  guint capacity;
+  GMutex mutex;
+};
+
+/**
+ * GstVaapiVideoPoolClass:
+ * @alloc_object: virtual function for allocating a video pool object
+ *
+ * A pool base class used to hold video objects. e.g. surfaces, images.
+ */
+struct _GstVaapiVideoPoolClass
+{
+  /*< private >*/
+  GstVaapiMiniObjectClass parent_class;
+
+  /*< public >*/
+  gpointer (*alloc_object) (GstVaapiVideoPool * pool);
+};
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_pool_init (GstVaapiVideoPool * pool, GstVaapiDisplay * display,
+    GstVaapiVideoPoolObjectType object_type);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_pool_finalize (GstVaapiVideoPool * pool);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_VIDEO_POOL_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow.c
new file mode 100644 (file)
index 0000000..7fd4502
--- /dev/null
@@ -0,0 +1,705 @@
+/*
+ *  gstvaapiwindow.c - VA window abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiwindow
+ * @short_description: VA window abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiwindow.h"
+#include "gstvaapiwindow_priv.h"
+#include "gstvaapidisplay_priv.h"
+#include "gstvaapisurface_priv.h"
+
+GST_DEBUG_CATEGORY (gst_debug_vaapi_window);
+#define GST_CAT_DEFAULT gst_debug_vaapi_window
+
+#define _do_init \
+    GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_window, "vaapiwindow", 0, \
+        "VA-API Window");
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVaapiWindow, gst_vaapi_window,
+    GST_TYPE_OBJECT, _do_init);
+
+enum
+{
+  PROP_DISPLAY = 1,
+  N_PROPERTIES
+};
+static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
+
+static void
+gst_vaapi_window_ensure_size (GstVaapiWindow * window)
+{
+  const GstVaapiWindowClass *const klass = GST_VAAPI_WINDOW_GET_CLASS (window);
+
+  if (!window->check_geometry)
+    return;
+
+  if (klass->get_geometry)
+    klass->get_geometry (window, NULL, NULL, &window->width, &window->height);
+
+  window->check_geometry = FALSE;
+  window->is_fullscreen = (window->width == window->display_width &&
+      window->height == window->display_height);
+}
+
+static gboolean
+ensure_filter (GstVaapiWindow * window)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window);
+
+  /* Ensure VPP pipeline is built */
+  if (window->filter)
+    return TRUE;
+
+  window->filter = gst_vaapi_filter_new (display);
+  if (!window->filter)
+    goto error_create_filter;
+  if (!gst_vaapi_filter_set_format (window->filter, GST_VIDEO_FORMAT_NV12))
+    goto error_unsupported_format;
+
+  return TRUE;
+
+error_create_filter:
+  {
+    GST_WARNING ("failed to create VPP filter. Disabling");
+    window->has_vpp = FALSE;
+    return FALSE;
+  }
+error_unsupported_format:
+  {
+    GST_ERROR ("unsupported render target format %s",
+        gst_vaapi_video_format_to_string (GST_VIDEO_FORMAT_NV12));
+    window->has_vpp = FALSE;
+    return FALSE;
+  }
+}
+
+void
+gst_vaapi_window_set_vpp_format_internal (GstVaapiWindow * window,
+    GstVideoFormat format, guint flags)
+{
+  if (window->surface_pool_format == format &&
+      window->surface_pool_flags == flags)
+    return;
+
+  gst_vaapi_video_pool_replace (&window->surface_pool, NULL);
+  window->surface_pool_format = format;
+  window->surface_pool_flags = flags;
+}
+
+static gboolean
+ensure_filter_surface_pool (GstVaapiWindow * window)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window);
+
+  if (window->surface_pool)
+    goto ensure_filter;
+
+  /* Ensure VA surface pool is created */
+  /* XXX: optimize the surface format to use. e.g. YUY2 */
+  window->surface_pool = gst_vaapi_surface_pool_new (display,
+      window->surface_pool_format, window->width, window->height,
+      window->surface_pool_flags);
+  if (!window->surface_pool) {
+    GST_WARNING ("failed to create surface pool for conversion");
+    return FALSE;
+  }
+  gst_vaapi_filter_replace (&window->filter, NULL);
+
+ensure_filter:
+  return ensure_filter (window);
+}
+
+static gboolean
+gst_vaapi_window_create (GstVaapiWindow * window, guint width, guint height)
+{
+  gst_vaapi_display_get_size (GST_VAAPI_WINDOW_DISPLAY (window),
+      &window->display_width, &window->display_height);
+
+  if (!GST_VAAPI_WINDOW_GET_CLASS (window)->create (window, &width, &height))
+    return FALSE;
+
+  if (width != window->width || height != window->height) {
+    GST_DEBUG ("backend resized window to %ux%u", width, height);
+    window->width = width;
+    window->height = height;
+  }
+  return TRUE;
+}
+
+static void
+gst_vaapi_window_finalize (GObject * object)
+{
+  GstVaapiWindow *const window = GST_VAAPI_WINDOW (object);
+
+  gst_vaapi_video_pool_replace (&window->surface_pool, NULL);
+  gst_vaapi_filter_replace (&window->filter, NULL);
+  gst_vaapi_display_replace (&window->display, NULL);
+
+  G_OBJECT_CLASS (gst_vaapi_window_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_window_set_property (GObject * object, guint property_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiWindow *const window = GST_VAAPI_WINDOW (object);
+
+  switch (property_id) {
+    case PROP_DISPLAY:
+      g_assert (window->display == NULL);
+      window->display = g_value_dup_object (value);
+      g_assert (window->display != NULL);
+      window->has_vpp = GST_VAAPI_DISPLAY_HAS_VPP (window->display);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_window_get_property (GObject * object, guint property_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiWindow *const window = GST_VAAPI_WINDOW (object);
+
+  switch (property_id) {
+    case PROP_DISPLAY:
+      g_value_set_object (value, window->display);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_window_class_init (GstVaapiWindowClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+
+  object_class->set_property = gst_vaapi_window_set_property;
+  object_class->get_property = gst_vaapi_window_get_property;
+  object_class->finalize = gst_vaapi_window_finalize;
+
+  /**
+   * GstVaapiWindow:display:
+   *
+   * #GstVaapiDisplay to be used.
+   */
+  g_properties[PROP_DISPLAY] =
+      g_param_spec_object ("display", "Gst VA-API Display",
+      "The VA-API display object to use", GST_TYPE_VAAPI_DISPLAY,
+      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME);
+
+  g_object_class_install_properties (object_class, N_PROPERTIES, g_properties);
+}
+
+static void
+gst_vaapi_window_init (GstVaapiWindow * window)
+{
+}
+
+GstVaapiWindow *
+gst_vaapi_window_new_internal (GType type, GstVaapiDisplay * display,
+    GstVaapiID id, guint width, guint height)
+{
+  GstVaapiWindow *window;
+
+  if (id != GST_VAAPI_ID_INVALID) {
+    g_return_val_if_fail (width == 0, NULL);
+    g_return_val_if_fail (height == 0, NULL);
+  } else {
+    g_return_val_if_fail (width > 0, NULL);
+    g_return_val_if_fail (height > 0, NULL);
+  }
+
+  window = g_object_new (type, "display", display, NULL);
+  if (!window)
+    return NULL;
+
+  window->surface_pool_format = GST_VIDEO_FORMAT_NV12;
+
+  window->use_foreign_window = id != GST_VAAPI_ID_INVALID;
+  GST_VAAPI_WINDOW_ID (window) = window->use_foreign_window ? id : 0;
+
+  GST_DEBUG_OBJECT (window, "new window with id = 0x%08" G_GSIZE_MODIFIER
+      "x and size %ux%u", id, width, height);
+
+  if (!gst_vaapi_window_create (window, width, height))
+    goto error;
+
+  return window;
+
+  /* ERRORS */
+error:
+  {
+    gst_object_unref (window);
+    return NULL;
+  }
+}
+
+GstVaapiSurface *
+gst_vaapi_window_vpp_convert_internal (GstVaapiWindow * window,
+    GstVaapiSurface * surface, const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect, guint flags)
+{
+  GstVaapiSurface *vpp_surface = NULL;
+  GstVaapiFilterStatus status;
+
+  if (!window->has_vpp)
+    return NULL;
+
+  if (!ensure_filter_surface_pool (window))
+    return NULL;
+
+  if (src_rect)
+    if (!gst_vaapi_filter_set_cropping_rectangle (window->filter, src_rect))
+      return NULL;
+  if (dst_rect)
+    if (!gst_vaapi_filter_set_target_rectangle (window->filter, dst_rect))
+      return NULL;
+
+  /* Post-process the decoded source surface */
+  vpp_surface = gst_vaapi_video_pool_get_object (window->surface_pool);
+  if (!vpp_surface)
+    return NULL;
+
+  status =
+      gst_vaapi_filter_process (window->filter, surface, vpp_surface, flags);
+  if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
+    goto error_process_filter;
+  return vpp_surface;
+
+  /* ERRORS */
+error_process_filter:
+  {
+    GST_ERROR ("failed to process surface %" GST_VAAPI_ID_FORMAT " (error %d)",
+        GST_VAAPI_ID_ARGS (GST_VAAPI_SURFACE_ID (surface)), status);
+    gst_vaapi_video_pool_put_object (window->surface_pool, vpp_surface);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_window_new:
+ * @display: a #GstVaapiDisplay
+ * @width: the requested window width, in pixels
+ * @height: the requested windo height, in pixels
+ *
+ * Creates a window with the specified @width and @height. The window
+ * will be attached to the @display and remains invisible to the user
+ * until gst_vaapi_window_show() is called.
+ *
+ * Return value: the newly allocated #GstVaapiWindow object
+ */
+GstVaapiWindow *
+gst_vaapi_window_new (GstVaapiDisplay * display, guint width, guint height)
+{
+  GstVaapiDisplayClass *dpy_class;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY (display), NULL);
+
+  dpy_class = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  if (G_UNLIKELY (!dpy_class->create_window))
+    return NULL;
+  return dpy_class->create_window (display, GST_VAAPI_ID_INVALID, width,
+      height);
+}
+
+/**
+ * gst_vaapi_window_replace:
+ * @old_window_ptr: a pointer to a #GstVaapiWindow
+ * @new_window: a #GstVaapiWindow
+ *
+ * Atomically replaces the window window held in @old_window_ptr with
+ * @new_window. This means that @old_window_ptr shall reference a
+ * valid window. However, @new_window can be NULL.
+ */
+void
+gst_vaapi_window_replace (GstVaapiWindow ** old_window_ptr,
+    GstVaapiWindow * new_window)
+{
+  gst_object_replace ((GstObject **) old_window_ptr, GST_OBJECT (new_window));
+}
+
+/**
+ * gst_vaapi_window_get_display:
+ * @window: a #GstVaapiWindow
+ *
+ * Returns the #GstVaapiDisplay this @window is bound to.
+ *
+ * Return value: the parent #GstVaapiDisplay object
+ */
+GstVaapiDisplay *
+gst_vaapi_window_get_display (GstVaapiWindow * window)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), NULL);
+
+  return GST_VAAPI_WINDOW_DISPLAY (window);
+}
+
+/**
+ * gst_vaapi_window_show:
+ * @window: a #GstVaapiWindow
+ *
+ * Flags a window to be displayed. Any window that is not shown will
+ * not appear on the screen.
+ */
+void
+gst_vaapi_window_show (GstVaapiWindow * window)
+{
+  g_return_if_fail (GST_VAAPI_IS_WINDOW (window));
+
+  GST_VAAPI_WINDOW_GET_CLASS (window)->show (window);
+  window->check_geometry = TRUE;
+}
+
+/**
+ * gst_vaapi_window_hide:
+ * @window: a #GstVaapiWindow
+ *
+ * Reverses the effects of gst_vaapi_window_show(), causing the window
+ * to be hidden (invisible to the user).
+ */
+void
+gst_vaapi_window_hide (GstVaapiWindow * window)
+{
+  g_return_if_fail (GST_VAAPI_IS_WINDOW (window));
+
+  GST_VAAPI_WINDOW_GET_CLASS (window)->hide (window);
+}
+
+/**
+ * gst_vaapi_window_get_fullscreen:
+ * @window: a #GstVaapiWindow
+ *
+ * Retrieves whether the @window is fullscreen or not
+ *
+ * Return value: %TRUE if the window is fullscreen
+ */
+gboolean
+gst_vaapi_window_get_fullscreen (GstVaapiWindow * window)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), FALSE);
+
+  gst_vaapi_window_ensure_size (window);
+
+  return window->is_fullscreen;
+}
+
+/**
+ * gst_vaapi_window_set_render_rectangle:
+ * @window: a #GstVaapiWindow
+ * @x: the horizontal offset of the render area inside the window
+ * @y: the vertical offset of the render area inside the window
+ * @width: the width of the render area inside the window
+ * @height: the height of the render area inside the window
+ *
+ * Set information of the render area.
+ *
+ * Since: 1.18
+ */
+void
+gst_vaapi_window_set_render_rectangle (GstVaapiWindow * window, gint x, gint y,
+    gint width, gint height)
+{
+  const GstVaapiWindowClass *klass;
+
+  g_return_if_fail (window != NULL);
+
+  klass = GST_VAAPI_WINDOW_GET_CLASS (window);
+
+  if (klass->set_render_rect)
+    klass->set_render_rect (window, x, y, width, height);
+}
+
+/**
+ * gst_vaapi_window_set_fullscreen:
+ * @window: a #GstVaapiWindow
+ * @fullscreen: %TRUE to request window to get fullscreen
+ *
+ * Requests to place the @window in fullscreen or unfullscreen states.
+ */
+void
+gst_vaapi_window_set_fullscreen (GstVaapiWindow * window, gboolean fullscreen)
+{
+  const GstVaapiWindowClass *klass;
+
+  g_return_if_fail (GST_VAAPI_IS_WINDOW (window));
+
+  klass = GST_VAAPI_WINDOW_GET_CLASS (window);
+
+  if (window->is_fullscreen != fullscreen &&
+      klass->set_fullscreen && klass->set_fullscreen (window, fullscreen)) {
+    window->is_fullscreen = fullscreen;
+    window->check_geometry = TRUE;
+  }
+}
+
+/**
+ * gst_vaapi_window_get_width:
+ * @window: a #GstVaapiWindow
+ *
+ * Retrieves the width of a #GstVaapiWindow.
+ *
+ * Return value: the width of the @window, in pixels
+ */
+guint
+gst_vaapi_window_get_width (GstVaapiWindow * window)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), 0);
+
+  gst_vaapi_window_ensure_size (window);
+
+  return window->width;
+}
+
+/**
+ * gst_vaapi_window_get_height:
+ * @window: a #GstVaapiWindow
+ *
+ * Retrieves the height of a #GstVaapiWindow
+ *
+ * Return value: the height of the @window, in pixels
+ */
+guint
+gst_vaapi_window_get_height (GstVaapiWindow * window)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), 0);
+
+  gst_vaapi_window_ensure_size (window);
+
+  return window->height;
+}
+
+/**
+ * gst_vaapi_window_get_size:
+ * @window: a #GstVaapiWindow
+ * @width_ptr: return location for the width, or %NULL
+ * @height_ptr: return location for the height, or %NULL
+ *
+ * Retrieves the dimensions of a #GstVaapiWindow.
+ */
+void
+gst_vaapi_window_get_size (GstVaapiWindow * window, guint * width_ptr,
+    guint * height_ptr)
+{
+  g_return_if_fail (GST_VAAPI_IS_WINDOW (window));
+
+  gst_vaapi_window_ensure_size (window);
+
+  if (width_ptr)
+    *width_ptr = window->width;
+
+  if (height_ptr)
+    *height_ptr = window->height;
+}
+
+/**
+ * gst_vaapi_window_set_width:
+ * @window: a #GstVaapiWindow
+ * @width: requested new width for the window, in pixels
+ *
+ * Resizes the @window to match the specified @width.
+ */
+void
+gst_vaapi_window_set_width (GstVaapiWindow * window, guint width)
+{
+  g_return_if_fail (GST_VAAPI_IS_WINDOW (window));
+
+  gst_vaapi_window_set_size (window, width, window->height);
+}
+
+/**
+ * gst_vaapi_window_set_height:
+ * @window: a #GstVaapiWindow
+ * @height: requested new height for the window, in pixels
+ *
+ * Resizes the @window to match the specified @height.
+ */
+void
+gst_vaapi_window_set_height (GstVaapiWindow * window, guint height)
+{
+  g_return_if_fail (GST_VAAPI_IS_WINDOW (window));
+
+  gst_vaapi_window_set_size (window, window->width, height);
+}
+
+/**
+ * gst_vaapi_window_set_size:
+ * @window: a #GstVaapiWindow
+ * @width: requested new width for the window, in pixels
+ * @height: requested new height for the window, in pixels
+ *
+ * Resizes the @window to match the specified @width and @height.
+ */
+void
+gst_vaapi_window_set_size (GstVaapiWindow * window, guint width, guint height)
+{
+  g_return_if_fail (GST_VAAPI_IS_WINDOW (window));
+
+  if (width == window->width && height == window->height)
+    return;
+
+  if (!GST_VAAPI_WINDOW_GET_CLASS (window)->resize (window, width, height))
+    return;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  gst_vaapi_video_pool_replace (&window->surface_pool, NULL);
+
+  window->width = width;
+  window->height = height;
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+}
+
+static inline void
+get_surface_rect (GstVaapiSurface * surface, GstVaapiRectangle * rect)
+{
+  rect->x = 0;
+  rect->y = 0;
+  rect->width = GST_VAAPI_SURFACE_WIDTH (surface);
+  rect->height = GST_VAAPI_SURFACE_HEIGHT (surface);
+}
+
+static inline void
+get_window_rect (GstVaapiWindow * window, GstVaapiRectangle * rect)
+{
+  guint width, height;
+
+  gst_vaapi_window_get_size (window, &width, &height);
+  rect->x = 0;
+  rect->y = 0;
+  rect->width = width;
+  rect->height = height;
+}
+
+/**
+ * gst_vaapi_window_put_surface:
+ * @window: a #GstVaapiWindow
+ * @surface: a #GstVaapiSurface
+ * @src_rect: the sub-rectangle of the source surface to
+ *   extract and process. If %NULL, the entire surface will be used.
+ * @dst_rect: the sub-rectangle of the destination
+ *   window into which the surface is rendered. If %NULL, the entire
+ *   window will be used.
+ * @flags: postprocessing flags. See #GstVaapiSurfaceRenderFlags
+ *
+ * Renders the @surface region specified by @src_rect into the @window
+ * region specified by @dst_rect. The @flags specify how de-interlacing
+ * (if needed), color space conversion, scaling and other postprocessing
+ * transformations are performed.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_window_put_surface (GstVaapiWindow * window,
+    GstVaapiSurface * surface,
+    const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect, guint flags)
+{
+  const GstVaapiWindowClass *klass;
+  GstVaapiRectangle src_rect_default, dst_rect_default;
+
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), FALSE);
+  g_return_val_if_fail (surface != NULL, FALSE);
+
+  klass = GST_VAAPI_WINDOW_GET_CLASS (window);
+  if (!klass->render)
+    return FALSE;
+
+  if (!src_rect) {
+    src_rect = &src_rect_default;
+    get_surface_rect (surface, &src_rect_default);
+  }
+
+  if (!dst_rect) {
+    dst_rect = &dst_rect_default;
+    get_window_rect (window, &dst_rect_default);
+  }
+
+  return klass->render (window, surface, src_rect, dst_rect, flags);
+}
+
+/**
+ * gst_vaapi_window_reconfigure:
+ * @window: a #GstVaapiWindow
+ *
+ * Updates internal window size from geometry of the underlying window
+ * implementation if necessary.
+ */
+void
+gst_vaapi_window_reconfigure (GstVaapiWindow * window)
+{
+  g_return_if_fail (GST_VAAPI_IS_WINDOW (window));
+
+  window->check_geometry = TRUE;
+  gst_vaapi_window_ensure_size (window);
+}
+
+/**
+ * gst_vaapi_window_unblock:
+ * @window: a #GstVaapiWindow
+ *
+ * Unblocks a rendering surface operation.
+ */
+gboolean
+gst_vaapi_window_unblock (GstVaapiWindow * window)
+{
+  const GstVaapiWindowClass *klass;
+
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), FALSE);
+
+  klass = GST_VAAPI_WINDOW_GET_CLASS (window);
+
+  if (klass->unblock)
+    return klass->unblock (window);
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_window_unblock_cancel:
+ * @window: a #GstVaapiWindow
+ *
+ * Cancels the previous unblock request.
+ */
+gboolean
+gst_vaapi_window_unblock_cancel (GstVaapiWindow * window)
+{
+  const GstVaapiWindowClass *klass;
+
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW (window), FALSE);
+
+  klass = GST_VAAPI_WINDOW_GET_CLASS (window);
+
+  if (klass->unblock_cancel)
+    return klass->unblock_cancel (window);
+
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow.h
new file mode 100644 (file)
index 0000000..c1628f7
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *  gstvaapiwindow.h - VA window abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_H
+#define GST_VAAPI_WINDOW_H
+
+#include <gst/gst.h>
+#include <gst/vaapi/gstvaapitypes.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapisurface.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_WINDOW                    (gst_vaapi_window_get_type ())
+#define GST_VAAPI_WINDOW(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW, GstVaapiWindow))
+#define GST_VAAPI_IS_WINDOW(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW))
+
+typedef struct _GstVaapiWindow GstVaapiWindow;
+typedef struct _GstVaapiWindowClass GstVaapiWindowClass;
+
+GType
+gst_vaapi_window_get_type (void) G_GNUC_CONST;
+
+GstVaapiWindow *
+gst_vaapi_window_new (GstVaapiDisplay * display, guint width, guint height);
+
+void
+gst_vaapi_window_replace (GstVaapiWindow ** old_window_ptr,
+    GstVaapiWindow * new_window);
+
+GstVaapiDisplay *
+gst_vaapi_window_get_display (GstVaapiWindow * window);
+
+void
+gst_vaapi_window_show (GstVaapiWindow * window);
+
+void
+gst_vaapi_window_hide (GstVaapiWindow * window);
+
+gboolean
+gst_vaapi_window_get_fullscreen (GstVaapiWindow * window);
+
+void
+gst_vaapi_window_set_fullscreen (GstVaapiWindow * window, gboolean fullscreen);
+
+guint
+gst_vaapi_window_get_width (GstVaapiWindow * window);
+
+guint
+gst_vaapi_window_get_height (GstVaapiWindow * window);
+
+void
+gst_vaapi_window_get_size (GstVaapiWindow * window, guint * width_ptr,
+    guint * height_ptr);
+
+void
+gst_vaapi_window_set_width (GstVaapiWindow * window, guint width);
+
+void
+gst_vaapi_window_set_height (GstVaapiWindow * window, guint height);
+
+void
+gst_vaapi_window_set_size (GstVaapiWindow * window, guint width, guint height);
+
+void
+gst_vaapi_window_set_render_rectangle (GstVaapiWindow * window, gint x, gint y,
+    gint width, gint height);
+
+gboolean
+gst_vaapi_window_put_surface (GstVaapiWindow * window,
+    GstVaapiSurface * surface, const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect, guint flags);
+
+void
+gst_vaapi_window_reconfigure (GstVaapiWindow * window);
+
+gboolean
+gst_vaapi_window_unblock (GstVaapiWindow * window);
+
+gboolean
+gst_vaapi_window_unblock_cancel (GstVaapiWindow * window);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindow, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_drm.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_drm.c
new file mode 100644 (file)
index 0000000..54735b4
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  gstvaapiwindow_drm.c - VA/DRM window abstraction
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiwindow_drm
+ * @short_description: VA/DRM dummy window abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiwindow_drm.h"
+#include "gstvaapiwindow_priv.h"
+#include "gstvaapidisplay_drm_priv.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window);
+#define GST_CAT_DEFAULT gst_debug_vaapi_window
+
+typedef struct _GstVaapiWindowDRMClass GstVaapiWindowDRMClass;
+
+/**
+ * GstVaapiWindowDRM:
+ *
+ * A dummy DRM window abstraction.
+ */
+struct _GstVaapiWindowDRM
+{
+  /*< private > */
+  GstVaapiWindow parent_instance;
+};
+
+/**
+ * GstVaapiWindowDRMClass:
+ *
+ * A dummy DRM window abstraction class.
+ */
+struct _GstVaapiWindowDRMClass
+{
+  /*< private > */
+  GstVaapiWindowClass parent_instance;
+};
+
+G_DEFINE_TYPE (GstVaapiWindowDRM, gst_vaapi_window_drm, GST_TYPE_VAAPI_WINDOW);
+
+static gboolean
+gst_vaapi_window_drm_show (GstVaapiWindow * window)
+{
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_drm_hide (GstVaapiWindow * window)
+{
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_drm_create (GstVaapiWindow * window,
+    guint * width, guint * height)
+{
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_drm_resize (GstVaapiWindow * window, guint width, guint height)
+{
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_drm_render (GstVaapiWindow * window,
+    GstVaapiSurface * surface,
+    const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect, guint flags)
+{
+  return TRUE;
+}
+
+static void
+gst_vaapi_window_drm_class_init (GstVaapiWindowDRMClass * klass)
+{
+  GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass);
+
+  window_class->create = gst_vaapi_window_drm_create;
+  window_class->show = gst_vaapi_window_drm_show;
+  window_class->hide = gst_vaapi_window_drm_hide;
+  window_class->resize = gst_vaapi_window_drm_resize;
+  window_class->render = gst_vaapi_window_drm_render;
+}
+
+static void
+gst_vaapi_window_drm_init (GstVaapiWindowDRM * window)
+{
+}
+
+/**
+ * gst_vaapi_window_drm_new:
+ * @display: a #GstVaapiDisplay
+ * @width: the requested window width, in pixels (unused)
+ * @height: the requested windo height, in pixels (unused)
+ *
+ * Creates a dummy window. The window will be attached to the @display.
+ * All rendering functions will return success since VA/DRM is a
+ * renderless API.
+ *
+ * Note: this dummy window object is only necessary to fulfill cases
+ * where the client application wants to automatically determine the
+ * best display to use for the current system. As such, it provides
+ * utility functions with the same API (function arguments) to help
+ * implement uniform function tables.
+ *
+ * Return value: the newly allocated #GstVaapiWindow object
+ */
+GstVaapiWindow *
+gst_vaapi_window_drm_new (GstVaapiDisplay * display, guint width, guint height)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_DRM (display), NULL);
+
+  return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_DRM, display,
+      GST_VAAPI_ID_INVALID, width, height);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_drm.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_drm.h
new file mode 100644 (file)
index 0000000..48accb8
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  gstvaapiwindow_drm.h - VA/DRM window abstraction
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_DRM_H
+#define GST_VAAPI_WINDOW_DRM_H
+
+#include <gst/gst.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_WINDOW_DRM (gst_vaapi_window_drm_get_type ())
+#define GST_VAAPI_WINDOW_DRM(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_DRM, GstVaapiWindowDRM))
+#define GST_VAAPI_IS_WINDOW_DRM(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_DRM))
+
+typedef struct _GstVaapiWindowDRM GstVaapiWindowDRM;
+
+GType
+gst_vaapi_window_drm_get_type (void) G_GNUC_CONST;
+
+GstVaapiWindow *
+gst_vaapi_window_drm_new (GstVaapiDisplay * display, guint width, guint height);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowDRM, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_DRM_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_egl.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_egl.c
new file mode 100644 (file)
index 0000000..46bb2f9
--- /dev/null
@@ -0,0 +1,553 @@
+/*
+ *  gstvaapiwindow_egl.c - VA/EGL window abstraction
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiwindow_egl
+ * @short_description: VA/EGL window abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiwindow_egl.h"
+#include "gstvaapiwindow_priv.h"
+#include "gstvaapitexture_egl.h"
+#include "gstvaapitexture_priv.h"
+#include "gstvaapidisplay_egl_priv.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window);
+#define GST_CAT_DEFAULT gst_debug_vaapi_window
+
+#define GST_VAAPI_WINDOW_EGL_CAST(obj) \
+    ((GstVaapiWindowEGL *)(obj))
+
+#define GST_VAAPI_WINDOW_EGL_GET_PROXY(obj) \
+    (GST_VAAPI_WINDOW_EGL_CAST(obj)->window)
+
+#define GST_VAAPI_WINDOW_EGL_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_EGL, GstVaapiWindowEGLClass))
+
+typedef struct _GstVaapiWindowEGLClass GstVaapiWindowEGLClass;
+
+enum
+{
+  RENDER_PROGRAM_VAR_PROJ = 0,
+  RENDER_PROGRAM_VAR_TEX0,
+  RENDER_PROGRAM_VAR_TEX1,
+  RENDER_PROGRAM_VAR_TEX2,
+};
+
+struct _GstVaapiWindowEGL
+{
+  GstVaapiWindow parent_instance;
+
+  GstVaapiWindow *window;
+  GstVaapiTexture *texture;
+  EglWindow *egl_window;
+  EglVTable *egl_vtable;
+  EglProgram *render_program;
+  gfloat render_projection[16];
+};
+
+struct _GstVaapiWindowEGLClass
+{
+  GstVaapiWindowClass parent_class;
+};
+
+typedef struct
+{
+  GstVaapiWindowEGL *window;
+  guint width;
+  guint height;
+  EglContext *egl_context;
+  gboolean success;             /* result */
+} CreateObjectsArgs;
+
+typedef struct
+{
+  GstVaapiWindowEGL *window;
+  guint width;
+  guint height;
+  gboolean success;             /* result */
+} ResizeWindowArgs;
+
+typedef struct
+{
+  GstVaapiWindowEGL *window;
+  GstVaapiSurface *surface;
+  const GstVaapiRectangle *src_rect;
+  const GstVaapiRectangle *dst_rect;
+  guint flags;
+  gboolean success;             /* result */
+} UploadSurfaceArgs;
+
+/* *IDENT-OFF* */
+static const gchar *vert_shader_text =
+    "#ifdef GL_ES                                      \n"
+    "precision mediump float;                          \n"
+    "#endif                                            \n"
+    "uniform mat4 proj;                                \n"
+    "attribute vec2 position;                          \n"
+    "attribute vec2 texcoord;                          \n"
+    "varying vec2 v_texcoord;                          \n"
+    "void main ()                                      \n"
+    "{                                                 \n"
+    "  gl_Position = proj * vec4 (position, 0.0, 1.0); \n"
+    "  v_texcoord  = texcoord;                         \n"
+    "}                                                 \n";
+
+static const gchar *frag_shader_text_rgba =
+    "#ifdef GL_ES                                      \n"
+    "precision mediump float;                          \n"
+    "#endif                                            \n"
+    "uniform sampler2D tex0;                           \n"
+    "varying vec2 v_texcoord;                          \n"
+    "void main ()                                      \n"
+    "{                                                 \n"
+    "  gl_FragColor = texture2D (tex0, v_texcoord);    \n"
+    "}                                                 \n";
+/* *IDENT-ON* */
+
+G_DEFINE_TYPE (GstVaapiWindowEGL, gst_vaapi_window_egl, GST_TYPE_VAAPI_WINDOW);
+
+static gboolean
+ensure_texture (GstVaapiWindowEGL * window, guint width, guint height)
+{
+  GstVaapiTexture *texture;
+
+  if (window->texture &&
+      GST_VAAPI_TEXTURE_WIDTH (window->texture) == width &&
+      GST_VAAPI_TEXTURE_HEIGHT (window->texture) == height)
+    return TRUE;
+
+  texture = gst_vaapi_texture_egl_new (GST_VAAPI_WINDOW_DISPLAY (window),
+      GL_TEXTURE_2D, GL_RGBA, width, height);
+  gst_mini_object_replace ((GstMiniObject **) & window->texture,
+      (GstMiniObject *) texture);
+  gst_mini_object_replace ((GstMiniObject **) & texture, NULL);
+  return window->texture != NULL;
+}
+
+static gboolean
+ensure_shaders (GstVaapiWindowEGL * window)
+{
+  EglVTable *const vtable = window->egl_vtable;
+  EglProgram *program;
+  GLuint prog_id;
+
+  g_return_val_if_fail (window->texture != NULL, FALSE);
+  g_return_val_if_fail (GST_VAAPI_TEXTURE_FORMAT (window->texture) == GL_RGBA,
+      FALSE);
+
+  if (window->render_program)
+    return TRUE;
+
+  program = egl_program_new (window->egl_window->context,
+      frag_shader_text_rgba, vert_shader_text);
+  if (!program)
+    return FALSE;
+
+  prog_id = program->base.handle.u;
+
+  vtable->glUseProgram (prog_id);
+  program->uniforms[RENDER_PROGRAM_VAR_PROJ] =
+      vtable->glGetUniformLocation (prog_id, "proj");
+  program->uniforms[RENDER_PROGRAM_VAR_TEX0] =
+      vtable->glGetUniformLocation (prog_id, "tex0");
+  program->uniforms[RENDER_PROGRAM_VAR_TEX1] =
+      vtable->glGetUniformLocation (prog_id, "tex1");
+  program->uniforms[RENDER_PROGRAM_VAR_TEX2] =
+      vtable->glGetUniformLocation (prog_id, "tex2");
+  vtable->glUseProgram (0);
+
+  egl_matrix_set_identity (window->render_projection);
+
+  egl_object_replace (&window->render_program, program);
+  egl_object_replace (&program, NULL);
+  return TRUE;
+}
+
+static gboolean
+do_create_objects_unlocked (GstVaapiWindowEGL * window, guint width,
+    guint height, EglContext * egl_context)
+{
+  EglWindow *egl_window;
+  EglVTable *egl_vtable;
+
+  egl_window = egl_window_new (egl_context,
+      GSIZE_TO_POINTER (GST_VAAPI_WINDOW_ID (GST_VAAPI_WINDOW_EGL_GET_PROXY
+              (window))));
+  if (!egl_window)
+    return FALSE;
+  window->egl_window = egl_window;
+
+  egl_vtable = egl_context_get_vtable (egl_window->context, TRUE);
+  if (!egl_vtable)
+    return FALSE;
+  window->egl_vtable = egl_object_ref (egl_vtable);
+  return TRUE;
+}
+
+static void
+do_create_objects (CreateObjectsArgs * args)
+{
+  GstVaapiWindowEGL *const window = args->window;
+  EglContextState old_cs;
+
+  args->success = FALSE;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  if (egl_context_set_current (args->egl_context, TRUE, &old_cs)) {
+    args->success = do_create_objects_unlocked (window, args->width,
+        args->height, args->egl_context);
+    egl_context_set_current (args->egl_context, FALSE, &old_cs);
+  }
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+}
+
+static gboolean
+gst_vaapi_window_egl_create (GstVaapiWindow * window, guint * width,
+    guint * height)
+{
+  GstVaapiDisplayEGL *const display =
+      GST_VAAPI_DISPLAY_EGL (GST_VAAPI_WINDOW_DISPLAY (window));
+  const GstVaapiDisplayClass *const native_dpy_class =
+      GST_VAAPI_DISPLAY_GET_CLASS (display->display);
+  CreateObjectsArgs args;
+
+  g_return_val_if_fail (native_dpy_class != NULL, FALSE);
+
+  GST_VAAPI_WINDOW_EGL_GET_PROXY (window) =
+      native_dpy_class->create_window (GST_VAAPI_DISPLAY (display->display),
+      GST_VAAPI_ID_INVALID, *width, *height);
+  if (!GST_VAAPI_WINDOW_EGL_GET_PROXY (window))
+    return FALSE;
+
+  gst_vaapi_window_get_size (GST_VAAPI_WINDOW_EGL_GET_PROXY (window), width,
+      height);
+
+  args.window = GST_VAAPI_WINDOW_EGL_CAST (window);
+  args.width = *width;
+  args.height = *height;
+  args.egl_context = GST_VAAPI_DISPLAY_EGL_CONTEXT (display);
+  return egl_context_run (args.egl_context,
+      (EglContextRunFunc) do_create_objects, &args) && args.success;
+}
+
+static void
+do_destroy_objects_unlocked (GstVaapiWindowEGL * window)
+{
+  egl_object_replace (&window->render_program, NULL);
+  egl_object_replace (&window->egl_vtable, NULL);
+  egl_object_replace (&window->egl_window, NULL);
+}
+
+static void
+do_destroy_objects (GstVaapiWindowEGL * window)
+{
+  EglContext *const egl_context =
+      GST_VAAPI_DISPLAY_EGL_CONTEXT (GST_VAAPI_WINDOW_DISPLAY (window));
+  EglContextState old_cs;
+
+  if (!window->egl_window)
+    return;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  if (egl_context_set_current (egl_context, TRUE, &old_cs)) {
+    do_destroy_objects_unlocked (window);
+    egl_context_set_current (egl_context, FALSE, &old_cs);
+  }
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+}
+
+static void
+gst_vaapi_window_egl_finalize (GObject * object)
+{
+  GstVaapiWindowEGL *const window = GST_VAAPI_WINDOW_EGL (object);
+
+  if (window->egl_window) {
+    egl_context_run (window->egl_window->context,
+        (EglContextRunFunc) do_destroy_objects, window);
+  }
+
+  gst_vaapi_window_replace (&window->window, NULL);
+  gst_mini_object_replace ((GstMiniObject **) & window->texture, NULL);
+
+  G_OBJECT_CLASS (gst_vaapi_window_egl_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_vaapi_window_egl_show (GstVaapiWindow * window)
+{
+  const GstVaapiWindowClass *const klass =
+      GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window));
+
+  g_return_val_if_fail (klass->show, FALSE);
+
+  return klass->show (GST_VAAPI_WINDOW_EGL_GET_PROXY (window));
+}
+
+static gboolean
+gst_vaapi_window_egl_hide (GstVaapiWindow * window)
+{
+  const GstVaapiWindowClass *const klass =
+      GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window));
+
+  g_return_val_if_fail (klass->hide, FALSE);
+
+  return klass->hide (GST_VAAPI_WINDOW_EGL_GET_PROXY (window));
+}
+
+static gboolean
+gst_vaapi_window_egl_get_geometry (GstVaapiWindow * window, gint * x_ptr,
+    gint * y_ptr, guint * width_ptr, guint * height_ptr)
+{
+  const GstVaapiWindowClass *const klass =
+      GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window));
+
+  return klass->get_geometry ?
+      klass->get_geometry (GST_VAAPI_WINDOW_EGL_GET_PROXY (window), x_ptr,
+      y_ptr, width_ptr, height_ptr) : FALSE;
+}
+
+static gboolean
+gst_vaapi_window_egl_set_fullscreen (GstVaapiWindow * window,
+    gboolean fullscreen)
+{
+  const GstVaapiWindowClass *const klass =
+      GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window));
+
+  return klass->set_fullscreen ?
+      klass->set_fullscreen (GST_VAAPI_WINDOW_EGL_GET_PROXY (window),
+      fullscreen) : FALSE;
+}
+
+static gboolean
+do_resize_window_unlocked (GstVaapiWindowEGL * window, guint width,
+    guint height)
+{
+  EglVTable *const vtable = window->egl_vtable;
+
+  vtable->glViewport (0, 0, width, height);
+  vtable->glClearColor (0.0f, 0.0f, 0.0f, 1.0f);
+  vtable->glClear (GL_COLOR_BUFFER_BIT);
+  return TRUE;
+}
+
+static void
+do_resize_window (ResizeWindowArgs * args)
+{
+  GstVaapiWindowEGL *const window = args->window;
+  EglContextState old_cs;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  if (egl_context_set_current (window->egl_window->context, TRUE, &old_cs)) {
+    args->success = do_resize_window_unlocked (window, args->width,
+        args->height);
+    egl_context_set_current (window->egl_window->context, FALSE, &old_cs);
+  }
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+}
+
+static gboolean
+gst_vaapi_window_egl_resize (GstVaapiWindow * window, guint width, guint height)
+{
+  GstVaapiWindowEGL *const win = GST_VAAPI_WINDOW_EGL_CAST (window);
+  const GstVaapiWindowClass *const klass =
+      GST_VAAPI_WINDOW_GET_CLASS (GST_VAAPI_WINDOW_EGL_GET_PROXY (window));
+  ResizeWindowArgs args = { win, width, height };
+
+  g_return_val_if_fail (klass->resize, FALSE);
+
+  if (!klass->resize (GST_VAAPI_WINDOW_EGL_GET_PROXY (window), width, height))
+    return FALSE;
+
+  return egl_context_run (win->egl_window->context,
+      (EglContextRunFunc) do_resize_window, &args) && args.success;
+}
+
+static gboolean
+do_render_texture (GstVaapiWindowEGL * window, const GstVaapiRectangle * rect)
+{
+  const GLuint tex_id = GST_VAAPI_TEXTURE_ID (window->texture);
+  EglVTable *const vtable = window->egl_vtable;
+  GLfloat x0, y0, x1, y1;
+  GLfloat texcoords[4][2];
+  GLfloat positions[4][2];
+  guint tex_width, tex_height;
+
+  if (!ensure_shaders (window))
+    return FALSE;
+
+  tex_width = GST_VAAPI_TEXTURE_WIDTH (window->texture);
+  tex_height = GST_VAAPI_TEXTURE_HEIGHT (window->texture);
+
+  // Source coords in VA surface
+  x0 = 0.0f;
+  y0 = 0.0f;
+  x1 = 1.0f;
+  y1 = 1.0f;
+  texcoords[0][0] = x0;
+  texcoords[0][1] = y1;
+  texcoords[1][0] = x1;
+  texcoords[1][1] = y1;
+  texcoords[2][0] = x1;
+  texcoords[2][1] = y0;
+  texcoords[3][0] = x0;
+  texcoords[3][1] = y0;
+
+  // Target coords in EGL surface
+  x0 = 2.0f * ((GLfloat) rect->x / tex_width) - 1.0f;
+  y1 = -2.0f * ((GLfloat) rect->y / tex_height) + 1.0f;
+  x1 = 2.0f * ((GLfloat) (rect->x + rect->width) / tex_width) - 1.0f;
+  y0 = -2.0f * ((GLfloat) (rect->y + rect->height) / tex_height) + 1.0f;
+  positions[0][0] = x0;
+  positions[0][1] = y0;
+  positions[1][0] = x1;
+  positions[1][1] = y0;
+  positions[2][0] = x1;
+  positions[2][1] = y1;
+  positions[3][0] = x0;
+  positions[3][1] = y1;
+
+  vtable->glClear (GL_COLOR_BUFFER_BIT);
+
+  if (G_UNLIKELY (window->egl_window->context->config->gles_version == 1)) {
+    vtable->glBindTexture (GST_VAAPI_TEXTURE_TARGET (window->texture), tex_id);
+    vtable->glEnableClientState (GL_VERTEX_ARRAY);
+    vtable->glVertexPointer (2, GL_FLOAT, 0, positions);
+    vtable->glEnableClientState (GL_TEXTURE_COORD_ARRAY);
+    vtable->glTexCoordPointer (2, GL_FLOAT, 0, texcoords);
+
+    vtable->glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
+
+    vtable->glDisableClientState (GL_VERTEX_ARRAY);
+    vtable->glDisableClientState (GL_TEXTURE_COORD_ARRAY);
+  } else {
+    EglProgram *const program = window->render_program;
+
+    vtable->glUseProgram (program->base.handle.u);
+    vtable->glUniformMatrix4fv (program->uniforms[RENDER_PROGRAM_VAR_PROJ],
+        1, GL_FALSE, window->render_projection);
+    vtable->glEnableVertexAttribArray (0);
+    vtable->glVertexAttribPointer (0, 2, GL_FLOAT, GL_FALSE, 0, positions);
+    vtable->glEnableVertexAttribArray (1);
+    vtable->glVertexAttribPointer (1, 2, GL_FLOAT, GL_FALSE, 0, texcoords);
+
+    vtable->glBindTexture (GST_VAAPI_TEXTURE_TARGET (window->texture), tex_id);
+    vtable->glUniform1i (program->uniforms[RENDER_PROGRAM_VAR_TEX0], 0);
+    vtable->glDrawArrays (GL_TRIANGLE_FAN, 0, 4);
+
+    vtable->glDisableVertexAttribArray (1);
+    vtable->glDisableVertexAttribArray (0);
+    vtable->glUseProgram (0);
+  }
+
+  eglSwapBuffers (window->egl_window->context->display->base.handle.p,
+      window->egl_window->base.handle.p);
+  return TRUE;
+}
+
+static gboolean
+do_upload_surface_unlocked (GstVaapiWindowEGL * window,
+    GstVaapiSurface * surface, const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect, guint flags)
+{
+  if (!ensure_texture (window, dst_rect->width, dst_rect->height))
+    return FALSE;
+  if (!gst_vaapi_texture_put_surface (window->texture, surface, src_rect,
+          flags))
+    return FALSE;
+  if (!do_render_texture (window, dst_rect))
+    return FALSE;
+  return TRUE;
+}
+
+static void
+do_upload_surface (UploadSurfaceArgs * args)
+{
+  GstVaapiWindowEGL *const window = args->window;
+  EglContextState old_cs;
+
+  args->success = FALSE;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  if (egl_context_set_current (window->egl_window->context, TRUE, &old_cs)) {
+    args->success = do_upload_surface_unlocked (window, args->surface,
+        args->src_rect, args->dst_rect, args->flags);
+    egl_context_set_current (window->egl_window->context, FALSE, &old_cs);
+  }
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+}
+
+static gboolean
+gst_vaapi_window_egl_render (GstVaapiWindow * window, GstVaapiSurface * surface,
+    const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect,
+    guint flags)
+{
+  GstVaapiWindowEGL *const win = GST_VAAPI_WINDOW_EGL_CAST (window);
+  UploadSurfaceArgs args = { win, surface, src_rect, dst_rect, flags };
+
+  return egl_context_run (win->egl_window->context,
+      (EglContextRunFunc) do_upload_surface, &args) && args.success;
+}
+
+static void
+gst_vaapi_window_egl_class_init (GstVaapiWindowEGLClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_window_egl_finalize;
+
+  window_class->create = gst_vaapi_window_egl_create;
+  window_class->show = gst_vaapi_window_egl_show;
+  window_class->hide = gst_vaapi_window_egl_hide;
+  window_class->get_geometry = gst_vaapi_window_egl_get_geometry;
+  window_class->set_fullscreen = gst_vaapi_window_egl_set_fullscreen;
+  window_class->resize = gst_vaapi_window_egl_resize;
+  window_class->render = gst_vaapi_window_egl_render;
+}
+
+static void
+gst_vaapi_window_egl_init (GstVaapiWindowEGL * window)
+{
+}
+
+/**
+ * gst_vaapi_window_egl_new:
+ * @display: a #GstVaapiDisplay
+ * @width: the requested window width, in pixels
+ * @height: the requested windo height, in pixels
+ *
+ * Creates a window with the specified @width and @height. The window
+ * will be attached to the @display and remains invisible to the user
+ * until gst_vaapi_window_show() is called.
+ *
+ * Return value: the newly allocated #GstVaapiWindow object
+ */
+GstVaapiWindow *
+gst_vaapi_window_egl_new (GstVaapiDisplay * display, guint width, guint height)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_EGL (display), NULL);
+
+  return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_EGL, display,
+      GST_VAAPI_ID_INVALID, width, height);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_egl.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_egl.h
new file mode 100644 (file)
index 0000000..ac6db51
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ *  gstvaapiwindow_egl.h - VA/EGL window abstraction
+ *
+ *  Copyright (C) 2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_EGL_H
+#define GST_VAAPI_WINDOW_EGL_H
+
+#include <gst/gst.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_WINDOW_EGL (gst_vaapi_window_egl_get_type ())
+#define GST_VAAPI_WINDOW_EGL(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_EGL, GstVaapiWindowEGL))
+#define GST_VAAPI_IS_WINDOW_EGL(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_EGL))
+
+typedef struct _GstVaapiWindowEGL GstVaapiWindowEGL;
+
+GType
+gst_vaapi_window_egl_get_type (void) G_GNUC_CONST;
+
+GstVaapiWindow *
+gst_vaapi_window_egl_new (GstVaapiDisplay * display, guint width, guint height);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowEGL, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_EGL_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_glx.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_glx.c
new file mode 100644 (file)
index 0000000..245235e
--- /dev/null
@@ -0,0 +1,556 @@
+/*
+ *  gstvaapiwindow_glx.c - VA/GLX window abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiwindow_glx
+ * @short_description: VA/GLX window abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapiwindow_glx.h"
+#include "gstvaapiwindow_x11_priv.h"
+#include "gstvaapidisplay_x11.h"
+#include "gstvaapidisplay_x11_priv.h"
+#include "gstvaapidisplay_glx_priv.h"
+#include "gstvaapiutils_x11.h"
+#include "gstvaapiutils_glx.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window);
+#define GST_CAT_DEFAULT gst_debug_vaapi_window
+
+#define GST_VAAPI_WINDOW_GLX_CAST(obj) ((GstVaapiWindowGLX *)(obj))
+#define GST_VAAPI_WINDOW_GLX_GET_PRIVATE(window) \
+    gst_vaapi_window_glx_get_instance_private (GST_VAAPI_WINDOW_GLX_CAST (window))
+
+#define GST_VAAPI_WINDOW_GLX_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_GLX, GstVaapiWindowGLXClass))
+
+typedef struct _GstVaapiWindowGLXPrivate GstVaapiWindowGLXPrivate;
+typedef struct _GstVaapiWindowGLXClass GstVaapiWindowGLXClass;
+
+struct _GstVaapiWindowGLXPrivate
+{
+  Colormap cmap;
+  GLContextState *gl_context;
+};
+
+/**
+ * GstVaapiWindowGLX:
+ *
+ * An X11 Window suitable for GLX rendering.
+ */
+struct _GstVaapiWindowGLX
+{
+  /*< private > */
+  GstVaapiWindowX11 parent_instance;
+};
+
+/**
+ * GstVaapiWindowGLXClass:
+ *
+ * An X11 Window suitable for GLX rendering.
+ */
+struct _GstVaapiWindowGLXClass
+{
+  /*< private > */
+  GstVaapiWindowX11Class parent_class;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiWindowGLX, gst_vaapi_window_glx,
+    GST_TYPE_VAAPI_WINDOW_X11);
+
+/* Fill rectangle coords with capped bounds */
+static inline void
+fill_rect (GstVaapiRectangle * dst_rect,
+    const GstVaapiRectangle * src_rect, guint width, guint height)
+{
+  if (src_rect) {
+    dst_rect->x = src_rect->x > 0 ? src_rect->x : 0;
+    dst_rect->y = src_rect->y > 0 ? src_rect->y : 0;
+    if (src_rect->x + src_rect->width < width)
+      dst_rect->width = src_rect->width;
+    else
+      dst_rect->width = width - dst_rect->x;
+    if (src_rect->y + src_rect->height < height)
+      dst_rect->height = src_rect->height;
+    else
+      dst_rect->height = height - dst_rect->y;
+  } else {
+    dst_rect->x = 0;
+    dst_rect->y = 0;
+    dst_rect->width = width;
+    dst_rect->height = height;
+  }
+}
+
+static void
+_gst_vaapi_window_glx_destroy_context (GstVaapiWindow * window)
+{
+  GstVaapiWindowGLXPrivate *const priv =
+      GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  if (priv->gl_context) {
+    gl_destroy_context (priv->gl_context);
+    priv->gl_context = NULL;
+  }
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+}
+
+static gboolean
+_gst_vaapi_window_glx_create_context (GstVaapiWindow * window,
+    GLXContext foreign_context)
+{
+  GstVaapiWindowGLXPrivate *const priv =
+      GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  GLContextState parent_cs;
+
+  parent_cs.display = dpy;
+  parent_cs.window = None;
+  parent_cs.context = foreign_context;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  priv->gl_context = gl_create_context (dpy, DefaultScreen (dpy), &parent_cs);
+  if (!priv->gl_context) {
+    GST_DEBUG ("could not create GLX context");
+    goto end;
+  }
+
+  if (!glXIsDirect (dpy, priv->gl_context->context)) {
+    GST_DEBUG ("could not create a direct-rendering GLX context");
+    goto out_destroy_context;
+  }
+  goto end;
+
+out_destroy_context:
+  gl_destroy_context (priv->gl_context);
+  priv->gl_context = NULL;
+end:
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  return priv->gl_context != NULL;
+}
+
+static gboolean
+_gst_vaapi_window_glx_ensure_context (GstVaapiWindow * window,
+    GLXContext foreign_context)
+{
+  GstVaapiWindowGLXPrivate *const priv =
+      GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+
+  if (priv->gl_context) {
+    if (!foreign_context || foreign_context == priv->gl_context->context)
+      return TRUE;
+    _gst_vaapi_window_glx_destroy_context (window);
+  }
+  return _gst_vaapi_window_glx_create_context (window, foreign_context);
+}
+
+static gboolean
+gst_vaapi_window_glx_ensure_context (GstVaapiWindow * window,
+    GLXContext foreign_context)
+{
+  GstVaapiWindowGLXPrivate *const priv =
+      GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+  GLContextState old_cs;
+  guint width, height;
+
+  if (!_gst_vaapi_window_glx_ensure_context (window, foreign_context))
+    return FALSE;
+
+  priv->gl_context->window = GST_VAAPI_WINDOW_ID (window);
+  if (!gl_set_current_context (priv->gl_context, &old_cs)) {
+    GST_DEBUG ("could not make newly created GLX context current");
+    return FALSE;
+  }
+
+  glDisable (GL_DEPTH_TEST);
+  glDepthMask (GL_FALSE);
+  glDisable (GL_CULL_FACE);
+  glDrawBuffer (GL_BACK);
+  glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+  glEnable (GL_BLEND);
+  glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+  gst_vaapi_window_get_size (window, &width, &height);
+  gl_resize (width, height);
+
+  gl_set_bgcolor (0);
+  glClear (GL_COLOR_BUFFER_BIT);
+  gl_set_current_context (&old_cs, NULL);
+  return TRUE;
+}
+
+static guintptr
+gst_vaapi_window_glx_get_visual_id (GstVaapiWindow * window)
+{
+  GstVaapiWindowGLXPrivate *const priv =
+      GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+
+  if (!_gst_vaapi_window_glx_ensure_context (window, NULL))
+    return 0;
+  return priv->gl_context->visual->visualid;
+}
+
+static void
+gst_vaapi_window_glx_destroy_colormap (GstVaapiWindow * window)
+{
+  GstVaapiWindowGLXPrivate *const priv =
+      GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+
+  if (priv->cmap) {
+    if (!window->use_foreign_window) {
+      GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+      XFreeColormap (dpy, priv->cmap);
+      GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    }
+    priv->cmap = None;
+  }
+}
+
+static Colormap
+gst_vaapi_window_glx_create_colormap (GstVaapiWindow * window)
+{
+  GstVaapiWindowGLXPrivate *const priv =
+      GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  XWindowAttributes wattr;
+  gboolean success = FALSE;
+
+  if (!priv->cmap) {
+    if (!window->use_foreign_window) {
+      if (!_gst_vaapi_window_glx_ensure_context (window, NULL))
+        return None;
+      GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+      x11_trap_errors ();
+      /* XXX: add a GstVaapiDisplayX11:x11-screen property? */
+      priv->cmap = XCreateColormap (dpy, RootWindow (dpy, DefaultScreen (dpy)),
+          priv->gl_context->visual->visual, AllocNone);
+      success = x11_untrap_errors () == 0;
+      GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    } else {
+      GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+      x11_trap_errors ();
+      XGetWindowAttributes (dpy, GST_VAAPI_WINDOW_ID (window), &wattr);
+      priv->cmap = wattr.colormap;
+      success = x11_untrap_errors () == 0;
+      GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    }
+    if (!success)
+      return None;
+  }
+  return priv->cmap;
+}
+
+static guintptr
+gst_vaapi_window_glx_get_colormap (GstVaapiWindow * window)
+{
+  return GPOINTER_TO_SIZE (gst_vaapi_window_glx_create_colormap (window));
+}
+
+static gboolean
+gst_vaapi_window_glx_resize (GstVaapiWindow * window, guint width, guint height)
+{
+  GstVaapiWindowGLXPrivate *const priv =
+      GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+  const GstVaapiWindowClass *const parent_klass =
+      GST_VAAPI_WINDOW_CLASS (gst_vaapi_window_glx_parent_class);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  GLContextState old_cs;
+
+  if (!parent_klass->resize (window, width, height))
+    return FALSE;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  XSync (dpy, False);           /* make sure resize completed */
+  if (gl_set_current_context (priv->gl_context, &old_cs)) {
+    gl_resize (width, height);
+    gl_set_current_context (&old_cs, NULL);
+  }
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  return TRUE;
+}
+
+static void
+gst_vaapi_window_glx_finalize (GObject * object)
+{
+  GstVaapiWindow *const window = GST_VAAPI_WINDOW (object);
+
+  _gst_vaapi_window_glx_destroy_context (window);
+  gst_vaapi_window_glx_destroy_colormap (window);
+
+  G_OBJECT_CLASS (gst_vaapi_window_glx_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_window_glx_class_init (GstVaapiWindowGLXClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_window_glx_finalize;
+
+  window_class->resize = gst_vaapi_window_glx_resize;
+  window_class->get_visual_id = gst_vaapi_window_glx_get_visual_id;
+  window_class->get_colormap = gst_vaapi_window_glx_get_colormap;
+}
+
+static void
+gst_vaapi_window_glx_init (GstVaapiWindowGLX * window)
+{
+}
+
+/**
+ * gst_vaapi_window_glx_new:
+ * @display: a #GstVaapiDisplay
+ * @width: the requested window width, in pixels
+ * @height: the requested windo height, in pixels
+ *
+ * Creates a window with the specified @width and @height. The window
+ * will be attached to the @display and remains invisible to the user
+ * until gst_vaapi_window_show() is called.
+ *
+ * Return value: the newly allocated #GstVaapiWindow object
+ */
+GstVaapiWindow *
+gst_vaapi_window_glx_new (GstVaapiDisplay * display, guint width, guint height)
+{
+  GstVaapiWindow *window;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_GLX (display), NULL);
+
+  window = gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_GLX, display,
+      GST_VAAPI_ID_INVALID, width, height);
+  if (!window)
+    return NULL;
+
+  if (!gst_vaapi_window_glx_ensure_context (window, NULL))
+    goto error;
+  return window;
+
+  /* ERRORS */
+error:
+  {
+    gst_object_unref (window);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_window_glx_new_with_xid:
+ * @display: a #GstVaapiDisplay
+ * @xid: an X11 Window id
+ *
+ * Creates a #GstVaapiWindow using the X11 Window @xid. The caller
+ * still owns the window and must call XDestroyWindow() when all
+ * #GstVaapiWindow references are released. Doing so too early can
+ * yield undefined behaviour.
+ *
+ * Return value: the newly allocated #GstVaapiWindow object
+ */
+GstVaapiWindow *
+gst_vaapi_window_glx_new_with_xid (GstVaapiDisplay * display, Window xid)
+{
+  GstVaapiWindow *window;
+
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_GLX (display), NULL);
+  g_return_val_if_fail (xid != None, NULL);
+
+  window = gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_GLX, display,
+      xid, 0, 0);
+  if (!window)
+    return NULL;
+
+  if (!gst_vaapi_window_glx_ensure_context (window, NULL))
+    goto error;
+  return window;
+
+  /* ERRORS */
+error:
+  {
+    gst_object_unref (window);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_window_glx_get_context:
+ * @window: a #GstVaapiWindowGLX
+ *
+ * Returns the #GLXContext bound to the @window.
+ *
+ * Return value: the #GLXContext bound to the @window
+ */
+GLXContext
+gst_vaapi_window_glx_get_context (GstVaapiWindowGLX * window)
+{
+  GstVaapiWindowGLXPrivate *priv;
+
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW_GLX (window), NULL);
+
+  priv = GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+  return priv->gl_context->context;
+}
+
+/**
+ * gst_vaapi_window_glx_set_context:
+ * @window: a #GstVaapiWindowGLX
+ * @ctx: a GLX context
+ *
+ * Binds GLX context @ctx to @window. If @ctx is non %NULL, the caller
+ * is responsible to making sure it has compatible visual with that of
+ * the underlying X window. If @ctx is %NULL, a new context is created
+ * and the @window owns it.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_window_glx_set_context (GstVaapiWindowGLX * window, GLXContext ctx)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW_GLX (window), FALSE);
+
+  return gst_vaapi_window_glx_ensure_context (GST_VAAPI_WINDOW (window), ctx);
+}
+
+/**
+ * gst_vaapi_window_glx_make_current:
+ * @window: a #GstVaapiWindowGLX
+ *
+ * Makes the @window GLX context the current GLX rendering context of
+ * the calling thread, replacing the previously current context if
+ * there was one.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_window_glx_make_current (GstVaapiWindowGLX * window)
+{
+  gboolean success;
+  GstVaapiWindowGLXPrivate *priv;
+
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW_GLX (window), FALSE);
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  priv = GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+  success = gl_set_current_context (priv->gl_context, NULL);
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  return success;
+}
+
+/**
+ * gst_vaapi_window_glx_swap_buffers:
+ * @window: a #GstVaapiWindowGLX
+ *
+ * Promotes the contents of the back buffer of @window to become the
+ * contents of the front buffer of @window. This simply is wrapper
+ * around glXSwapBuffers().
+ */
+void
+gst_vaapi_window_glx_swap_buffers (GstVaapiWindowGLX * window)
+{
+  GstVaapiWindowGLXPrivate *priv;
+
+  g_return_if_fail (GST_VAAPI_IS_WINDOW_GLX (window));
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  priv = GST_VAAPI_WINDOW_GLX_GET_PRIVATE (window);
+  gl_swap_buffers (priv->gl_context);
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+}
+
+/**
+ * gst_vaapi_window_glx_put_texture:
+ * @window: a #GstVaapiWindowGLX
+ * @texture: a #GstVaapiTexture
+ * @src_rect: the sub-rectangle of the source texture to
+ *   extract and process. If %NULL, the entire texture will be used.
+ * @dst_rect: the sub-rectangle of the destination
+ *   window into which the texture is rendered. If %NULL, the entire
+ *   window will be used.
+ *
+ * Renders the @texture region specified by @src_rect into the @window
+ * region specified by @dst_rect.
+ *
+ * NOTE: only GL_TEXTURE_2D textures are supported at this time.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_window_glx_put_texture (GstVaapiWindowGLX * window,
+    GstVaapiTexture * texture,
+    const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect)
+{
+  GstVaapiRectangle tmp_src_rect, tmp_dst_rect;
+  GLTextureState ts;
+  GLenum tex_target;
+  GLuint tex_id;
+  guint tex_width, tex_height;
+  guint win_width, win_height;
+
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW_GLX (window), FALSE);
+  g_return_val_if_fail (texture != NULL, FALSE);
+
+  gst_vaapi_texture_get_size (texture, &tex_width, &tex_height);
+  fill_rect (&tmp_src_rect, src_rect, tex_width, tex_height);
+  src_rect = &tmp_src_rect;
+
+  gst_vaapi_window_get_size (GST_VAAPI_WINDOW (window), &win_width,
+      &win_height);
+  fill_rect (&tmp_dst_rect, dst_rect, win_width, win_height);
+  dst_rect = &tmp_dst_rect;
+
+  /* XXX: only GL_TEXTURE_2D textures are supported at this time */
+  tex_target = gst_vaapi_texture_get_target (texture);
+  if (tex_target != GL_TEXTURE_2D)
+    return FALSE;
+
+  tex_id = gst_vaapi_texture_get_id (texture);
+  if (!gl_bind_texture (&ts, tex_target, tex_id))
+    return FALSE;
+  glColor4f (1.0f, 1.0f, 1.0f, 1.0f);
+  glPushMatrix ();
+  glTranslatef ((GLfloat) dst_rect->x, (GLfloat) dst_rect->y, 0.0f);
+  glBegin (GL_QUADS);
+  {
+    const float tx1 = (float) src_rect->x / tex_width;
+    const float tx2 = (float) (src_rect->x + src_rect->width) / tex_width;
+    const float ty1 = (float) src_rect->y / tex_height;
+    const float ty2 = (float) (src_rect->y + src_rect->height) / tex_height;
+    const guint w = dst_rect->width;
+    const guint h = dst_rect->height;
+    glTexCoord2f (tx1, ty1);
+    glVertex2i (0, 0);
+    glTexCoord2f (tx1, ty2);
+    glVertex2i (0, h);
+    glTexCoord2f (tx2, ty2);
+    glVertex2i (w, h);
+    glTexCoord2f (tx2, ty1);
+    glVertex2i (w, 0);
+  }
+  glEnd ();
+  glPopMatrix ();
+  gl_unbind_texture (&ts);
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_glx.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_glx.h
new file mode 100644 (file)
index 0000000..d3ff9a4
--- /dev/null
@@ -0,0 +1,75 @@
+/*
+ *  gstvaapiwindow_glx.h - VA/GLX window abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_GLX_H
+#define GST_VAAPI_WINDOW_GLX_H
+
+#include <GL/glx.h>
+#include <gst/gst.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiwindow_x11.h>
+#include <gst/vaapi/gstvaapitexture.h>
+#include <gst/vaapi/gstvaapitypes.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_WINDOW_GLX (gst_vaapi_window_glx_get_type ())
+#define GST_VAAPI_WINDOW_GLX(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_GLX, GstVaapiWindowGLX))
+#define GST_VAAPI_IS_WINDOW_GLX(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_GLX))
+
+typedef struct _GstVaapiWindowGLX GstVaapiWindowGLX;
+
+GType
+gst_vaapi_window_glx_get_type (void) G_GNUC_CONST;
+
+GstVaapiWindow *
+gst_vaapi_window_glx_new (GstVaapiDisplay * display, guint width, guint height);
+
+GstVaapiWindow *
+gst_vaapi_window_glx_new_with_xid (GstVaapiDisplay * display, Window xid);
+
+GLXContext
+gst_vaapi_window_glx_get_context (GstVaapiWindowGLX * window);
+
+gboolean
+gst_vaapi_window_glx_set_context (GstVaapiWindowGLX * window, GLXContext ctx);
+
+gboolean
+gst_vaapi_window_glx_make_current (GstVaapiWindowGLX * window);
+
+void
+gst_vaapi_window_glx_swap_buffers (GstVaapiWindowGLX * window);
+
+gboolean
+gst_vaapi_window_glx_put_texture (GstVaapiWindowGLX * window,
+    GstVaapiTexture * texture, const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowGLX, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_GLX_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_priv.h
new file mode 100644 (file)
index 0000000..168e002
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ *  gstvaapiwindow_priv.h - VA window abstraction (private definitions)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_PRIV_H
+#define GST_VAAPI_WINDOW_PRIV_H
+
+#include "gstvaapidisplay.h"
+#include "gstvaapifilter.h"
+#include "gstvaapisurfacepool.h"
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_WINDOW_CAST(window) \
+    ((GstVaapiWindow *)(window))
+
+#define GST_VAAPI_WINDOW_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_WINDOW, GstVaapiWindowClass))
+
+#define GST_VAAPI_IS_WINDOW_CLASS(klass) \
+    (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_WINDOW))
+
+#define GST_VAAPI_WINDOW_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW, GstVaapiWindowClass))
+
+#define GST_VAAPI_WINDOW_DISPLAY(window) \
+   (GST_VAAPI_WINDOW_CAST (window)->display)
+
+#define GST_VAAPI_WINDOW_LOCK_DISPLAY(window) \
+   GST_VAAPI_DISPLAY_LOCK (GST_VAAPI_WINDOW_DISPLAY (window))
+
+#define GST_VAAPI_WINDOW_UNLOCK_DISPLAY(window) \
+   GST_VAAPI_DISPLAY_UNLOCK (GST_VAAPI_WINDOW_DISPLAY (window))
+
+#define GST_VAAPI_WINDOW_NATIVE_DISPLAY(window) \
+    GST_VAAPI_DISPLAY_NATIVE (GST_VAAPI_WINDOW_DISPLAY (window))
+
+#define GST_VAAPI_WINDOW_ID(window) \
+    (GST_VAAPI_WINDOW_CAST (window)->native_id)
+
+#define GST_VAAPI_WINDOW_VADISPLAY(window) \
+    GST_VAAPI_DISPLAY_VADISPLAY (GST_VAAPI_WINDOW_DISPLAY (window))
+
+/**
+ * GstVaapiWindow:
+ *
+ * Base class for system-dependent windows.
+ */
+struct _GstVaapiWindow
+{
+  /*< private >*/
+  GstObject parent_instance;
+  GstVaapiDisplay *display;
+  GstVaapiID native_id;
+
+  /*< protected >*/
+  guint width;
+  guint height;
+  guint display_width;
+  guint display_height;
+  guint use_foreign_window:1;
+  guint is_fullscreen:1;
+  guint check_geometry:1;
+
+  /* for conversion */
+  GstVideoFormat surface_pool_format;
+  guint surface_pool_flags;
+  GstVaapiVideoPool *surface_pool;
+  GstVaapiFilter *filter;
+  gboolean has_vpp;
+};
+
+/**
+ * GstVaapiWindowClass:
+ * @create: virtual function to create a window with width and height
+ * @show: virtual function to show (map) a window
+ * @hide: virtual function to hide (unmap) a window
+ * @get_geometry: virtual function to get the current window geometry
+ * @set_fullscreen: virtual function to change window fullscreen state
+ * @resize: virtual function to resize a window
+ * @render: virtual function to render a #GstVaapiSurface into a window
+ * @get_visual_id: virtual function to get the desired visual id used to
+ *   create the window
+ * @get_colormap: virtual function to get the desired colormap used to
+ *   create the window, or the currently allocated one
+ * @unblock: virtual function to unblock a rendering surface operation
+ * @unblock_cancel: virtual function to cancel the previous unblock
+ *   request.
+ *
+ * Base class for system-dependent windows.
+ */
+struct _GstVaapiWindowClass
+{
+  /*< private >*/
+  GstObjectClass parent_class;
+
+  /*< protected >*/
+  gboolean (*create) (GstVaapiWindow * window, guint * width, guint * height);
+  gboolean (*show) (GstVaapiWindow * window);
+  gboolean (*hide) (GstVaapiWindow * window);
+  gboolean (*get_geometry) (GstVaapiWindow * window, gint * px, gint * py,
+      guint * pwidth, guint * pheight);
+  gboolean (*set_fullscreen) (GstVaapiWindow * window, gboolean fullscreen);
+  gboolean (*resize) (GstVaapiWindow * window, guint width, guint height);
+  gboolean (*render) (GstVaapiWindow * window, GstVaapiSurface * surface,
+      const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect,
+      guint flags);
+  guintptr (*get_visual_id) (GstVaapiWindow * window);
+  guintptr (*get_colormap) (GstVaapiWindow * window);
+  gboolean (*unblock) (GstVaapiWindow * window);
+  gboolean (*unblock_cancel) (GstVaapiWindow * window);
+  void (*set_render_rect) (GstVaapiWindow * window, gint x, gint y, gint width, gint height);
+};
+
+GstVaapiWindow *
+gst_vaapi_window_new_internal (GType type, GstVaapiDisplay * display,
+    GstVaapiID handle, guint width, guint height);
+
+GstVaapiSurface *
+gst_vaapi_window_vpp_convert_internal (GstVaapiWindow * window,
+    GstVaapiSurface * surface, const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect, guint flags);
+
+void
+gst_vaapi_window_set_vpp_format_internal (GstVaapiWindow * window,
+    GstVideoFormat format, guint flags);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_wayland.c
new file mode 100644 (file)
index 0000000..394a089
--- /dev/null
@@ -0,0 +1,1092 @@
+/*
+ *  gstvaapiwindow_wayland.c - VA/Wayland window abstraction
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiwindow_wayland
+ * @short_description: VA/Wayland window abstraction
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapisurface_priv.h"
+#include "gstvaapiwindow_wayland.h"
+#include "gstvaapiwindow_priv.h"
+#include "gstvaapidisplay_wayland.h"
+#include "gstvaapidisplay_wayland_priv.h"
+#include "gstvaapiutils.h"
+#include "gstvaapifilter.h"
+#include "gstvaapisurfacepool.h"
+
+#include <unistd.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window);
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi);
+#define GST_CAT_DEFAULT gst_debug_vaapi_window
+
+#define GST_VAAPI_WINDOW_WAYLAND_CAST(obj) \
+    ((GstVaapiWindowWayland *)(obj))
+
+#define GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE(obj) \
+    gst_vaapi_window_wayland_get_instance_private (GST_VAAPI_WINDOW_WAYLAND_CAST (obj))
+
+#define GST_VAAPI_WINDOW_WAYLAND_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_WAYLAND, GstVaapiWindowWaylandClass))
+
+typedef struct _GstVaapiWindowWaylandPrivate GstVaapiWindowWaylandPrivate;
+typedef struct _GstVaapiWindowWaylandClass GstVaapiWindowWaylandClass;
+typedef struct _FrameState FrameState;
+
+struct _FrameState
+{
+  GstVaapiWindow *window;
+  GstVaapiSurface *surface;
+  GstVaapiVideoPool *surface_pool;
+  struct wl_buffer *buffer;
+  struct wl_callback *callback;
+  gboolean done;
+};
+
+static FrameState *
+frame_state_new (GstVaapiWindow * window)
+{
+  FrameState *frame;
+
+  frame = g_slice_new (FrameState);
+  if (!frame)
+    return NULL;
+
+  frame->window = window;
+  frame->surface = NULL;
+  frame->surface_pool = NULL;
+  frame->callback = NULL;
+  frame->done = FALSE;
+  return frame;
+}
+
+struct _GstVaapiWindowWaylandPrivate
+{
+  struct xdg_surface *xdg_surface;
+  struct xdg_toplevel *xdg_toplevel;
+  struct wl_shell_surface *wl_shell_surface;
+  struct wl_surface *surface;
+  struct wl_subsurface *video_subsurface;
+  struct wl_event_queue *event_queue;
+  GList *frames;
+  FrameState *last_frame;
+  GstPoll *poll;
+  GstPollFD pollfd;
+  guint is_shown:1;
+  guint fullscreen_on_show:1;
+  guint sync_failed:1;
+  guint num_frames_pending;
+  gint configure_pending;
+  gboolean need_vpp;
+  gboolean dmabuf_broken;
+  GMutex opaque_mutex;
+  gint opaque_width, opaque_height;
+};
+
+/**
+ * GstVaapiWindowWayland:
+ *
+ * A Wayland window abstraction.
+ */
+struct _GstVaapiWindowWayland
+{
+  /*< private > */
+  GstVaapiWindow parent_instance;
+};
+
+/**
+ * GstVaapiWindowWaylandClass:
+ *
+ * An Wayland Window wrapper class.
+ */
+struct _GstVaapiWindowWaylandClass
+{
+  /*< private > */
+  GstVaapiWindowClass parent_class;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiWindowWayland, gst_vaapi_window_wayland,
+    GST_TYPE_VAAPI_WINDOW);
+
+/* Object signals */
+enum
+{
+  SIZE_CHANGED,
+  N_SIGNALS
+};
+
+static guint signals[N_SIGNALS];
+
+static void
+frame_state_free (FrameState * frame)
+{
+  GstVaapiWindowWaylandPrivate *priv;
+
+  if (!frame)
+    return;
+
+  priv = GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (frame->window);
+  priv->frames = g_list_remove (priv->frames, frame);
+
+  if (frame->surface) {
+    if (frame->surface_pool)
+      gst_vaapi_video_pool_put_object (frame->surface_pool, frame->surface);
+    frame->surface = NULL;
+  }
+  gst_vaapi_video_pool_replace (&frame->surface_pool, NULL);
+
+  g_clear_pointer (&frame->callback, wl_callback_destroy);
+  wl_buffer_destroy (frame->buffer);
+  g_slice_free (FrameState, frame);
+}
+
+static void
+handle_xdg_toplevel_configure (void *data, struct xdg_toplevel *xdg_toplevel,
+    int32_t width, int32_t height, struct wl_array *states)
+{
+  GstVaapiWindow *window = GST_VAAPI_WINDOW (data);
+  const uint32_t *state;
+
+  GST_DEBUG ("Got XDG-toplevel::reconfigure, [width x height] = [%d x %d]",
+      width, height);
+
+  wl_array_for_each (state, states) {
+    switch (*state) {
+      case XDG_TOPLEVEL_STATE_FULLSCREEN:
+      case XDG_TOPLEVEL_STATE_MAXIMIZED:
+      case XDG_TOPLEVEL_STATE_RESIZING:
+      case XDG_TOPLEVEL_STATE_ACTIVATED:
+        break;
+    }
+  }
+
+  if (width > 0 && height > 0) {
+    gst_vaapi_window_set_size (window, width, height);
+    g_signal_emit (window, signals[SIZE_CHANGED], 0, width, height);
+  }
+}
+
+static void
+handle_xdg_toplevel_close (void *data, struct xdg_toplevel *xdg_toplevel)
+{
+}
+
+static const struct xdg_toplevel_listener xdg_toplevel_listener = {
+  handle_xdg_toplevel_configure,
+  handle_xdg_toplevel_close,
+};
+
+static gboolean gst_vaapi_window_wayland_sync (GstVaapiWindow * window);
+
+static gboolean
+gst_vaapi_window_wayland_show (GstVaapiWindow * window)
+{
+  GstVaapiWindowWaylandPrivate *priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+
+  if (priv->xdg_surface == NULL) {
+    GST_FIXME ("GstVaapiWindowWayland::show() unimplemented for wl_shell");
+    return TRUE;
+  }
+
+  if (priv->xdg_toplevel != NULL) {
+    GST_DEBUG ("XDG toplevel already mapped");
+    return TRUE;
+  }
+
+  g_atomic_int_set (&priv->configure_pending, 1);
+  g_atomic_int_inc (&priv->num_frames_pending);
+  /* Create a toplevel window out of it */
+  priv->xdg_toplevel = xdg_surface_get_toplevel (priv->xdg_surface);
+  g_return_val_if_fail (priv->xdg_toplevel, FALSE);
+  xdg_toplevel_set_title (priv->xdg_toplevel, "VA-API Wayland window");
+  wl_proxy_set_queue ((struct wl_proxy *) priv->xdg_toplevel,
+      priv->event_queue);
+
+  xdg_toplevel_add_listener (priv->xdg_toplevel, &xdg_toplevel_listener,
+      window);
+
+  /* Commit the xdg_surface state as top-level window */
+  wl_surface_commit (priv->surface);
+
+  return gst_vaapi_window_wayland_sync (window);
+}
+
+static gboolean
+gst_vaapi_window_wayland_hide (GstVaapiWindow * window)
+{
+  GstVaapiWindowWaylandPrivate *priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+
+  if (priv->xdg_surface == NULL) {
+    GST_FIXME ("GstVaapiWindowWayland::hide() unimplemented for wl_shell");
+    return TRUE;
+  }
+
+  if (priv->xdg_toplevel != NULL) {
+    g_clear_pointer (&priv->xdg_toplevel, xdg_toplevel_destroy);
+    wl_surface_commit (priv->surface);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_wayland_sync (GstVaapiWindow * window)
+{
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+  struct wl_display *const wl_display =
+      GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+
+  if (priv->sync_failed)
+    return FALSE;
+
+  if (priv->pollfd.fd < 0) {
+    priv->pollfd.fd = wl_display_get_fd (wl_display);
+    gst_poll_add_fd (priv->poll, &priv->pollfd);
+    gst_poll_fd_ctl_read (priv->poll, &priv->pollfd, TRUE);
+  }
+
+  while (g_atomic_int_get (&priv->num_frames_pending) > 0) {
+    while (wl_display_prepare_read_queue (wl_display, priv->event_queue) < 0) {
+      if (wl_display_dispatch_queue_pending (wl_display, priv->event_queue) < 0)
+        goto error;
+    }
+
+    if (wl_display_flush (wl_display) < 0)
+      goto error;
+
+    if (g_atomic_int_get (&priv->num_frames_pending) == 0) {
+      wl_display_cancel_read (wl_display);
+      return TRUE;
+    }
+
+  again:
+    if (gst_poll_wait (priv->poll, GST_CLOCK_TIME_NONE) < 0) {
+      int saved_errno = errno;
+      if (saved_errno == EAGAIN || saved_errno == EINTR)
+        goto again;
+      wl_display_cancel_read (wl_display);
+      if (saved_errno == EBUSY) /* flushing */
+        return FALSE;
+      else
+        goto error;
+    }
+
+    if (wl_display_read_events (wl_display) < 0)
+      goto error;
+    if (wl_display_dispatch_queue_pending (wl_display, priv->event_queue) < 0)
+      goto error;
+  }
+  return TRUE;
+
+  /* ERRORS */
+error:
+  {
+    priv->sync_failed = TRUE;
+    GST_ERROR ("Error on dispatching events: %s", g_strerror (errno));
+    return FALSE;
+  }
+}
+
+static void
+handle_ping (void *data, struct wl_shell_surface *wl_shell_surface,
+    uint32_t serial)
+{
+  wl_shell_surface_pong (wl_shell_surface, serial);
+}
+
+static void
+handle_configure (void *data, struct wl_shell_surface *wl_shell_surface,
+    uint32_t edges, int32_t width, int32_t height)
+{
+}
+
+static void
+handle_popup_done (void *data, struct wl_shell_surface *wl_shell_surface)
+{
+}
+
+static const struct wl_shell_surface_listener shell_surface_listener = {
+  handle_ping,
+  handle_configure,
+  handle_popup_done
+};
+
+static void
+handle_xdg_surface_configure (void *data, struct xdg_surface *xdg_surface,
+    uint32_t serial)
+{
+  GstVaapiWindow *window = GST_VAAPI_WINDOW (data);
+  GstVaapiWindowWaylandPrivate *priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+
+  xdg_surface_ack_configure (xdg_surface, serial);
+  if (g_atomic_int_compare_and_exchange (&priv->configure_pending, 1, 0))
+    g_atomic_int_dec_and_test (&priv->num_frames_pending);
+}
+
+static const struct xdg_surface_listener xdg_surface_listener = {
+  handle_xdg_surface_configure,
+};
+
+static gboolean
+gst_vaapi_window_wayland_set_fullscreen (GstVaapiWindow * window,
+    gboolean fullscreen)
+{
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+
+  if (window->use_foreign_window)
+    return TRUE;
+
+  if (!priv->is_shown) {
+    priv->fullscreen_on_show = fullscreen;
+    return TRUE;
+  }
+
+  /* XDG-shell */
+  if (priv->xdg_toplevel != NULL) {
+    if (fullscreen)
+      xdg_toplevel_set_fullscreen (priv->xdg_toplevel, NULL);
+    else
+      xdg_toplevel_unset_fullscreen (priv->xdg_toplevel);
+    return TRUE;
+  }
+
+  /* wl_shell fallback */
+  if (!fullscreen)
+    wl_shell_surface_set_toplevel (priv->wl_shell_surface);
+  else {
+    wl_shell_surface_set_fullscreen (priv->wl_shell_surface,
+        WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE, 0, NULL);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_wayland_create (GstVaapiWindow * window,
+    guint * width, guint * height)
+{
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+  GstVaapiDisplayWaylandPrivate *const priv_display =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (GST_VAAPI_WINDOW_DISPLAY (window));
+
+  GST_DEBUG ("create window, size %ux%u", *width, *height);
+
+  g_return_val_if_fail (priv_display->compositor != NULL, FALSE);
+  g_return_val_if_fail (priv_display->xdg_wm_base || priv_display->wl_shell,
+      FALSE);
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  priv->event_queue = wl_display_create_queue (priv_display->wl_display);
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  if (!priv->event_queue)
+    return FALSE;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  priv->surface = wl_compositor_create_surface (priv_display->compositor);
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  if (!priv->surface)
+    return FALSE;
+  wl_proxy_set_queue ((struct wl_proxy *) priv->surface, priv->event_queue);
+
+  if (window->use_foreign_window) {
+    struct wl_surface *wl_surface;
+
+    if (priv_display->subcompositor) {
+      if (GST_VAAPI_SURFACE_ID (window) == VA_INVALID_ID) {
+        GST_ERROR ("Invalid window");
+        return FALSE;
+      }
+
+      wl_surface = (struct wl_surface *) GST_VAAPI_WINDOW_ID (window);
+      GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+      priv->video_subsurface =
+          wl_subcompositor_get_subsurface (priv_display->subcompositor,
+          priv->surface, wl_surface);
+      GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+      if (!priv->video_subsurface)
+        return FALSE;
+
+      wl_proxy_set_queue ((struct wl_proxy *) priv->video_subsurface,
+          priv->event_queue);
+
+      wl_subsurface_set_desync (priv->video_subsurface);
+    } else {
+      GST_ERROR ("Wayland server does not support subsurfaces");
+      window->use_foreign_window = FALSE;
+    }
+    /* Prefer XDG-shell over deprecated wl_shell (if available) */
+  } else if (priv_display->xdg_wm_base) {
+    /* Create the XDG surface. We make the toplevel on VaapiWindow::show() */
+    GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+    priv->xdg_surface = xdg_wm_base_get_xdg_surface (priv_display->xdg_wm_base,
+        priv->surface);
+    GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    if (!priv->xdg_surface)
+      return FALSE;
+    wl_proxy_set_queue ((struct wl_proxy *) priv->xdg_surface,
+        priv->event_queue);
+    xdg_surface_add_listener (priv->xdg_surface, &xdg_surface_listener, window);
+  } else {
+    /* Fall back to wl_shell */
+    GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+    priv->wl_shell_surface = wl_shell_get_shell_surface (priv_display->wl_shell,
+        priv->surface);
+    GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    if (!priv->wl_shell_surface)
+      return FALSE;
+    wl_proxy_set_queue ((struct wl_proxy *) priv->wl_shell_surface,
+        priv->event_queue);
+
+    wl_shell_surface_add_listener (priv->wl_shell_surface,
+        &shell_surface_listener, priv);
+    wl_shell_surface_set_toplevel (priv->wl_shell_surface);
+  }
+
+  priv->poll = gst_poll_new (TRUE);
+  gst_poll_fd_init (&priv->pollfd);
+
+  g_mutex_init (&priv->opaque_mutex);
+
+  if (priv->fullscreen_on_show)
+    gst_vaapi_window_wayland_set_fullscreen (window, TRUE);
+
+  priv->is_shown = TRUE;
+
+  return TRUE;
+}
+
+static void
+gst_vaapi_window_wayland_finalize (GObject * object)
+{
+  GstVaapiWindow *window = GST_VAAPI_WINDOW (object);
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+  struct wl_display *const wl_display =
+      GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+
+  /* Make sure that the last wl buffer's callback could be called */
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  if (priv->surface) {
+    wl_surface_attach (priv->surface, NULL, 0, 0);
+    wl_surface_commit (priv->surface);
+    wl_display_flush (wl_display);
+  }
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+
+  gst_poll_set_flushing (priv->poll, TRUE);
+
+  if (priv->event_queue)
+    wl_display_roundtrip_queue (wl_display, priv->event_queue);
+
+  while (priv->frames)
+    frame_state_free ((FrameState *) priv->frames->data);
+
+  g_clear_pointer (&priv->xdg_surface, xdg_surface_destroy);
+  g_clear_pointer (&priv->wl_shell_surface, wl_shell_surface_destroy);
+  g_clear_pointer (&priv->video_subsurface, wl_subsurface_destroy);
+  g_clear_pointer (&priv->surface, wl_surface_destroy);
+  g_clear_pointer (&priv->event_queue, wl_event_queue_destroy);
+
+  gst_poll_free (priv->poll);
+
+  G_OBJECT_CLASS (gst_vaapi_window_wayland_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_window_wayland_update_opaque_region (GstVaapiWindow * window,
+    guint width, guint height)
+{
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+
+  g_mutex_lock (&priv->opaque_mutex);
+  priv->opaque_width = width;
+  priv->opaque_height = height;
+  g_mutex_unlock (&priv->opaque_mutex);
+}
+
+static gboolean
+gst_vaapi_window_wayland_resize (GstVaapiWindow * window,
+    guint width, guint height)
+{
+  if (window->use_foreign_window)
+    return TRUE;
+
+  GST_DEBUG ("resize window, new size %ux%u", width, height);
+
+  gst_vaapi_window_wayland_update_opaque_region (window, width, height);
+
+  return TRUE;
+}
+
+void
+gst_vaapi_window_wayland_set_render_rect (GstVaapiWindow * window, gint x,
+    gint y, gint width, gint height)
+{
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+
+  if (priv->video_subsurface)
+    wl_subsurface_set_position (priv->video_subsurface, x, y);
+
+  gst_vaapi_window_wayland_update_opaque_region (window, width, height);
+}
+
+static inline gboolean
+frame_done (FrameState * frame)
+{
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (frame->window);
+
+  g_atomic_int_set (&frame->done, TRUE);
+  if (g_atomic_pointer_compare_and_exchange (&priv->last_frame, frame, NULL))
+    return g_atomic_int_dec_and_test (&priv->num_frames_pending);
+  return FALSE;
+}
+
+static void
+frame_done_callback (void *data, struct wl_callback *callback, uint32_t time)
+{
+  if (!frame_done (data))
+    GST_INFO ("cannot remove last frame because it didn't match or empty");
+}
+
+static const struct wl_callback_listener frame_callback_listener = {
+  frame_done_callback
+};
+
+static void
+frame_release_callback (void *data, struct wl_buffer *wl_buffer)
+{
+  FrameState *const frame = data;
+
+  if (!frame->done)
+    if (!frame_done (frame))
+      GST_INFO ("cannot remove last frame because it didn't match or empty");
+  frame_state_free (frame);
+}
+
+static const struct wl_buffer_listener frame_buffer_listener = {
+  frame_release_callback
+};
+
+typedef enum
+{
+  GST_VAAPI_DMABUF_SUCCESS,
+  GST_VAAPI_DMABUF_BAD_FLAGS,
+  GST_VAAPI_DMABUF_BAD_FORMAT,
+  GST_VAAPI_DMABUF_BAD_MODIFIER,
+  GST_VAAPI_DMABUF_NOT_SUPPORTED,
+  GST_VAAPI_DMABUF_FLUSH,
+
+} GstVaapiDmabufStatus;
+
+#define DRM_FORMAT_MOD_INVALID 0xffffffffffffff
+
+static GstVaapiDmabufStatus
+dmabuf_format_supported (GstVaapiDisplayWaylandPrivate * const priv_display,
+    guint format, guint64 modifier)
+{
+  GArray *formats = priv_display->dmabuf_formats;
+  gboolean linear = FALSE;
+  gint i;
+
+  for (i = 0; i < formats->len; i++) {
+    GstDRMFormat fmt = g_array_index (formats, GstDRMFormat, i);
+    if (fmt.format == format && (fmt.modifier == modifier ||
+            (fmt.modifier == DRM_FORMAT_MOD_INVALID && modifier == 0)))
+      return GST_VAAPI_DMABUF_SUCCESS;
+    if (fmt.format == format && (fmt.modifier == 0 ||
+            fmt.modifier == DRM_FORMAT_MOD_INVALID))
+      linear = TRUE;
+  }
+  if (linear)
+    return GST_VAAPI_DMABUF_BAD_MODIFIER;
+  else
+    return GST_VAAPI_DMABUF_BAD_FORMAT;
+}
+
+GstVideoFormat
+check_format (GstVaapiDisplay * const display, gint index,
+    GstVideoFormat expect)
+{
+  GstVaapiDisplayWaylandPrivate *const priv_display =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+  GArray *formats = priv_display->dmabuf_formats;
+  GstDRMFormat fmt = g_array_index (formats, GstDRMFormat, index);
+  GstVideoFormat format = gst_vaapi_video_format_from_drm_format (fmt.format);
+  GstVaapiSurface *surface;
+
+  /* unkown formats should be filtered out in the display */
+  g_assert (format != GST_VIDEO_FORMAT_UNKNOWN);
+
+  if ((expect != GST_VIDEO_FORMAT_UNKNOWN) && (format != expect))
+    return GST_VIDEO_FORMAT_UNKNOWN;
+
+  surface = gst_vaapi_surface_new_with_format (display, format, 64, 64,
+      fmt.modifier == 0 ? GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE : 0);
+  if (!surface)
+    return GST_VIDEO_FORMAT_UNKNOWN;
+
+  gst_vaapi_surface_unref (surface);
+
+  return format;
+}
+
+GstVideoFormat
+choose_next_format (GstVaapiDisplay * const display, gint * next_index)
+{
+  GstVaapiDisplayWaylandPrivate *const priv_display =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+  GArray *formats = priv_display->dmabuf_formats;
+  GstVideoFormat format;
+  gint i;
+
+  if (*next_index < 0) {
+    *next_index = 0;
+    /* try GST_VIDEO_FORMAT_RGBA first */
+    for (i = 0; i < formats->len; i++) {
+      format = check_format (display, i, GST_VIDEO_FORMAT_RGBA);
+      if (format != GST_VIDEO_FORMAT_UNKNOWN)
+        return format;
+    }
+  }
+
+  for (i = *next_index; i < formats->len; i++) {
+    format = check_format (display, i, GST_VIDEO_FORMAT_UNKNOWN);
+    if (format != GST_VIDEO_FORMAT_UNKNOWN) {
+      *next_index = i + 1;
+      return format;
+    }
+  }
+  *next_index = formats->len;
+  return GST_VIDEO_FORMAT_UNKNOWN;
+}
+
+static GstVaapiDmabufStatus
+dmabuf_buffer_from_surface (GstVaapiWindow * window, GstVaapiSurface * surface,
+    guint va_flags, struct wl_buffer **out_buffer)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window);
+  GstVaapiDisplayWaylandPrivate *const priv_display =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (display);
+  struct zwp_linux_buffer_params_v1 *params;
+  struct wl_buffer *buffer = NULL;
+  VADRMPRIMESurfaceDescriptor desc;
+  VAStatus status;
+  GstVaapiDmabufStatus ret;
+  guint format, i, j, plane = 0;
+
+  if (!priv_display->dmabuf)
+    return GST_VAAPI_DMABUF_NOT_SUPPORTED;
+
+  if ((va_flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD)) != VA_FRAME_PICTURE)
+    return GST_VAAPI_DMABUF_BAD_FLAGS;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  status = vaExportSurfaceHandle (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_SURFACE_ID (surface), VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
+      VA_EXPORT_SURFACE_SEPARATE_LAYERS | VA_EXPORT_SURFACE_READ_ONLY, &desc);
+  /* Try again with composed layers, in case the format is supported there */
+  if (status == VA_STATUS_ERROR_INVALID_SURFACE)
+    status = vaExportSurfaceHandle (GST_VAAPI_DISPLAY_VADISPLAY (display),
+        GST_VAAPI_SURFACE_ID (surface), VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
+        VA_EXPORT_SURFACE_COMPOSED_LAYERS | VA_EXPORT_SURFACE_READ_ONLY, &desc);
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+
+  if (!vaapi_check_status (status, "vaExportSurfaceHandle()")) {
+    if (status == VA_STATUS_ERROR_UNIMPLEMENTED)
+      return GST_VAAPI_DMABUF_NOT_SUPPORTED;
+    else
+      return GST_VAAPI_DMABUF_BAD_FORMAT;
+  }
+
+  format = gst_vaapi_drm_format_from_va_fourcc (desc.fourcc);
+  params = zwp_linux_dmabuf_v1_create_params (priv_display->dmabuf);
+  for (i = 0; i < desc.num_layers; i++) {
+    for (j = 0; j < desc.layers[i].num_planes; ++j) {
+      gint object = desc.layers[i].object_index[j];
+      guint64 modifier = desc.objects[object].drm_format_modifier;
+
+      ret = dmabuf_format_supported (priv_display, format, modifier);
+      if (ret != GST_VAAPI_DMABUF_SUCCESS) {
+        GST_DEBUG ("skipping unsupported format/modifier %s/0x%"
+            G_GINT64_MODIFIER "x", gst_video_format_to_string
+            (gst_vaapi_video_format_from_drm_format (format)), modifier);
+        goto out;
+      }
+
+      zwp_linux_buffer_params_v1_add (params,
+          desc.objects[object].fd, plane, desc.layers[i].offset[j],
+          desc.layers[i].pitch[j], modifier >> 32,
+          modifier & G_GUINT64_CONSTANT (0xffffffff));
+      plane++;
+    }
+  }
+
+  buffer = zwp_linux_buffer_params_v1_create_immed (params, window->width,
+      window->height, format, 0);
+
+  if (!buffer)
+    ret = GST_VAAPI_DMABUF_NOT_SUPPORTED;
+
+out:
+  zwp_linux_buffer_params_v1_destroy (params);
+
+  for (i = 0; i < desc.num_objects; i++)
+    close (desc.objects[i].fd);
+
+  *out_buffer = buffer;
+  return ret;
+}
+
+static gboolean
+buffer_from_surface (GstVaapiWindow * window, GstVaapiSurface ** surf,
+    const GstVaapiRectangle * src_rect, const GstVaapiRectangle * dst_rect,
+    guint flags, struct wl_buffer **buffer)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window);
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+  GstVaapiSurface *surface;
+  GstVaapiDmabufStatus ret;
+  guint va_flags;
+  VAStatus status;
+  gint format_index = -1;
+
+  va_flags = from_GstVaapiSurfaceRenderFlags (flags);
+
+again:
+  surface = *surf;
+  if (priv->need_vpp) {
+    GstVaapiSurface *vpp_surface = NULL;
+    if (window->has_vpp) {
+      GST_LOG ("VPP: %s <%d, %d, %d, %d> -> %s <%d, %d, %d, %d>",
+          gst_video_format_to_string (gst_vaapi_surface_get_format (surface)),
+          src_rect->x, src_rect->y, src_rect->width, src_rect->height,
+          gst_video_format_to_string (window->surface_pool_format),
+          dst_rect->x, dst_rect->y, dst_rect->width, dst_rect->height);
+      vpp_surface = gst_vaapi_window_vpp_convert_internal (window, surface,
+          src_rect, dst_rect, flags);
+    }
+    if (G_UNLIKELY (!vpp_surface)) {
+      /* Not all formats are supported as destination format during VPP.
+         So try again with the next format if VPP fails. */
+      GstVideoFormat format = choose_next_format (display, &format_index);
+      if ((format != GST_VIDEO_FORMAT_UNKNOWN) && window->has_vpp) {
+        GST_DEBUG ("VPP failed. Try again with format %s",
+            gst_video_format_to_string (format));
+        gst_vaapi_window_set_vpp_format_internal (window, format, 0);
+        goto again;
+      } else {
+        GST_WARNING ("VPP failed. No supported format found.");
+        priv->dmabuf_broken = TRUE;
+      }
+    } else {
+      surface = vpp_surface;
+      va_flags = VA_FRAME_PICTURE;
+    }
+  }
+  if (!priv->dmabuf_broken) {
+    ret = dmabuf_buffer_from_surface (window, surface, va_flags, buffer);
+    switch (ret) {
+      case GST_VAAPI_DMABUF_SUCCESS:
+        goto out;
+      case GST_VAAPI_DMABUF_BAD_FLAGS:
+        /* FIXME: how should this be handed? */
+        break;
+      case GST_VAAPI_DMABUF_BAD_FORMAT:{
+        /* The Wayland server does not accept the current format or
+           vaExportSurfaceHandle() failed. Try again with a different format */
+        GstVideoFormat format = choose_next_format (display, &format_index);
+        if ((format != GST_VIDEO_FORMAT_UNKNOWN) && window->has_vpp) {
+          GST_DEBUG ("Failed to export buffer. Try again with format %s",
+              gst_video_format_to_string (format));
+          priv->need_vpp = TRUE;
+          gst_vaapi_window_set_vpp_format_internal (window, format, 0);
+          goto again;
+        }
+        if (window->has_vpp)
+          GST_WARNING ("Failed to export buffer and VPP not supported.");
+        else
+          GST_WARNING ("Failed to export buffer. No supported format found.");
+        priv->dmabuf_broken = TRUE;
+        break;
+      }
+      case GST_VAAPI_DMABUF_BAD_MODIFIER:
+        /* The format is supported by the Wayland server but not with the
+           current modifier. Try linear instead. */
+        if (window->has_vpp) {
+          GST_DEBUG ("Modifier rejected by the server. Try linear instead.");
+          priv->need_vpp = TRUE;
+          gst_vaapi_window_set_vpp_format_internal (window,
+              gst_vaapi_surface_get_format (surface),
+              GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE);
+          goto again;
+        }
+        GST_WARNING ("Modifier rejected by the server and VPP not supported.");
+        priv->dmabuf_broken = TRUE;
+        break;
+      case GST_VAAPI_DMABUF_NOT_SUPPORTED:
+        GST_DEBUG ("DMABuf protocol not supported");
+        priv->dmabuf_broken = TRUE;
+        break;
+      case GST_VAAPI_DMABUF_FLUSH:
+        return FALSE;
+    }
+  }
+
+  /* DMABuf is not available or does not work. Fall back to the old API.
+     There is no format negotiation so stick with NV12  */
+  gst_vaapi_window_set_vpp_format_internal (window, GST_VIDEO_FORMAT_NV12, 0);
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  status = vaGetSurfaceBufferWl (GST_VAAPI_DISPLAY_VADISPLAY (display),
+      GST_VAAPI_SURFACE_ID (surface),
+      va_flags & (VA_TOP_FIELD | VA_BOTTOM_FIELD), buffer);
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+
+  if (window->has_vpp && !priv->need_vpp &&
+      (status == VA_STATUS_ERROR_FLAG_NOT_SUPPORTED ||
+          status == VA_STATUS_ERROR_UNIMPLEMENTED ||
+          status == VA_STATUS_ERROR_INVALID_IMAGE_FORMAT)) {
+    priv->need_vpp = TRUE;
+    goto again;
+  }
+  if (!vaapi_check_status (status, "vaGetSurfaceBufferWl()"))
+    return FALSE;
+
+out:
+  *surf = surface;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_wayland_render (GstVaapiWindow * window,
+    GstVaapiSurface * surface,
+    const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect, guint flags)
+{
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+  GstVaapiDisplayWaylandPrivate *const priv_display =
+      GST_VAAPI_DISPLAY_WAYLAND_GET_PRIVATE (GST_VAAPI_WINDOW_DISPLAY (window));
+  struct wl_display *const wl_display =
+      GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  struct wl_buffer *buffer;
+  FrameState *frame;
+  guint width, height;
+  gboolean ret;
+
+  /* Skip rendering without valid window size. This can happen with a foreign
+     window if the render rectangle is not yet set. */
+  if (window->width == 0 || window->height == 0)
+    return TRUE;
+
+  /* Check that we don't need to crop source VA surface */
+  gst_vaapi_surface_get_size (surface, &width, &height);
+  if (src_rect->x != 0 || src_rect->y != 0)
+    priv->need_vpp = TRUE;
+  if (src_rect->width != width)
+    priv->need_vpp = TRUE;
+
+  /* Check that we don't render to a subregion of this window */
+  if (dst_rect->x != 0 || dst_rect->y != 0)
+    priv->need_vpp = TRUE;
+  if (dst_rect->width != window->width || dst_rect->height != window->height)
+    priv->need_vpp = TRUE;
+
+  /* Check that the surface has the correct size for the window */
+  if (dst_rect->width != src_rect->width ||
+      dst_rect->height != src_rect->height)
+    priv->need_vpp = TRUE;
+
+  ret = buffer_from_surface (window, &surface, src_rect, dst_rect, flags,
+      &buffer);
+  if (!ret)
+    return FALSE;
+
+  /* if need_vpp is set then the vpp happend */
+  if (priv->need_vpp) {
+    width = window->width;
+    height = window->height;
+  }
+
+  /* Wait for the previous frame to complete redraw */
+  if (!gst_vaapi_window_wayland_sync (window)) {
+    /* Release vpp surface if exists */
+    if (priv->need_vpp && window->has_vpp)
+      gst_vaapi_video_pool_put_object (window->surface_pool, surface);
+    wl_buffer_destroy (buffer);
+    return !priv->sync_failed;
+  }
+
+  frame = frame_state_new (window);
+  if (!frame)
+    return FALSE;
+  g_atomic_pointer_set (&priv->last_frame, frame);
+  g_atomic_int_inc (&priv->num_frames_pending);
+
+  if (priv->need_vpp && window->has_vpp) {
+    frame->surface = surface;
+    frame->surface_pool = gst_vaapi_video_pool_ref (window->surface_pool);
+  }
+
+  /* XXX: attach to the specified target rectangle */
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  wl_surface_attach (priv->surface, buffer, 0, 0);
+  wl_surface_damage (priv->surface, 0, 0, width, height);
+
+  g_mutex_lock (&priv->opaque_mutex);
+  if (priv->opaque_width > 0) {
+    struct wl_region *opaque_region;
+    opaque_region = wl_compositor_create_region (priv_display->compositor);
+    wl_region_add (opaque_region, 0, 0, width, height);
+    wl_surface_set_opaque_region (priv->surface, opaque_region);
+    wl_region_destroy (opaque_region);
+    priv->opaque_width = 0;
+    priv->opaque_height = 0;
+  }
+  g_mutex_unlock (&priv->opaque_mutex);
+
+  wl_proxy_set_queue ((struct wl_proxy *) buffer, priv->event_queue);
+  wl_buffer_add_listener (buffer, &frame_buffer_listener, frame);
+
+  frame->buffer = buffer;
+  frame->callback = wl_surface_frame (priv->surface);
+  wl_callback_add_listener (frame->callback, &frame_callback_listener, frame);
+  priv->frames = g_list_append (priv->frames, frame);
+
+  wl_surface_commit (priv->surface);
+  wl_display_flush (wl_display);
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_wayland_unblock (GstVaapiWindow * window)
+{
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+
+  gst_poll_set_flushing (priv->poll, TRUE);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_window_wayland_unblock_cancel (GstVaapiWindow * window)
+{
+  GstVaapiWindowWaylandPrivate *const priv =
+      GST_VAAPI_WINDOW_WAYLAND_GET_PRIVATE (window);
+
+  gst_poll_set_flushing (priv->poll, FALSE);
+
+  return TRUE;
+}
+
+static void
+gst_vaapi_window_wayland_class_init (GstVaapiWindowWaylandClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_window_wayland_finalize;
+
+  window_class->create = gst_vaapi_window_wayland_create;
+  window_class->show = gst_vaapi_window_wayland_show;
+  window_class->hide = gst_vaapi_window_wayland_hide;
+  window_class->render = gst_vaapi_window_wayland_render;
+  window_class->resize = gst_vaapi_window_wayland_resize;
+  window_class->set_fullscreen = gst_vaapi_window_wayland_set_fullscreen;
+  window_class->unblock = gst_vaapi_window_wayland_unblock;
+  window_class->unblock_cancel = gst_vaapi_window_wayland_unblock_cancel;
+  window_class->set_render_rect = gst_vaapi_window_wayland_set_render_rect;
+
+  signals[SIZE_CHANGED] = g_signal_new ("size-changed",
+      G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL,
+      G_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);
+}
+
+static void
+gst_vaapi_window_wayland_init (GstVaapiWindowWayland * window)
+{
+}
+
+/**
+ * gst_vaapi_window_wayland_new:
+ * @display: a #GstVaapiDisplay
+ * @width: the requested window width, in pixels
+ * @height: the requested windo height, in pixels
+ *
+ * Creates a window with the specified @width and @height. The window
+ * will be attached to the @display and remains invisible to the user
+ * until gst_vaapi_window_show() is called.
+ *
+ * Return value (transfer full): the newly allocated #GstVaapiWindow object
+ */
+GstVaapiWindow *
+gst_vaapi_window_wayland_new (GstVaapiDisplay * display,
+    guint width, guint height)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_WAYLAND (display), NULL);
+
+  return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_WAYLAND, display,
+      GST_VAAPI_ID_INVALID, width, height);
+}
+
+/**
+ * gst_vaapi_window_wayland_new_with_surface:
+ * @display: a #GstVaapiDisplay
+ * @wl_surface: a Wayland surface pointer
+ *
+ * Creates a window with the specified @wl_surface. The window
+ * will be attached to the @display and remains invisible to the user
+ * until gst_vaapi_window_show() is called.
+ *
+ * Return value (transfer full): the newly allocated #GstVaapiWindow object
+ *
+ * Since: 1.18
+ */
+GstVaapiWindow *
+gst_vaapi_window_wayland_new_with_surface (GstVaapiDisplay * display,
+    guintptr wl_surface)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_WAYLAND (display), NULL);
+  g_return_val_if_fail (wl_surface, NULL);
+
+  GST_CAT_DEBUG (gst_debug_vaapi, "new window from surface 0x%"
+      G_GINTPTR_MODIFIER "x", wl_surface);
+
+  return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_WAYLAND, display,
+      wl_surface, 0, 0);
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_wayland.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_wayland.h
new file mode 100644 (file)
index 0000000..016f582
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  gstvaapiwindow_wayland.h - VA/Wayland window abstraction
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_WAYLAND_H
+#define GST_VAAPI_WINDOW_WAYLAND_H
+
+#include <gst/gst.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_WINDOW_WAYLAND (gst_vaapi_window_wayland_get_type ())
+#define GST_VAAPI_WINDOW_WAYLAND(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_WAYLAND, GstVaapiWindowWayland))
+#define GST_VAAPI_IS_WINDOW_WAYLAND(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_WAYLAND))
+
+typedef struct _GstVaapiWindowWayland GstVaapiWindowWayland;
+
+GType
+gst_vaapi_window_wayland_get_type (void) G_GNUC_CONST;
+
+GstVaapiWindow *
+gst_vaapi_window_wayland_new (GstVaapiDisplay * display, guint width,
+    guint height);
+
+GstVaapiWindow *
+gst_vaapi_window_wayland_new_with_surface (GstVaapiDisplay * display,
+    guintptr wl_surface);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowWayland, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_WAYLAND_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_x11.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_x11.c
new file mode 100644 (file)
index 0000000..38fed7a
--- /dev/null
@@ -0,0 +1,585 @@
+/*
+ *  gstvaapiwindow_x11.c - VA/X11 window abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapiwindow_x11
+ * @short_description: VA/X11 window abstraction
+ */
+
+#include "sysdeps.h"
+#include <X11/Xatom.h>
+#include "gstvaapicompat.h"
+#include "gstvaapiwindow_x11.h"
+#include "gstvaapiwindow_x11_priv.h"
+#include "gstvaapidisplay_x11.h"
+#include "gstvaapidisplay_x11_priv.h"
+#include "gstvaapisurface_priv.h"
+#include "gstvaapiutils.h"
+#include "gstvaapiutils_x11.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gst_debug_vaapi_window);
+#define GST_CAT_DEFAULT gst_debug_vaapi_window
+
+#define GST_VAAPI_WINDOW_X11_GET_CLASS(obj) \
+   (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_X11, GstVaapiWindowX11Class))
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiWindowX11, gst_vaapi_window_x11,
+    GST_TYPE_VAAPI_WINDOW);
+
+#define _NET_WM_STATE_REMOVE    0       /* remove/unset property */
+#define _NET_WM_STATE_ADD       1       /* add/set property      */
+#define _NET_WM_STATE_TOGGLE    2       /* toggle property       */
+
+static void
+send_wmspec_change_state (GstVaapiWindow * window, Atom state, gboolean add)
+{
+  GstVaapiWindowX11Private *const priv =
+      GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  XClientMessageEvent xclient;
+
+  memset (&xclient, 0, sizeof (xclient));
+
+  xclient.type = ClientMessage;
+  xclient.window = GST_VAAPI_WINDOW_ID (window);
+  xclient.message_type = priv->atom_NET_WM_STATE;
+  xclient.format = 32;
+
+  xclient.data.l[0] = add ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
+  xclient.data.l[1] = state;
+  xclient.data.l[2] = 0;
+  xclient.data.l[3] = 0;
+  xclient.data.l[4] = 0;
+
+  XSendEvent (dpy,
+      DefaultRootWindow (dpy),
+      False,
+      SubstructureRedirectMask | SubstructureNotifyMask, (XEvent *) & xclient);
+}
+
+static void
+wait_event (GstVaapiWindow * window, int type)
+{
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  const Window xid = GST_VAAPI_WINDOW_ID (window);
+  XEvent e;
+  Bool got_event;
+
+  for (;;) {
+    GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+    got_event = XCheckTypedWindowEvent (dpy, xid, type, &e);
+    GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    if (got_event)
+      break;
+    g_usleep (10);
+  }
+}
+
+static gboolean
+timed_wait_event (GstVaapiWindow * window, int type, guint64 end_time,
+    XEvent * e)
+{
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  const Window xid = GST_VAAPI_WINDOW_ID (window);
+  XEvent tmp_event;
+  guint64 now_time;
+  Bool got_event;
+
+  if (!e)
+    e = &tmp_event;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  got_event = XCheckTypedWindowEvent (dpy, xid, type, e);
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  if (got_event)
+    return TRUE;
+
+  do {
+    g_usleep (10);
+    GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+    got_event = XCheckTypedWindowEvent (dpy, xid, type, e);
+    GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    if (got_event)
+      return TRUE;
+    now_time = g_get_real_time ();
+  } while (now_time < end_time);
+  return FALSE;
+}
+
+static gboolean
+gst_vaapi_window_x11_show (GstVaapiWindow * window)
+{
+  GstVaapiWindowX11Private *const priv =
+      GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  const Window xid = GST_VAAPI_WINDOW_ID (window);
+  XWindowAttributes wattr;
+  gboolean has_errors;
+
+  if (priv->is_mapped)
+    return TRUE;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  x11_trap_errors ();
+  if (window->use_foreign_window) {
+    XGetWindowAttributes (dpy, xid, &wattr);
+    if (!(wattr.your_event_mask & StructureNotifyMask))
+      XSelectInput (dpy, xid, StructureNotifyMask);
+  }
+  XMapWindow (dpy, xid);
+  has_errors = x11_untrap_errors () != 0;
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+
+  if (!has_errors) {
+    wait_event (window, MapNotify);
+    if (window->use_foreign_window &&
+        !(wattr.your_event_mask & StructureNotifyMask)) {
+      GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+      x11_trap_errors ();
+      XSelectInput (dpy, xid, wattr.your_event_mask);
+      has_errors = x11_untrap_errors () != 0;
+      GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    }
+    priv->is_mapped = TRUE;
+
+    if (priv->fullscreen_on_map)
+      gst_vaapi_window_set_fullscreen (window, TRUE);
+  }
+  return !has_errors;
+}
+
+static gboolean
+gst_vaapi_window_x11_hide (GstVaapiWindow * window)
+{
+  GstVaapiWindowX11Private *const priv =
+      GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  const Window xid = GST_VAAPI_WINDOW_ID (window);
+  XWindowAttributes wattr;
+  gboolean has_errors;
+
+  if (!priv->is_mapped)
+    return TRUE;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  x11_trap_errors ();
+  if (window->use_foreign_window) {
+    XGetWindowAttributes (dpy, xid, &wattr);
+    if (!(wattr.your_event_mask & StructureNotifyMask))
+      XSelectInput (dpy, xid, StructureNotifyMask);
+  }
+  XUnmapWindow (dpy, xid);
+  has_errors = x11_untrap_errors () != 0;
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+
+  if (!has_errors) {
+    wait_event (window, UnmapNotify);
+    if (window->use_foreign_window &&
+        !(wattr.your_event_mask & StructureNotifyMask)) {
+      GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+      x11_trap_errors ();
+      XSelectInput (dpy, xid, wattr.your_event_mask);
+      has_errors = x11_untrap_errors () != 0;
+      GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    }
+    priv->is_mapped = FALSE;
+  }
+  return !has_errors;
+}
+
+static gboolean
+gst_vaapi_window_x11_create (GstVaapiWindow * window, guint * width,
+    guint * height)
+{
+  GstVaapiWindowX11Private *const priv =
+      GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
+  GstVaapiDisplay *const display = GST_VAAPI_WINDOW_DISPLAY (window);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  Window xid = GST_VAAPI_WINDOW_ID (window);
+  guint vid = 0;
+  Colormap cmap = None;
+  const GstVaapiDisplayClass *display_class;
+  const GstVaapiWindowClass *window_class;
+  XWindowAttributes wattr;
+  Atom wm_delete, atoms[2];
+  gboolean ok;
+
+  static const char *atom_names[2] = {
+    "_NET_WM_STATE",
+    "_NET_WM_STATE_FULLSCREEN",
+  };
+
+  if (window->use_foreign_window && xid) {
+    GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+    XGetWindowAttributes (dpy, xid, &wattr);
+    priv->is_mapped = wattr.map_state == IsViewable;
+    ok = x11_get_geometry (dpy, xid, NULL, NULL, width, height, NULL);
+    GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    return ok;
+  }
+
+  display_class = GST_VAAPI_DISPLAY_GET_CLASS (display);
+  if (display_class) {
+    if (display_class->get_visual_id)
+      vid = display_class->get_visual_id (display, window);
+    if (display_class->get_colormap)
+      cmap = display_class->get_colormap (display, window);
+  }
+
+  window_class = GST_VAAPI_WINDOW_GET_CLASS (window);
+  if (window_class) {
+    if (window_class->get_visual_id && !vid)
+      vid = window_class->get_visual_id (window);
+    if (window_class->get_colormap && !cmap)
+      cmap = window_class->get_colormap (window);
+  }
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  XInternAtoms (dpy,
+      (char **) atom_names, G_N_ELEMENTS (atom_names), False, atoms);
+  priv->atom_NET_WM_STATE = atoms[0];
+  priv->atom_NET_WM_STATE_FULLSCREEN = atoms[1];
+
+  xid = x11_create_window (dpy, *width, *height, vid, cmap);
+  if (xid) {
+    /* Tell the window manager we'd like delete client messages instead of
+     * being killed */
+    wm_delete = XInternAtom (dpy, "WM_DELETE_WINDOW", True);
+    if (wm_delete != None) {
+      (void) XSetWMProtocols (dpy, xid, &wm_delete, 1);
+    }
+
+    XRaiseWindow (dpy, xid);
+  }
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+
+  GST_DEBUG ("xid %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (xid));
+  GST_VAAPI_WINDOW_ID (window) = xid;
+  return xid != None;
+}
+
+static void
+gst_vaapi_window_x11_finalize (GObject * object)
+{
+  GstVaapiWindow *window = GST_VAAPI_WINDOW (object);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  const Window xid = GST_VAAPI_WINDOW_ID (window);
+
+  if (xid) {
+    if (!window->use_foreign_window) {
+      GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+      XDestroyWindow (dpy, xid);
+      GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+    }
+    GST_VAAPI_WINDOW_ID (window) = None;
+  }
+
+  G_OBJECT_CLASS (gst_vaapi_window_x11_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_vaapi_window_x11_get_geometry (GstVaapiWindow * window,
+    gint * px, gint * py, guint * pwidth, guint * pheight)
+{
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  const Window xid = GST_VAAPI_WINDOW_ID (window);
+  gboolean success;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  success = x11_get_geometry (dpy, xid, px, py, pwidth, pheight, NULL);
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  return success;
+}
+
+static gboolean
+gst_vaapi_window_x11_set_fullscreen (GstVaapiWindow * window,
+    gboolean fullscreen)
+{
+  GstVaapiWindowX11Private *const priv =
+      GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
+  Display *const dpy = GST_VAAPI_WINDOW_NATIVE_DISPLAY (window);
+  const Window xid = GST_VAAPI_WINDOW_ID (window);
+  XEvent e;
+  guint width, height;
+  gboolean has_errors;
+  guint64 end_time;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  x11_trap_errors ();
+  if (fullscreen) {
+    if (!priv->is_mapped) {
+      priv->fullscreen_on_map = TRUE;
+
+      XChangeProperty (dpy,
+          xid,
+          priv->atom_NET_WM_STATE, XA_ATOM, 32,
+          PropModeReplace,
+          (unsigned char *) &priv->atom_NET_WM_STATE_FULLSCREEN, 1);
+    } else {
+      send_wmspec_change_state (window,
+          priv->atom_NET_WM_STATE_FULLSCREEN, TRUE);
+    }
+  } else {
+    if (!priv->is_mapped) {
+      priv->fullscreen_on_map = FALSE;
+
+      XDeleteProperty (dpy, xid, priv->atom_NET_WM_STATE);
+    } else {
+      send_wmspec_change_state (window,
+          priv->atom_NET_WM_STATE_FULLSCREEN, FALSE);
+    }
+  }
+  XSync (dpy, False);
+  has_errors = x11_untrap_errors () != 0;
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  if (has_errors)
+    return FALSE;
+
+  /* Try to wait for the completion of the fullscreen mode switch */
+  if (!window->use_foreign_window && priv->is_mapped) {
+    const guint DELAY = 100000; /* 100 ms */
+    end_time = DELAY + g_get_real_time ();
+    while (timed_wait_event (window, ConfigureNotify, end_time, &e)) {
+      if (fullscreen) {
+        gst_vaapi_display_get_size (GST_VAAPI_WINDOW_DISPLAY (window),
+            &width, &height);
+        if (e.xconfigure.width == width && e.xconfigure.height == height)
+          return TRUE;
+      } else {
+        gst_vaapi_window_get_size (window, &width, &height);
+        if (e.xconfigure.width != width || e.xconfigure.height != height)
+          return TRUE;
+      }
+    }
+  }
+  return FALSE;
+}
+
+static gboolean
+gst_vaapi_window_x11_resize (GstVaapiWindow * window, guint width, guint height)
+{
+  gboolean has_errors;
+
+  if (!GST_VAAPI_WINDOW_ID (window))
+    return FALSE;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  x11_trap_errors ();
+  XResizeWindow (GST_VAAPI_WINDOW_NATIVE_DISPLAY (window),
+      GST_VAAPI_WINDOW_ID (window), width, height);
+  has_errors = x11_untrap_errors () != 0;
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+  return !has_errors;
+}
+
+static VAStatus
+gst_vaapi_window_x11_put_surface (GstVaapiWindow * window,
+    VASurfaceID surface_id,
+    const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect, guint flags)
+{
+  VAStatus status;
+
+  GST_VAAPI_WINDOW_LOCK_DISPLAY (window);
+  status = vaPutSurface (GST_VAAPI_WINDOW_VADISPLAY (window),
+      surface_id,
+      GST_VAAPI_WINDOW_ID (window),
+      src_rect->x,
+      src_rect->y,
+      src_rect->width,
+      src_rect->height,
+      dst_rect->x,
+      dst_rect->y,
+      dst_rect->width,
+      dst_rect->height, NULL, 0, from_GstVaapiSurfaceRenderFlags (flags)
+      );
+
+  GST_VAAPI_WINDOW_UNLOCK_DISPLAY (window);
+
+  return status;
+}
+
+static gboolean
+gst_vaapi_window_x11_render (GstVaapiWindow * window,
+    GstVaapiSurface * surface,
+    const GstVaapiRectangle * src_rect,
+    const GstVaapiRectangle * dst_rect, guint flags)
+{
+  VASurfaceID surface_id;
+  VAStatus status;
+  GstVaapiWindowX11Private *const priv =
+      GST_VAAPI_WINDOW_X11_GET_PRIVATE (window);
+  gboolean ret = FALSE;
+
+  surface_id = GST_VAAPI_SURFACE_ID (surface);
+  if (surface_id == VA_INVALID_ID)
+    return FALSE;
+
+  if (window->has_vpp && priv->need_vpp)
+    goto conversion;
+
+  status =
+      gst_vaapi_window_x11_put_surface (window, surface_id, src_rect, dst_rect,
+      flags);
+
+  if (status == VA_STATUS_ERROR_FLAG_NOT_SUPPORTED ||
+      status == VA_STATUS_ERROR_UNIMPLEMENTED ||
+      status == VA_STATUS_ERROR_INVALID_IMAGE_FORMAT) {
+    priv->need_vpp = TRUE;
+  } else {
+    ret = vaapi_check_status (status, "vaPutSurface()");
+  }
+
+conversion:
+  if (priv->need_vpp && window->has_vpp) {
+    GstVaapiSurface *const vpp_surface =
+        gst_vaapi_window_vpp_convert_internal (window, surface, NULL, NULL,
+        flags);
+    if (G_LIKELY (vpp_surface)) {
+      GstVaapiRectangle vpp_src_rect;
+
+      surface_id = GST_VAAPI_SURFACE_ID (vpp_surface);
+      vpp_src_rect.x = vpp_src_rect.y = 0;
+      vpp_src_rect.width = GST_VAAPI_SURFACE_WIDTH (vpp_surface);
+      vpp_src_rect.height = GST_VAAPI_SURFACE_HEIGHT (vpp_surface);
+
+      status =
+          gst_vaapi_window_x11_put_surface (window, surface_id, &vpp_src_rect,
+          dst_rect, flags);
+
+      ret = vaapi_check_status (status, "vaPutSurface()");
+
+      if (!gst_vaapi_surface_sync (vpp_surface)) {
+        GST_WARNING ("failed to render surface");
+        ret = FALSE;
+      }
+
+      gst_vaapi_video_pool_put_object (window->surface_pool, vpp_surface);
+    } else {
+      priv->need_vpp = FALSE;
+    }
+  }
+
+  return ret;
+}
+
+static void
+gst_vaapi_window_x11_class_init (GstVaapiWindowX11Class * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstVaapiWindowClass *const window_class = GST_VAAPI_WINDOW_CLASS (klass);
+
+  object_class->finalize = gst_vaapi_window_x11_finalize;
+
+  window_class->create = gst_vaapi_window_x11_create;
+  window_class->show = gst_vaapi_window_x11_show;
+  window_class->hide = gst_vaapi_window_x11_hide;
+  window_class->get_geometry = gst_vaapi_window_x11_get_geometry;
+  window_class->set_fullscreen = gst_vaapi_window_x11_set_fullscreen;
+  window_class->resize = gst_vaapi_window_x11_resize;
+  window_class->render = gst_vaapi_window_x11_render;
+}
+
+static void
+gst_vaapi_window_x11_init (GstVaapiWindowX11 * window)
+{
+}
+
+/**
+ * gst_vaapi_window_x11_new:
+ * @display: a #GstVaapiDisplay
+ * @width: the requested window width, in pixels
+ * @height: the requested windo height, in pixels
+ *
+ * Creates a window with the specified @width and @height. The window
+ * will be attached to the @display and remains invisible to the user
+ * until gst_vaapi_window_show() is called.
+ *
+ * Return value: the newly allocated #GstVaapiWindow object
+ */
+GstVaapiWindow *
+gst_vaapi_window_x11_new (GstVaapiDisplay * display, guint width, guint height)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), NULL);
+
+  return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_X11, display,
+      GST_VAAPI_ID_INVALID, width, height);
+}
+
+/**
+ * gst_vaapi_window_x11_new_with_xid:
+ * @display: a #GstVaapiDisplay
+ * @xid: an X11 Window id
+ *
+ * Creates a #GstVaapiWindow using the X11 Window @xid. The caller
+ * still owns the window and must call XDestroyWindow() when all
+ * #GstVaapiWindow references are released. Doing so too early can
+ * yield undefined behaviour.
+ *
+ * Return value: the newly allocated #GstVaapiWindow object
+ */
+GstVaapiWindow *
+gst_vaapi_window_x11_new_with_xid (GstVaapiDisplay * display, Window xid)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_DISPLAY_X11 (display), NULL);
+  g_return_val_if_fail (xid != None, NULL);
+
+  return gst_vaapi_window_new_internal (GST_TYPE_VAAPI_WINDOW_X11, display,
+      xid, 0, 0);
+}
+
+/**
+ * gst_vaapi_window_x11_get_xid:
+ * @window: a #GstVaapiWindowX11
+ *
+ * Returns the underlying X11 Window that was created by
+ * gst_vaapi_window_x11_new() or that was bound with
+ * gst_vaapi_window_x11_new_with_xid().
+ *
+ * Return value: the underlying X11 Window bound to @window.
+ */
+Window
+gst_vaapi_window_x11_get_xid (GstVaapiWindowX11 * window)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW_X11 (window), None);
+
+  return GST_VAAPI_WINDOW_ID (window);
+}
+
+/**
+ * gst_vaapi_window_x11_is_foreign_xid:
+ * @window: a #GstVaapiWindowX11
+ *
+ * Checks whether the @window XID was created by gst_vaapi_window_x11_new() or bound with gst_vaapi_window_x11_new_with_xid().
+ *
+ * Return value: %TRUE if the underlying X window is owned by the
+ *   caller (foreign window)
+ */
+gboolean
+gst_vaapi_window_x11_is_foreign_xid (GstVaapiWindowX11 * window)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_WINDOW_X11 (window), FALSE);
+
+  return GST_VAAPI_WINDOW (window)->use_foreign_window;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_x11.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_x11.h
new file mode 100644 (file)
index 0000000..672e1ff
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ *  gstvaapiwindow_x11.h - VA/X11 window abstraction
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_X11_H
+#define GST_VAAPI_WINDOW_X11_H
+
+#include <X11/Xlib.h>
+#include <gst/gst.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_WINDOW_X11 (gst_vaapi_window_x11_get_type ())
+#define GST_VAAPI_WINDOW_X11(obj) \
+    (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_WINDOW_X11, GstVaapiWindowX11))
+#define GST_VAAPI_IS_WINDOW_X11(obj) \
+    (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_WINDOW_X11))
+
+/**
+ * GST_VAAPI_WINDOW_XWINDOW:
+ * @window: a #GstVaapiWindow
+ *
+ * Macro that evaluates to the underlying X11 Window of @window
+ */
+#define GST_VAAPI_WINDOW_XWINDOW(window) \
+    gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (window))
+
+typedef struct _GstVaapiWindowX11 GstVaapiWindowX11;
+
+GType
+gst_vaapi_window_x11_get_type (void) G_GNUC_CONST;
+
+GstVaapiWindow *
+gst_vaapi_window_x11_new (GstVaapiDisplay * display, guint width, guint height);
+
+GstVaapiWindow *
+gst_vaapi_window_x11_new_with_xid (GstVaapiDisplay * display, Window xid);
+
+Window
+gst_vaapi_window_x11_get_xid (GstVaapiWindowX11 * window);
+
+gboolean
+gst_vaapi_window_x11_is_foreign_xid (GstVaapiWindowX11 * window);
+
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GstVaapiWindowX11, gst_object_unref)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_X11_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiwindow_x11_priv.h
new file mode 100644 (file)
index 0000000..751647f
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ *  gstvaapiwindow_x11_priv.h - VA/X11 window abstraction (private definitions)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_WINDOW_X11_PRIV_H
+#define GST_VAAPI_WINDOW_X11_PRIV_H
+
+#include "gstvaapiwindow_priv.h"
+
+#if HAVE_XRENDER
+# include <X11/extensions/Xrender.h>
+#endif
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_WINDOW_X11_CAST(obj) ((GstVaapiWindowX11 *)(obj))
+#define GST_VAAPI_WINDOW_X11_GET_PRIVATE(obj) \
+    gst_vaapi_window_x11_get_instance_private (GST_VAAPI_WINDOW_X11_CAST (obj))
+
+#define GST_VAAPI_WINDOW_X11_GET_CLASS(obj) \
+    (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_WINDOW_X11, GstVaapiWindowX11Class))
+
+typedef struct _GstVaapiWindowX11Private GstVaapiWindowX11Private;
+typedef struct _GstVaapiWindowX11Class GstVaapiWindowX11Class;
+
+struct _GstVaapiWindowX11Private
+{
+  Atom atom_NET_WM_STATE;
+  Atom atom_NET_WM_STATE_FULLSCREEN;
+  guint is_mapped:1;
+  guint fullscreen_on_map:1;
+  gboolean need_vpp;
+};
+
+/**
+ * GstVaapiWindowX11:
+ *
+ * An X11 Window wrapper.
+ */
+struct _GstVaapiWindowX11
+{
+  /*< private >*/
+  GstVaapiWindow parent_instance;
+};
+
+/**
+ * GstVaapiWindowX11Class:
+ *
+ * An X11 Window wrapper class.
+ */
+struct _GstVaapiWindowX11Class
+{
+  /*< private >*/
+  GstVaapiWindowClass parent_class;
+};
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WINDOW_X11_PRIV_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiworkarounds.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/gstvaapiworkarounds.h
new file mode 100644 (file)
index 0000000..967ef3e
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *  gstvaapiworkaround.h - GStreamer/VA workarounds
+ *
+ *  Copyright (C) 2011-2012 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_WORKAROUNDS_H
+#define GST_VAAPI_WORKAROUNDS_H
+
+G_BEGIN_DECLS
+
+/*
+ * Workaround to expose H.263 Baseline decode profile for drivers that
+ * support MPEG-4:2 Simple profile decoding.
+ */
+#define WORKAROUND_H263_BASELINE_DECODE_PROFILE (1)
+
+/*
+ * Workaround for qtdemux that does not report profiles for
+ * video/x-h263. Assume H.263 Baseline profile in this case.
+ */
+#define WORKAROUND_QTDEMUX_NO_H263_PROFILES (1)
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_WORKAROUNDS_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/meson.build b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/meson.build
new file mode 100644 (file)
index 0000000..2e15063
--- /dev/null
@@ -0,0 +1,240 @@
+gstlibvaapi_sources = [
+  'gstvaapiblend.c',
+  'gstvaapibufferproxy.c',
+  'gstvaapicodec_objects.c',
+  'gstvaapicontext.c',
+  'gstvaapidecoder.c',
+  'gstvaapidecoder_dpb.c',
+  'gstvaapidecoder_h264.c',
+  'gstvaapidecoder_h265.c',
+  'gstvaapidecoder_jpeg.c',
+  'gstvaapidecoder_mpeg2.c',
+  'gstvaapidecoder_mpeg4.c',
+  'gstvaapidecoder_objects.c',
+  'gstvaapidecoder_unit.c',
+  'gstvaapidecoder_vc1.c',
+  'gstvaapidecoder_vp8.c',
+  'gstvaapidecoder_vp9.c',
+  'gstvaapidisplay.c',
+  'gstvaapifilter.c',
+  'gstvaapiimage.c',
+  'gstvaapiimagepool.c',
+  'gstvaapiminiobject.c',
+  'gstvaapiparser_frame.c',
+  'gstvaapiprofile.c',
+  'gstvaapiprofilecaps.c',
+  'gstvaapisubpicture.c',
+  'gstvaapisurface.c',
+  'gstvaapisurface_drm.c',
+  'gstvaapisurfacepool.c',
+  'gstvaapisurfaceproxy.c',
+  'gstvaapitexture.c',
+  'gstvaapitexturemap.c',
+  'gstvaapiutils.c',
+  'gstvaapiutils_core.c',
+  'gstvaapiutils_h264.c',
+  'gstvaapiutils_h265.c',
+  'gstvaapiutils_h26x.c',
+  'gstvaapiutils_mpeg2.c',
+  'gstvaapiutils_vpx.c',
+  'gstvaapivalue.c',
+  'gstvaapivideopool.c',
+  'gstvaapiwindow.c',
+  'video-format.c',
+]
+
+gstlibvaapi_headers = [
+  'gstvaapiblend.h',
+  'gstvaapibufferproxy.h',
+  'gstvaapidecoder.h',
+  'gstvaapidecoder_h264.h',
+  'gstvaapidecoder_h265.h',
+  'gstvaapidecoder_jpeg.h',
+  'gstvaapidecoder_mpeg2.h',
+  'gstvaapidecoder_mpeg4.h',
+  'gstvaapidecoder_vc1.h',
+  'gstvaapidecoder_vp8.h',
+  'gstvaapidecoder_vp9.h',
+  'gstvaapidisplay.h',
+  'gstvaapifilter.h',
+  'gstvaapiimage.h',
+  'gstvaapiimagepool.h',
+  'gstvaapiprofile.h',
+  'gstvaapiprofilecaps.h',
+  'gstvaapisubpicture.h',
+  'gstvaapisurface.h',
+  'gstvaapisurface_drm.h',
+  'gstvaapisurfacepool.h',
+  'gstvaapisurfaceproxy.h',
+  'gstvaapitexture.h',
+  'gstvaapitexturemap.h',
+  'gstvaapitypes.h',
+  'gstvaapiutils_h264.h',
+  'gstvaapiutils_h265.h',
+  'gstvaapiutils_mpeg2.h',
+  'gstvaapiutils_vpx.h',
+  'gstvaapivalue.h',
+  'gstvaapivideopool.h',
+  'gstvaapiwindow.h',
+  'video-format.h',
+]
+
+if USE_ENCODERS
+  gstlibvaapi_sources += [
+      'gstvaapicodedbuffer.c',
+      'gstvaapicodedbufferpool.c',
+      'gstvaapicodedbufferproxy.c',
+      'gstvaapiencoder.c',
+      'gstvaapiencoder_h264.c',
+      'gstvaapiencoder_h265.c',
+      'gstvaapiencoder_jpeg.c',
+      'gstvaapiencoder_mpeg2.c',
+      'gstvaapiencoder_objects.c',
+      'gstvaapiencoder_vp8.c',
+    ]
+  gstlibvaapi_headers += [
+      'gstvaapicodedbuffer.h',
+      'gstvaapicodedbufferpool.h',
+      'gstvaapicodedbufferproxy.h',
+      'gstvaapiencoder.h',
+      'gstvaapiencoder_h264.h',
+      'gstvaapiencoder_h265.h',
+      'gstvaapiencoder_jpeg.h',
+      'gstvaapiencoder_mpeg2.h',
+      'gstvaapiencoder_vp8.h',
+    ]
+endif
+
+if USE_VP9_ENCODER
+  gstlibvaapi_sources += 'gstvaapiencoder_vp9.c'
+  gstlibvaapi_headers += 'gstvaapiencoder_vp9.h'
+endif
+
+if USE_AV1_DECODER
+  gstlibvaapi_sources += 'gstvaapidecoder_av1.c'
+  gstlibvaapi_headers += 'gstvaapidecoder_av1.h'
+endif
+
+if USE_DRM
+  gstlibvaapi_sources += [
+      'gstvaapidisplay_drm.c',
+      'gstvaapiwindow_drm.c',
+    ]
+  gstlibvaapi_headers += [
+      'gstvaapidisplay_drm.h',
+      'gstvaapiwindow_drm.h',
+    ]
+endif
+
+if USE_X11
+  gstlibvaapi_sources += [
+      'gstvaapidisplay_x11.c',
+      'gstvaapiutils_x11.c',
+      'gstvaapiwindow_x11.c',
+    ]
+  gstlibvaapi_headers += [
+      'gstvaapidisplay_x11.h',
+      'gstvaapiwindow_x11.h',
+    ]
+endif
+
+if USE_GLX
+  gstlibvaapi_sources += [
+      'gstvaapidisplay_glx.c',
+      'gstvaapitexture_glx.c',
+      'gstvaapiutils_glx.c',
+      'gstvaapiwindow_glx.c',
+    ]
+  gstlibvaapi_headers += [
+      'gstvaapidisplay_glx.h',
+      'gstvaapitexture.h',
+      'gstvaapitexture_glx.h',
+      'gstvaapiwindow_glx.h',
+    ]
+endif
+
+if USE_EGL
+  gstlibvaapi_sources += [
+      'gstvaapidisplay_egl.c',
+      'gstvaapisurface_egl.c',
+      'gstvaapitexture_egl.c',
+      'gstvaapiutils_egl.c',
+      'gstvaapiwindow_egl.c',
+    ]
+  gstlibvaapi_headers += [
+      'gstvaapidisplay_egl.h',
+      'gstvaapisurface_egl.h',
+      'gstvaapitexture_egl.h',
+      'gstvaapiwindow_egl.h',
+    ]
+endif
+
+if USE_WAYLAND
+  # The XDG shell interface needs to be generated first
+  wayland_protocols_basedir = wayland_protocols_dep.get_variable('pkgdatadir')
+  xdg_shell_xml_spec = join_paths(wayland_protocols_basedir, 'stable', 'xdg-shell', 'xdg-shell.xml')
+  xdg_shell_header = custom_target('vaapi-xdg-shell-client-header',
+      command: [ wayland_scanner_bin, 'client-header', '@INPUT@', '@OUTPUT@' ],
+      input: xdg_shell_xml_spec,
+      output: 'xdg-shell-client-protocol.h')
+  xdg_shell_code = custom_target('vaapi-xdg-shell-client-code',
+      command: [ wayland_scanner_bin, 'private-code', '@INPUT@', '@OUTPUT@' ],
+      input: xdg_shell_xml_spec,
+      output: 'xdg-shell-client-protocol.c')
+  dmabuf_xml_spec = join_paths(wayland_protocols_basedir, 'unstable', 'linux-dmabuf', 'linux-dmabuf-unstable-v1.xml')
+  dmabuf_header = custom_target('vaapi-dmabuf-client-header',
+      command: [ wayland_scanner_bin, 'client-header', '@INPUT@', '@OUTPUT@' ],
+      input: dmabuf_xml_spec,
+      output: 'linux-dmabuf-unstable-v1-client-protocol.h')
+  dmabuf_code = custom_target('vaapi-dmabuf-client-code',
+      command: [ wayland_scanner_bin, 'private-code', '@INPUT@', '@OUTPUT@' ],
+      input: dmabuf_xml_spec,
+      output: 'linux-dmabuf-unstable-v1-client-protocol.c')
+
+  gstlibvaapi_sources += [
+      'gstvaapidisplay_wayland.c',
+      'gstvaapiwindow_wayland.c',
+      xdg_shell_header,
+      xdg_shell_code,
+      dmabuf_header,
+      dmabuf_code,
+  ]
+  gstlibvaapi_headers += [
+      'gstvaapidisplay_wayland.h',
+      'gstvaapiwindow_wayland.h',
+    ]
+endif
+
+gstlibvaapi_deps = [ gstbase_dep,
+                     gstvideo_dep,
+                     gstgl_dep,
+                     gstglproto_dep,
+                     gstcodecparsers_dep,
+                     libva_dep,
+                     libm ]
+if USE_DRM
+  gstlibvaapi_deps  += [libva_drm_dep, libdrm_dep, libudev_dep]
+endif
+if USE_EGL
+  gstlibvaapi_deps  += [egl_dep, gmodule_dep, gstglegl_dep]
+endif
+if USE_GLX
+  gstlibvaapi_deps  += [libva_x11_dep, x11_dep, gl_dep, libdl_dep]
+endif
+if USE_WAYLAND
+  gstlibvaapi_deps  += [libva_wayland_dep, gstglwayland_dep, wayland_client_dep, wayland_protocols_dep]
+endif
+if USE_X11
+  gstlibvaapi_deps  += [libva_x11_dep, x11_dep, xrandr_dep, gstglx11_dep]
+endif
+
+gstlibvaapi = static_library('gstlibvaapi-@0@'.format(api_version),
+  gstlibvaapi_sources + gstlibvaapi_headers,
+  c_args : gstreamer_vaapi_args + [ '-DGST_USE_UNSTABLE_API', '-DGST_VAAPI_VERSION_ID="@0@"'.format(gst_version)],
+  include_directories: [configinc, libsinc],
+  dependencies : gstlibvaapi_deps,
+)
+
+gstlibvaapi_dep = declare_dependency(link_with: gstlibvaapi,
+  include_directories : [libsinc],
+  dependencies : gstlibvaapi_deps)
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/ogl_compat.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/ogl_compat.h
new file mode 100644 (file)
index 0000000..2fa40e7
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * ogl_compat.h - OpenGL compatiliby layer
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *   Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301
+ */
+
+#ifndef OGL_COMPAT_H
+#define OGL_COMPAT_H
+
+typedef void                    GLvoid;
+typedef char                    GLchar;
+typedef unsigned char           GLubyte;
+typedef unsigned char           GLboolean;
+typedef int                     GLint;
+typedef unsigned int            GLuint;
+typedef int                     GLsizei;
+typedef float                   GLfloat;
+typedef double                  GLdouble;
+typedef GLuint                  GLenum;
+typedef GLuint                  GLbitfield;
+typedef GLfloat                 GLclampf;
+
+#define GL_VENDOR               0x1F00
+#define GL_RENDERER             0x1F01
+#define GL_VERSION              0x1F02
+#define GL_EXTENSIONS           0x1F03
+#define GL_NEAREST              0x2600
+#define GL_LINEAR               0x2601
+
+#define GL_DEPTH_BUFFER_BIT     0x00000100
+#define GL_COLOR_BUFFER_BIT     0x00004000
+#define GL_FALSE                0
+#define GL_TRUE                 1
+#define GL_NONE                 0
+
+#define GL_BLEND                0x0BE2
+#define GL_DEPTH_TEST           0x0B71
+
+#define GL_TEXTURE0             0x84C0
+#define GL_TEXTURE1             0x84C1
+#define GL_TEXTURE2             0x84C2
+#define GL_TEXTURE3             0x84C3
+#define GL_TEXTURE_2D           0x0DE1
+#define GL_TEXTURE_EXTERNAL_OES 0x8D65
+#define GL_TEXTURE_MAG_FILTER   0x2800
+#define GL_TEXTURE_MIN_FILTER   0x2801
+#define GL_TEXTURE_WRAP_S       0x2802
+#define GL_TEXTURE_WRAP_T       0x2803
+
+#define GL_UNPACK_ALIGNMENT     0x0cf5
+
+#define GL_TRIANGLE_FAN         0x0006
+
+#define GL_BYTE                 0x1400
+#define GL_UNSIGNED_BYTE        0x1401
+#define GL_SHORT                0x1402
+#define GL_UNSIGNED_SHORT       0x1403
+#define GL_INT                  0x1404
+#define GL_UNSIGNED_INT         0x1405
+#define GL_FLOAT                0x1406
+
+#define GL_ALPHA                0x1906
+#define GL_RGB                  0x1907
+#define GL_RGBA                 0x1908
+#define GL_LUMINANCE            0x1909
+#define GL_LUMINANCE_ALPHA      0x190A
+
+#define GL_REPEAT               0x2901
+#define GL_CLAMP_TO_EDGE        0x812F
+
+#define GL_VERTEX_ARRAY         0x8074
+#define GL_TEXTURE_COORD_ARRAY  0x8078
+
+#define GL_FRAGMENT_SHADER      0x8B30
+#define GL_VERTEX_SHADER        0x8B31
+#define GL_COMPILE_STATUS       0x8B81
+#define GL_LINK_STATUS          0x8B82
+#define GL_INFO_LOG_LENGTH      0x8B84
+
+#define GL_BGRA_EXT             0x80e1
+#ifndef GL_R8
+#define GL_R8                   GL_R8_EXT
+#endif
+#ifndef GL_RG8
+#define GL_RG8                  GL_RG8_EXT
+#endif
+
+#endif /* OGL_COMPAT_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/sysdeps.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/sysdeps.h
new file mode 100644 (file)
index 0000000..5e6dafb
--- /dev/null
@@ -0,0 +1,36 @@
+/*
+ *  sysdeps.h - System-dependent definitions
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef SYSDEPS_H
+#define SYSDEPS_H
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <gst/gst.h>
+
+#endif /* SYSDEPS_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/video-format.c b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/video-format.c
new file mode 100644 (file)
index 0000000..916f66a
--- /dev/null
@@ -0,0 +1,697 @@
+/*
+ *  video-format.h - Video format helpers for VA-API
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:videoformat
+ * @short_description: Video format helpers for VA-API
+ */
+
+#include "sysdeps.h"
+#include "gstvaapicompat.h"
+#include "gstvaapisurface.h"
+#include "video-format.h"
+
+#define DEBUG 1
+#include "gst/vaapi/gstvaapidebug.h"
+
+#if GST_VAAPI_USE_DRM
+#include <drm_fourcc.h>
+#endif
+
+typedef struct _GstVideoFormatMapMap
+{
+  GstVideoFormat format;
+  uint32_t drm_format;
+  GstVaapiChromaType chroma_type;
+  VAImageFormat va_format;
+} GstVideoFormatMap;
+
+#define VA_BYTE_ORDER_NOT_CARE 0
+
+#if GST_VAAPI_USE_DRM
+#define MAKE_DRM_FORMAT(DRM_FORMAT) G_PASTE(DRM_FORMAT_,DRM_FORMAT)
+#else
+#define MAKE_DRM_FORMAT(DRM_FORMAT) 0
+#endif
+
+#define DEF_YUV(BYTE_ORDER, FORMAT, DRM_FORMAT, FOURCC, BPP, SUB)       \
+  { G_PASTE(GST_VIDEO_FORMAT_,FORMAT),                                  \
+    MAKE_DRM_FORMAT(DRM_FORMAT),                                        \
+    G_PASTE(GST_VAAPI_CHROMA_TYPE_YUV,SUB),                             \
+    { VA_FOURCC FOURCC, BYTE_ORDER, BPP, }, }
+
+#define DEF_RGB(BYTE_ORDER, FORMAT, DRM, FOURCC, BPP, DEPTH, R,G,B,A)   \
+  { G_PASTE(GST_VIDEO_FORMAT_,FORMAT),                                  \
+    MAKE_DRM_FORMAT(DRM),                                               \
+    G_PASTE(GST_VAAPI_CHROMA_TYPE_RGB,BPP),                             \
+    { VA_FOURCC FOURCC, BYTE_ORDER, BPP, DEPTH, R, G, B, A }, }
+
+/* Image formats, listed in HW order preference */
+/* XXX: The new added video format must be added to
+ * GST_VAAPI_FORMATS_ALL in header file to make it available to all
+ * vaapi element's pad cap template. */
+/* *INDENT-OFF* */
+static const GstVideoFormatMap gst_vaapi_video_default_formats[] = {
+  /* LSB and MSB video formats definitions are unclear and ambiguous.
+   *
+   * For MSB, there is no ambiguity: same order in define, memory and
+   * CPU. For example,
+   *
+   *  RGBA is RGBA in memory and RGBA with channel mask R:0xFF0000
+   *  G:0x00FF0000 B:0x0000FF00 A:0x000000FF in CPU.
+   *
+   * For LSB, CPU's perspective and memory's perspective are
+   * different. For example,
+   *
+   *  RGBA in LSB, from CPU's perspective, it's RGBA order in memory,
+   *  but when it is stored in memory, because CPU's little
+   *  endianness, it will be re-ordered, with mask R:0x000000FF
+   *  G:0x0000FF00 B:0x00FF0000 A:0xFF000000. In other words, from
+   *  memory's perspective, RGBA LSB is equal as ABGR MSB.
+   *
+   * These definitions are mixed used all over the media system and we
+   * need to correct the mapping form VA video format to GStreamer
+   * video format in both manners, especially for RGB format.
+   */
+
+  /* YUV formats */
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, NV12, NV12, ('N', 'V', '1', '2'), 12, 420),
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, YV12, YVU420, ('Y', 'V', '1', '2'), 12, 420),
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, I420, YUV420, ('I', '4', '2', '0'), 12, 420),
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, YUY2, YUYV, ('Y', 'U', 'Y', '2'), 16, 422),
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, UYVY, UYVY, ('U', 'Y', 'V', 'Y'), 16, 422),
+
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y444, YUV444, ('4', '4', '4', 'P'), 24, 444),
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, GRAY8, INVALID, ('Y', '8', '0', '0'), 8, 400),
+
+  DEF_YUV (VA_LSB_FIRST, P010_10LE, P010, ('P', '0', '1', '0'), 24, 420_10BPP),
+  DEF_YUV (VA_LSB_FIRST, P012_LE, P012, ('P', '0', '1', '2'), 24, 420_12BPP),
+  /* AYUV is a clear defined format by doc */
+  DEF_YUV (VA_LSB_FIRST, VUYA, AYUV, ('A', 'Y', 'U', 'V'), 32, 444),
+
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y210, Y210, ('Y', '2', '1', '0'), 32, 422_10BPP),
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y410, Y410, ('Y', '4', '1', '0'), 32, 444_10BPP),
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y212_LE, Y212, ('Y', '2', '1', '2'), 32, 422_12BPP),
+  DEF_YUV (VA_BYTE_ORDER_NOT_CARE, Y412_LE, Y412, ('Y', '4', '1', '2'), 32, 444_12BPP),
+
+  /* RGB formats */
+  DEF_RGB (VA_LSB_FIRST, ARGB, BGRA8888, ('A', 'R', 'G', 'B'), 32, 32, 0x0000ff00,
+      0x00ff0000, 0xff000000, 0x000000ff),
+  DEF_RGB (VA_LSB_FIRST, ARGB, BGRA8888, ('B', 'G', 'R', 'A'), 32, 32, 0x0000ff00,
+      0x00ff0000, 0xff000000, 0x000000ff),
+  DEF_RGB (VA_MSB_FIRST, ARGB, BGRA8888, ('A', 'R', 'G', 'B'), 32, 32, 0x00ff0000,
+      0x0000ff00, 0x000000ff, 0xff000000),
+
+  DEF_RGB (VA_LSB_FIRST, xRGB, BGRX8888, ('X', 'R', 'G', 'B'), 32, 24, 0x0000ff00,
+      0x00ff0000, 0xff000000, 0x00000000),
+  DEF_RGB (VA_LSB_FIRST, xRGB, BGRX8888, ('B', 'G', 'R', 'X'), 32, 24, 0x0000ff00,
+      0x00ff0000, 0xff000000, 0x00000000),
+  DEF_RGB (VA_MSB_FIRST, xRGB, BGRX8888, ('X', 'R', 'G', 'B'), 32, 24, 0x00ff0000,
+      0x0000ff00, 0x000000ff, 0x00000000),
+
+  DEF_RGB (VA_LSB_FIRST, RGBA, ABGR8888, ('R', 'G', 'B', 'A'), 32, 32, 0x000000ff,
+      0x0000ff00, 0x00ff0000, 0xff000000),
+  DEF_RGB (VA_LSB_FIRST, RGBA, ABGR8888, ('A', 'B', 'G', 'R'), 32, 32, 0x000000ff,
+      0x0000ff00, 0x00ff0000, 0xff000000),
+  DEF_RGB (VA_MSB_FIRST, RGBA, ABGR8888, ('R', 'G', 'B', 'A'), 32, 32, 0xff000000,
+      0x00ff0000, 0x0000ff00, 0x000000ff),
+
+  DEF_RGB (VA_LSB_FIRST, RGBx, XBGR8888, ('R', 'G', 'B', 'X'), 32, 24, 0x000000ff,
+      0x0000ff00, 0x00ff0000, 0x00000000),
+  DEF_RGB (VA_LSB_FIRST, RGBx, XBGR8888, ('X', 'B', 'G', 'R'), 32, 24, 0x000000ff,
+      0x0000ff00, 0x00ff0000, 0x00000000),
+  DEF_RGB (VA_MSB_FIRST, RGBx, XBGR8888, ('R', 'G', 'B', 'X'), 32, 24, 0xff000000,
+      0x00ff0000, 0x0000ff00, 0x00000000),
+
+  DEF_RGB (VA_LSB_FIRST, ABGR, RGBA8888, ('A', 'B', 'G', 'R'), 32, 32, 0xff000000,
+      0x00ff0000, 0x0000ff00, 0x000000ff),
+  DEF_RGB (VA_LSB_FIRST, ABGR, RGBA8888, ('R', 'G', 'B', 'A'), 32, 32, 0xff000000,
+      0x00ff0000, 0x0000ff00, 0x000000ff),
+  DEF_RGB (VA_MSB_FIRST, ABGR, RGBA8888, ('A', 'B', 'G', 'R'), 32, 32, 0x000000ff,
+      0x0000ff00, 0x00ff0000, 0xff000000),
+
+  DEF_RGB (VA_LSB_FIRST, xBGR, RGBX8888, ('X', 'B', 'G', 'R'), 32, 24, 0xff000000,
+      0x00ff0000, 0x0000ff00, 0x00000000),
+  DEF_RGB (VA_LSB_FIRST, xBGR, RGBX8888, ('R', 'G', 'B', 'X'), 32, 24, 0xff000000,
+      0x00ff0000, 0x0000ff00, 0x00000000),
+  DEF_RGB (VA_MSB_FIRST, xBGR, RGBX8888, ('X', 'B', 'G', 'R'), 32, 24, 0x000000ff,
+      0x0000ff00, 0x00ff0000, 0x00000000),
+
+  DEF_RGB (VA_LSB_FIRST, BGRA, ARGB8888, ('B', 'G', 'R', 'A'), 32, 32, 0x00ff0000,
+      0x0000ff00, 0x000000ff, 0xff000000),
+  DEF_RGB (VA_LSB_FIRST, BGRA, ARGB8888, ('A', 'R', 'G', 'B'), 32, 32, 0x00ff0000,
+      0x0000ff00, 0x000000ff, 0xff000000),
+  DEF_RGB (VA_MSB_FIRST, BGRA, ARGB8888, ('B', 'G', 'R', 'A'), 32, 32, 0x0000ff00,
+      0x00ff0000, 0xff000000, 0x000000ff),
+
+  DEF_RGB (VA_LSB_FIRST, BGRx, XRGB8888, ('B', 'G', 'R', 'X'), 32, 24, 0x00ff0000,
+      0x0000ff00, 0x000000ff, 0x00000000),
+  DEF_RGB (VA_LSB_FIRST, BGRx, XRGB8888, ('X', 'R', 'G', 'B'), 32, 24, 0x00ff0000,
+      0x0000ff00, 0x000000ff, 0x00000000),
+  DEF_RGB (VA_MSB_FIRST, BGRx, XRGB8888, ('B', 'G', 'R', 'X'), 32, 24, 0x0000ff00,
+      0x00ff0000, 0xff000000, 0x00000000),
+
+  DEF_RGB (VA_BYTE_ORDER_NOT_CARE, RGB16, RGB565, ('R', 'G', '1', '6'), 16, 16,
+      0x0000f800, 0x000007e0, 0x0000001f, 0x00000000),
+  DEF_RGB (VA_BYTE_ORDER_NOT_CARE, RGB, RGB888, ('R', 'G', '2', '4'), 32, 24,
+      0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000),
+  DEF_RGB (VA_LSB_FIRST, BGR10A2_LE, ARGB2101010, ('A', 'R', '3', '0'), 32, 30,
+      0x3ff00000, 0x000ffc00, 0x000003ff, 0x30000000),
+  {0,}
+};
+/* *INDENT-ON* */
+
+#undef DEF_RGB
+#undef DEF_YUV
+
+static GArray *gst_vaapi_video_formats_map = NULL;
+
+static inline gboolean
+va_format_is_rgb (const VAImageFormat * va_format)
+{
+  return va_format->depth != 0;
+}
+
+static inline gboolean
+va_format_is_yuv (const VAImageFormat * va_format)
+{
+  return va_format->depth == 0;
+}
+
+static inline gboolean
+va_format_is_same_rgb (const VAImageFormat * fmt1, const VAImageFormat * fmt2)
+{
+  return (fmt1->red_mask == fmt2->red_mask &&
+      fmt1->green_mask == fmt2->green_mask &&
+      fmt1->blue_mask == fmt2->blue_mask &&
+      fmt1->alpha_mask == fmt2->alpha_mask);
+}
+
+static inline gboolean
+va_format_is_same (const VAImageFormat * fmt1, const VAImageFormat * fmt2)
+{
+  if (fmt1->fourcc != fmt2->fourcc)
+    return FALSE;
+  if (fmt1->byte_order != VA_BYTE_ORDER_NOT_CARE &&
+      fmt2->byte_order != VA_BYTE_ORDER_NOT_CARE &&
+      fmt1->byte_order != fmt2->byte_order)
+    return FALSE;
+
+  return va_format_is_rgb (fmt1) ? va_format_is_same_rgb (fmt1, fmt2) : TRUE;
+}
+
+static const GstVideoFormatMap *
+get_map_in_default_by_gst_format (GstVideoFormat format)
+{
+  const GstVideoFormatMap *m;
+  for (m = gst_vaapi_video_default_formats; m->format; m++) {
+    if (m->format == format)
+      return m;
+  }
+  return NULL;
+}
+
+static const GstVideoFormatMap *
+get_map_in_default_by_va_format (const VAImageFormat * va_format)
+{
+  const GstVideoFormatMap *m, *n;
+
+  n = NULL;
+  for (m = gst_vaapi_video_default_formats; m->format; m++) {
+    if (va_format_is_same (&m->va_format, va_format)) {
+      /* Should not map to VAImageFormat to same GstVideoFormat */
+      g_assert (n == NULL);
+      n = m;
+    }
+  }
+  return n;
+}
+
+static const GstVideoFormatMap *
+get_map_by_gst_format (const GArray * formats, GstVideoFormat format)
+{
+  const GstVideoFormatMap *entry;
+  guint i;
+
+  if (!formats)
+    return NULL;
+
+  for (i = 0; i < formats->len; i++) {
+    entry = &g_array_index (formats, GstVideoFormatMap, i);
+    if (entry->format == format)
+      return entry;
+  }
+  return NULL;
+}
+
+static const GstVideoFormatMap *
+get_map_by_va_format (const VAImageFormat * va_format)
+{
+  const GArray *formats = gst_vaapi_video_formats_map;
+  const GstVideoFormatMap *entry;
+  guint i;
+
+  if (!formats)
+    return NULL;
+
+  for (i = 0; i < formats->len; i++) {
+    entry = &g_array_index (formats, GstVideoFormatMap, i);
+    if (va_format_is_same (&entry->va_format, va_format))
+      return entry;
+  }
+  return NULL;
+}
+
+
+static guint
+get_fmt_score_in_default (GstVideoFormat format)
+{
+  const GstVideoFormatMap *const m = get_map_in_default_by_gst_format (format);
+
+  return m ? (m - &gst_vaapi_video_default_formats[0]) : G_MAXUINT;
+}
+
+static gint
+video_format_compare_by_score (gconstpointer a, gconstpointer b)
+{
+  const GstVideoFormatMap *m1 = (GstVideoFormatMap *) a;
+  const GstVideoFormatMap *m2 = (GstVideoFormatMap *) b;
+
+  return ((gint) get_fmt_score_in_default (m1->format) -
+      (gint) get_fmt_score_in_default (m2->format));
+}
+
+/**
+ * gst_vaapi_video_format_to_string:
+ * @format: a #GstVideoFormat
+ *
+ * Returns the string representation of the @format argument.
+ *
+ * Return value: string representation of @format, or %NULL if unknown
+ *   or unsupported.
+ */
+const gchar *
+gst_vaapi_video_format_to_string (GstVideoFormat format)
+{
+  return gst_video_format_to_string (format);
+}
+
+/**
+ * gst_vaapi_video_format_is_rgb:
+ * @format: a #GstVideoFormat
+ *
+ * Checks whether the format is an RGB format.
+ *
+ * Return value: %TRUE if @format is RGB format
+ */
+gboolean
+gst_vaapi_video_format_is_rgb (GstVideoFormat format)
+{
+  const GstVideoFormatMap *const m =
+      get_map_by_gst_format (gst_vaapi_video_formats_map, format);
+  return m && va_format_is_rgb (&m->va_format);
+}
+
+/**
+ * gst_vaapi_video_format_is_yuv:
+ * @format: a #GstVideoFormat
+ *
+ * Checks whether the format is an YUV format.
+ *
+ * Return value: %TRUE if @format is YUV format
+ */
+gboolean
+gst_vaapi_video_format_is_yuv (GstVideoFormat format)
+{
+  const GstVideoFormatMap *const m =
+      get_map_by_gst_format (gst_vaapi_video_formats_map, format);
+  return m && va_format_is_yuv (&m->va_format);
+}
+
+/**
+ * gst_vaapi_video_format_from_va_fourcc:
+ * @fourcc: a FOURCC value
+ *
+ * Converts a VA fourcc into the corresponding #GstVideoFormat. If no
+ * matching fourcc was found, then zero is returned.
+ *
+ * Return value: the #GstVideoFormat corresponding to the VA @fourcc
+ */
+GstVideoFormat
+gst_vaapi_video_format_from_va_fourcc (guint32 fourcc)
+{
+  const GArray *map = gst_vaapi_video_formats_map;
+  const GstVideoFormatMap *m;
+  guint i;
+
+  /* Note: VA fourcc values are now standardized and shall represent
+     a unique format. The associated VAImageFormat is just a hint to
+     determine RGBA component ordering */
+  for (i = 0; i < map->len; i++) {
+    m = &g_array_index (map, GstVideoFormatMap, i);
+    if (m->va_format.fourcc == fourcc)
+      return m->format;
+  }
+  return GST_VIDEO_FORMAT_UNKNOWN;
+}
+
+/**
+ * gst_vaapi_video_format_from_va_format:
+ * @va_format: a #VAImageFormat
+ *
+ * Converts a VA image format into the corresponding #GstVideoFormat.
+ * If the image format cannot be represented by #GstVideoFormat,
+ * then zero is returned.
+ *
+ * Return value: the #GstVideoFormat describing the @va_format
+ */
+GstVideoFormat
+gst_vaapi_video_format_from_va_format (const VAImageFormat * va_format)
+{
+  const GstVideoFormatMap *const m = get_map_by_va_format (va_format);
+  return m ? m->format : GST_VIDEO_FORMAT_UNKNOWN;
+}
+
+/**
+ * gst_vaapi_video_format_to_va_format:
+ * @format: a #GstVideoFormat
+ *
+ * Converts a #GstVideoFormat into the corresponding VA image
+ * format. If no matching VA image format was found, %NULL is returned
+ * and this error must be reported to be fixed.
+ *
+ * Return value: the VA image format, or %NULL if none was found
+ */
+const VAImageFormat *
+gst_vaapi_video_format_to_va_format (GstVideoFormat format)
+{
+  const GstVideoFormatMap *const m =
+      get_map_by_gst_format (gst_vaapi_video_formats_map, format);
+  return m ? &m->va_format : NULL;
+}
+
+/**
+ * gst_vaapi_video_format_get_chroma_type:
+ * @format: a #GstVideoFormat
+ *
+ * Converts a #GstVideoFormat into the corresponding #GstVaapiChromaType
+ * format.
+ *
+ * Return value: the #GstVaapiChromaType format, or zero if no match
+ *   was found.
+ */
+guint
+gst_vaapi_video_format_get_chroma_type (GstVideoFormat format)
+{
+  const GstVideoFormatMap *const m =
+      get_map_by_gst_format (gst_vaapi_video_formats_map, format);
+  return m ? m->chroma_type : 0;
+}
+
+/**
+ * gst_vaapi_video_format_get_score:
+ * @format: a #GstVideoFormat
+ *
+ * Determines how "native" is this @format. The lower is the returned
+ * score, the best format this is for the underlying hardware.
+ *
+ * Return value: the @format score, or %G_MAXUINT if none was found
+ */
+guint
+gst_vaapi_video_format_get_score (GstVideoFormat format)
+{
+  return get_fmt_score_in_default (format);
+}
+
+/**
+ * gst_vaapi_video_format_from_chroma:
+ * @chroma_type: a #GstVaapiChromaType
+ *
+ * Returns the "preferred" pixel format that matches with
+ * @chroma_type.
+ *
+ * Returns: the preferred pixel format for @chroma_type
+ **/
+GstVideoFormat
+gst_vaapi_video_format_from_chroma (guint chroma_type)
+{
+  switch (chroma_type) {
+    case GST_VAAPI_CHROMA_TYPE_YUV422:
+      return GST_VIDEO_FORMAT_YUY2;
+    case GST_VAAPI_CHROMA_TYPE_YUV400:
+      return GST_VIDEO_FORMAT_GRAY8;
+    case GST_VAAPI_CHROMA_TYPE_YUV420:
+    case GST_VAAPI_CHROMA_TYPE_RGB32:  /* GstVideoGLTextureUploadMeta */
+      return GST_VIDEO_FORMAT_NV12;
+    case GST_VAAPI_CHROMA_TYPE_YUV420_10BPP:
+      return GST_VIDEO_FORMAT_P010_10LE;
+    case GST_VAAPI_CHROMA_TYPE_YUV420_12BPP:
+      return GST_VIDEO_FORMAT_P012_LE;
+    case GST_VAAPI_CHROMA_TYPE_YUV444:
+      return GST_VIDEO_FORMAT_VUYA;
+    case GST_VAAPI_CHROMA_TYPE_YUV422_10BPP:
+      return GST_VIDEO_FORMAT_Y210;
+    case GST_VAAPI_CHROMA_TYPE_YUV444_10BPP:
+      return GST_VIDEO_FORMAT_Y410;
+    case GST_VAAPI_CHROMA_TYPE_YUV444_12BPP:
+      return GST_VIDEO_FORMAT_Y412_LE;
+    case GST_VAAPI_CHROMA_TYPE_YUV422_12BPP:
+      return GST_VIDEO_FORMAT_Y212_LE;
+    default:
+      return GST_VIDEO_FORMAT_UNKNOWN;
+  }
+}
+
+/**
+ * gst_vaapi_video_format_get_best_native:
+ * @format: a #GstVideoFormat
+ *
+ * Returns the best "native" pixel format that matches a particular
+ * color-space.
+ *
+ * Returns: the #GstVideoFormat with the corresponding best native
+ * format for #GstVaapiSurface
+ **/
+GstVideoFormat
+gst_vaapi_video_format_get_best_native (GstVideoFormat format)
+{
+  GstVaapiChromaType chroma_type;
+
+  if (format == GST_VIDEO_FORMAT_ENCODED)
+    return GST_VIDEO_FORMAT_NV12;
+  chroma_type = gst_vaapi_video_format_get_chroma_type (format);
+  return gst_vaapi_video_format_from_chroma (chroma_type);
+}
+
+/**
+ * gst_vaapi_video_format_get_formats_by_chroma:
+ * @chroma: a #GstVaapiChromaType
+ *
+ * Get all #GstVideoFormat which belong to #GstVaapiChromaType.
+ *
+ * Returns: an array of #GstVideoFormat.
+ **/
+GArray *
+gst_vaapi_video_format_get_formats_by_chroma (guint chroma)
+{
+  const GstVideoFormatMap *entry;
+  GArray *formats;
+  guint i;
+
+  formats = g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
+  if (!formats)
+    return NULL;
+
+  for (i = 0; i < gst_vaapi_video_formats_map->len; i++) {
+    entry = &g_array_index (gst_vaapi_video_formats_map, GstVideoFormatMap, i);
+    if (entry->chroma_type == chroma)
+      g_array_append_val (formats, entry->format);
+  }
+
+  if (formats->len == 0) {
+    g_array_unref (formats);
+    return NULL;
+  }
+
+  return formats;
+}
+
+struct ImageFormatsData
+{
+  VAImageFormat *formats;
+  guint n;
+};
+
+static gpointer
+video_format_create_map_once (gpointer data)
+{
+  const GstVideoFormatMap *src_entry, *entry;
+  guint i;
+  VAImageFormat *formats = ((struct ImageFormatsData *) data)->formats;
+  guint n = ((struct ImageFormatsData *) data)->n;
+  GArray *array = NULL;
+
+  array = g_array_new (FALSE, TRUE, sizeof (GstVideoFormatMap));
+  if (array == NULL)
+    return NULL;
+
+  /* All the YUV format has no ambiguity */
+  for (i = 0; i < G_N_ELEMENTS (gst_vaapi_video_default_formats); i++) {
+    if (va_format_is_yuv (&gst_vaapi_video_default_formats[i].va_format))
+      g_array_append_val (array, gst_vaapi_video_default_formats[i]);
+  }
+
+  if (formats) {
+    for (i = 0; i < n; i++) {
+      if (!va_format_is_rgb (&formats[i]))
+        continue;
+
+      src_entry = get_map_in_default_by_va_format (&formats[i]);
+      if (src_entry) {
+        entry = get_map_by_gst_format (array, src_entry->format);
+        if (entry && !va_format_is_same (&entry->va_format, &formats[i])) {
+          GST_INFO ("va_format1 with fourcc %" GST_FOURCC_FORMAT
+              " byte order: %d, BPP: %d, depth %d, red mask 0x%4x,"
+              " green mask 0x%4x, blue mask 0x%4x, alpha mask 0x%4x"
+              " conflict with va_foramt2 fourcc %" GST_FOURCC_FORMAT
+              " byte order: %d, BPP: %d, depth %d, red mask 0x%4x,"
+              " green mask 0x%4x, blue mask 0x%4x, alpha mask 0x%4x."
+              " Both map to the same GST format: %s, which is not"
+              " allowed, va_format1 will be skipped",
+              GST_FOURCC_ARGS (entry->va_format.fourcc),
+              entry->va_format.byte_order, entry->va_format.bits_per_pixel,
+              entry->va_format.depth, entry->va_format.red_mask,
+              entry->va_format.green_mask, entry->va_format.blue_mask,
+              entry->va_format.alpha_mask,
+              GST_FOURCC_ARGS (formats[i].fourcc),
+              formats[i].byte_order, formats[i].bits_per_pixel,
+              formats[i].depth, formats[i].red_mask, formats[i].green_mask,
+              formats[i].blue_mask, formats[i].alpha_mask,
+              gst_video_format_to_string (entry->format));
+          continue;
+        }
+        g_array_append_val (array, (*src_entry));
+      }
+
+      GST_LOG ("%s to map RGB va_format with fourcc: %"
+          GST_FOURCC_FORMAT
+          ", byte order: %d BPP: %d, depth %d, red mask %4x,"
+          " green mask %4x, blue mask %4x, alpha mask %4x to %s gstreamer"
+          " video format", src_entry ? "succeed" : "failed",
+          GST_FOURCC_ARGS (formats[i].fourcc), formats[i].byte_order,
+          formats[i].bits_per_pixel, formats[i].depth, formats[i].red_mask,
+          formats[i].green_mask, formats[i].blue_mask, formats[i].alpha_mask,
+          src_entry ? gst_video_format_to_string (src_entry->format) : "any");
+    }
+  }
+
+  g_array_sort (array, video_format_compare_by_score);
+  gst_vaapi_video_formats_map = array;
+  return array;
+}
+
+/**
+ * gst_vaapi_video_format_new_map:
+ * @formats: all #VAImageFormat need to map
+ * @n: the number of VAImageFormat
+ *
+ * Return: True if create successfully.
+ **/
+gboolean
+gst_vaapi_video_format_create_map (VAImageFormat * formats, guint n)
+{
+  static GOnce once = G_ONCE_INIT;
+  struct ImageFormatsData data = { formats, n };
+
+  g_once (&once, video_format_create_map_once, &data);
+
+  return once.retval != NULL;
+}
+
+/**
+ * gst_vaapi_drm_format_from_va_fourcc:
+ * @fourcc: a FOURCC value
+ *
+ * Converts a VA fourcc into the corresponding DRM_FORMAT_*. If no
+ * matching fourcc was found, then DRM_FORMAT_INVALID is returned.
+ *
+ * Return value: the DRM_FORMAT_* corresponding to the VA @fourcc
+ *
+ * Since: 1.18
+ */
+guint
+gst_vaapi_drm_format_from_va_fourcc (guint32 fourcc)
+{
+#if GST_VAAPI_USE_DRM
+  const GArray *map = gst_vaapi_video_formats_map;
+  const GstVideoFormatMap *m;
+  guint i;
+
+  if (!map)
+    return GST_VIDEO_FORMAT_UNKNOWN;
+
+  /* Note: VA fourcc values are now standardized and shall represent
+     a unique format. The associated VAImageFormat is just a hint to
+     determine RGBA component ordering */
+  for (i = 0; i < map->len; i++) {
+    m = &g_array_index (map, GstVideoFormatMap, i);
+    if (m->va_format.fourcc == fourcc)
+      return m->drm_format;
+  }
+  return DRM_FORMAT_INVALID;
+#else
+  return 0;
+#endif
+}
+
+/**
+ * gst_vaapi_video_format_from_drm_format:
+ * @drm_format: a DRM format value
+ *
+ * Converts a DRM_FORMAT_* to the corresponding GstVideoFormat. If no
+ * matching fourcc was found, then DRM_FORMAT_INVALID is returned.
+ *
+ * Return value: GstVideoFormat corresponding to the @drm_format
+ *
+ * Since: 1.18
+ */
+GstVideoFormat
+gst_vaapi_video_format_from_drm_format (guint drm_format)
+{
+#if GST_VAAPI_USE_DRM
+  const GArray *map = gst_vaapi_video_formats_map;
+  const GstVideoFormatMap *m;
+  guint i;
+
+  if (!map)
+    return GST_VIDEO_FORMAT_UNKNOWN;
+
+  for (i = 0; i < map->len; i++) {
+    m = &g_array_index (map, GstVideoFormatMap, i);
+    if (m->drm_format == drm_format)
+      return m->format;
+  }
+#endif
+  return GST_VIDEO_FORMAT_UNKNOWN;
+}
diff --git a/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/video-format.h b/subprojects/gstreamer-vaapi/gst-libs/gst/vaapi/video-format.h
new file mode 100644 (file)
index 0000000..22e14fb
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ *  video-format.h - Video format helpers for VA-API
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VIDEO_FORMAT_H
+#define GST_VAAPI_VIDEO_FORMAT_H
+
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_FORMATS_ALL "{ ENCODED, " \
+  "NV12, YV12, I420, YUY2, UYVY, Y444, GRAY8, P010_10LE, P012_LE, VUYA, Y210, Y410, Y212_LE, Y412_LE, " \
+  "ARGB, xRGB, RGBA, RGBx, ABGR, xBGR, BGRA, BGRx, RGB16, RGB, BGR10A2_LE "  \
+  "}"
+
+const gchar *
+gst_vaapi_video_format_to_string (GstVideoFormat format);
+
+gboolean
+gst_vaapi_video_format_is_rgb (GstVideoFormat format);
+
+gboolean
+gst_vaapi_video_format_is_yuv (GstVideoFormat format);
+
+GstVideoFormat
+gst_vaapi_video_format_from_va_fourcc (guint32 fourcc);
+
+GstVideoFormat
+gst_vaapi_video_format_from_va_format (const VAImageFormat * va_format);
+
+const VAImageFormat *
+gst_vaapi_video_format_to_va_format (GstVideoFormat format);
+
+guint
+gst_vaapi_video_format_get_chroma_type (GstVideoFormat format);
+
+guint
+gst_vaapi_video_format_get_score (GstVideoFormat format);
+
+GstVideoFormat
+gst_vaapi_video_format_from_chroma (guint chroma);
+
+GstVideoFormat
+gst_vaapi_video_format_get_best_native (GstVideoFormat format);
+
+GArray *
+gst_vaapi_video_format_get_formats_by_chroma (guint chroma);
+
+gboolean
+gst_vaapi_video_format_create_map (VAImageFormat * formats, guint n);
+
+guint
+gst_vaapi_drm_format_from_va_fourcc (guint32 fourcc);
+
+GstVideoFormat
+gst_vaapi_video_format_from_drm_format (guint drm_format);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_VIDEO_FORMAT_H */
diff --git a/subprojects/gstreamer-vaapi/gst-libs/meson.build b/subprojects/gstreamer-vaapi/gst-libs/meson.build
new file mode 100644 (file)
index 0000000..668dcba
--- /dev/null
@@ -0,0 +1 @@
+subdir('gst')
diff --git a/subprojects/gstreamer-vaapi/gst/meson.build b/subprojects/gstreamer-vaapi/gst/meson.build
new file mode 100644 (file)
index 0000000..a8719a1
--- /dev/null
@@ -0,0 +1 @@
+subdir('vaapi')
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstcompat.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstcompat.h
new file mode 100644 (file)
index 0000000..c953783
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *  gstcompat.h - Compatibility glue for GStreamer
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_COMPAT_H
+#define GST_COMPAT_H
+
+#include "gst/vaapi/sysdeps.h"
+
+#endif /* GST_COMPAT_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapi.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapi.c
new file mode 100644 (file)
index 0000000..3fc761e
--- /dev/null
@@ -0,0 +1,245 @@
+/*
+ *  gstvaapi.c - VA-API element registration
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *  Copyright (C) 2011 Collabora Ltd.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstcompat.h"
+#include "gstvaapidecode.h"
+#include "gstvaapioverlay.h"
+#include "gstvaapipostproc.h"
+#include "gstvaapisink.h"
+#include "gstvaapidecodebin.h"
+
+#if GST_VAAPI_USE_ENCODERS
+#include "gstvaapiencode_h264.h"
+#include "gstvaapiencode_mpeg2.h"
+#include "gstvaapiencode_jpeg.h"
+#include "gstvaapiencode_vp8.h"
+#include "gstvaapiencode_h265.h"
+
+#if GST_VAAPI_USE_VP9_ENCODER
+#include "gstvaapiencode_vp9.h"
+#endif
+#endif
+
+gboolean _gst_vaapi_has_video_processing = FALSE;
+
+#define PLUGIN_NAME     "vaapi"
+#define PLUGIN_DESC     "VA-API based elements"
+#define PLUGIN_LICENSE  "LGPL"
+
+static void
+plugin_add_dependencies (GstPlugin * plugin)
+{
+  const gchar *envvars[] = { "GST_VAAPI_ALL_DRIVERS", "LIBVA_DRIVER_NAME",
+    "DISPLAY", "WAYLAND_DISPLAY", NULL
+  };
+  const gchar *kernel_paths[] = { "/dev/dri", NULL };
+  const gchar *kernel_names[] = { "card", "render", NULL };
+
+  /* features get updated upon changes in /dev/dri/card* */
+  gst_plugin_add_dependency (plugin, NULL, kernel_paths, kernel_names,
+      GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX);
+
+  /* features get updated upon changes in VA environment variables */
+  gst_plugin_add_dependency (plugin, envvars, NULL, NULL,
+      GST_PLUGIN_DEPENDENCY_FLAG_NONE);
+
+  /* features get updated upon changes in default VA drivers
+   * directory */
+  gst_plugin_add_dependency_simple (plugin, "LIBVA_DRIVERS_PATH",
+      VA_DRIVERS_PATH, "_drv_video.so",
+      GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX |
+      GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY);
+}
+
+static GArray *
+profiles_get_codecs (GArray * profiles)
+{
+  guint i;
+  GArray *codecs;
+  GstVaapiProfile profile;
+  GstVaapiCodec codec;
+
+  codecs = g_array_new (FALSE, FALSE, sizeof (GstVaapiCodec));
+  if (!codecs)
+    return NULL;
+
+  for (i = 0; i < profiles->len; i++) {
+    profile = g_array_index (profiles, GstVaapiProfile, i);
+    codec = gst_vaapi_profile_get_codec (profile);
+    if (gst_vaapi_codecs_has_codec (codecs, codec))
+      continue;
+    g_array_append_val (codecs, codec);
+  }
+
+  return codecs;
+}
+
+static GArray *
+display_get_decoder_codecs (GstVaapiDisplay * display)
+{
+  GArray *profiles, *codecs;
+
+  profiles = gst_vaapi_display_get_decode_profiles (display);
+  if (!profiles)
+    return NULL;
+
+  codecs = profiles_get_codecs (profiles);
+  g_array_unref (profiles);
+  return codecs;
+}
+
+#if GST_VAAPI_USE_ENCODERS
+static GArray *
+display_get_encoder_codecs (GstVaapiDisplay * display)
+{
+  GArray *profiles, *codecs;
+
+  profiles = gst_vaapi_display_get_encode_profiles (display);
+  if (!profiles)
+    return NULL;
+
+  codecs = profiles_get_codecs (profiles);
+  g_array_unref (profiles);
+  return codecs;
+}
+
+typedef struct _GstVaapiEncoderMap GstVaapiEncoderMap;
+struct _GstVaapiEncoderMap
+{
+  GstVaapiCodec codec;
+  guint rank;
+  const gchar *name;
+    GType (*register_type) (GstVaapiDisplay * display);
+};
+
+#define DEF_ENC(CODEC,codec)          \
+  {GST_VAAPI_CODEC_##CODEC,           \
+   GST_RANK_PRIMARY,                  \
+   "vaapi" G_STRINGIFY (codec) "enc", \
+   gst_vaapiencode_##codec##_register_type}
+
+static const GstVaapiEncoderMap vaapi_encode_map[] = {
+  DEF_ENC (H264, h264),
+  DEF_ENC (MPEG2, mpeg2),
+  DEF_ENC (JPEG, jpeg),
+  DEF_ENC (VP8, vp8),
+#if GST_VAAPI_USE_VP9_ENCODER
+  DEF_ENC (VP9, vp9),
+#endif
+  DEF_ENC (H265, h265),
+};
+
+#undef DEF_ENC
+
+static void
+gst_vaapiencode_register (GstPlugin * plugin, GstVaapiDisplay * display)
+{
+  guint i, j;
+  GArray *codecs;
+  GstVaapiCodec codec;
+
+  codecs = display_get_encoder_codecs (display);
+  if (!codecs)
+    return;
+
+  for (i = 0; i < codecs->len; i++) {
+    codec = g_array_index (codecs, GstVaapiCodec, i);
+    for (j = 0; j < G_N_ELEMENTS (vaapi_encode_map); j++) {
+      if (vaapi_encode_map[j].codec == codec) {
+        gst_element_register (plugin, vaapi_encode_map[j].name,
+            vaapi_encode_map[j].rank,
+            vaapi_encode_map[j].register_type (display));
+        break;
+      }
+    }
+  }
+
+  g_array_unref (codecs);
+}
+#endif
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GstVaapiDisplay *display;
+  GArray *decoders;
+  guint rank;
+
+  plugin_add_dependencies (plugin);
+
+  display = gst_vaapi_create_test_display ();
+  if (!display)
+    goto error_no_display;
+  if (!gst_vaapi_driver_is_whitelisted (display))
+    goto unsupported_driver;
+
+  _gst_vaapi_has_video_processing =
+      gst_vaapi_display_has_video_processing (display);
+
+  decoders = display_get_decoder_codecs (display);
+  if (decoders) {
+    gst_vaapidecode_register (plugin, decoders);
+    gst_element_register (plugin, "vaapidecodebin",
+        GST_RANK_PRIMARY + 2, GST_TYPE_VAAPI_DECODE_BIN);
+    g_array_unref (decoders);
+  }
+
+  if (_gst_vaapi_has_video_processing) {
+    gst_vaapioverlay_register (plugin, display);
+
+    gst_element_register (plugin, "vaapipostproc",
+        GST_RANK_NONE, GST_TYPE_VAAPIPOSTPROC);
+  }
+
+  rank = GST_RANK_SECONDARY;
+  if (g_getenv ("WAYLAND_DISPLAY"))
+    rank = GST_RANK_MARGINAL;
+  gst_element_register (plugin, "vaapisink", rank, GST_TYPE_VAAPISINK);
+
+#if GST_VAAPI_USE_ENCODERS
+  gst_vaapiencode_register (plugin, display);
+#endif
+
+  gst_object_unref (display);
+
+  return TRUE;
+
+  /* ERRORS: */
+error_no_display:
+  {
+    GST_WARNING ("Cannot create a VA display");
+    /* Avoid blacklisting: failure to create a display could be a
+     * transient condition */
+    return TRUE;
+  }
+unsupported_driver:
+  {
+    gst_object_unref (display);
+    return TRUE;                /* return TRUE to avoid get blacklisted */
+  }
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR,
+    vaapi, PLUGIN_DESC, plugin_init,
+    PACKAGE_VERSION, PLUGIN_LICENSE, PACKAGE, PACKAGE_BUGREPORT)
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapi.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapi.h
new file mode 100644 (file)
index 0000000..f585950
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *  gstvaapi.h - VA-API element registration
+ *
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *  Copyright (C) 2011 Collabora Ltd.
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef __GST_VAAPI_H__
+#define __GST_VAAPI_H__
+
+G_GNUC_INTERNAL extern gboolean _gst_vaapi_has_video_processing;
+
+#endif /* __GST_VAAPI_H__ */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode.c
new file mode 100644 (file)
index 0000000..1eb6208
--- /dev/null
@@ -0,0 +1,1642 @@
+/*
+ *  gstvaapidecode.c - VA-API video decoder
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiprofilecaps.h>
+
+#include "gstvaapidecode.h"
+#include "gstvaapidecode_props.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideobuffer.h"
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+#include "gstvaapivideometa_texture.h"
+#endif
+#include "gstvaapivideobufferpool.h"
+#include "gstvaapivideomemory.h"
+
+#include <gst/vaapi/gstvaapidecoder_h264.h>
+#include <gst/vaapi/gstvaapidecoder_jpeg.h>
+#include <gst/vaapi/gstvaapidecoder_mpeg2.h>
+#include <gst/vaapi/gstvaapidecoder_mpeg4.h>
+#include <gst/vaapi/gstvaapidecoder_vc1.h>
+#include <gst/vaapi/gstvaapidecoder_vp8.h>
+#include <gst/vaapi/gstvaapidecoder_h265.h>
+#include <gst/vaapi/gstvaapidecoder_vp9.h>
+#if GST_VAAPI_USE_AV1_DECODER
+#include <gst/vaapi/gstvaapidecoder_av1.h>
+#endif
+
+#define GST_PLUGIN_NAME "vaapidecode"
+#define GST_PLUGIN_DESC "A VA-API based video decoder"
+
+#define GST_VAAPI_DECODE_FLOW_PARSE_DATA        GST_FLOW_CUSTOM_SUCCESS_2
+
+GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapidecode);
+#ifndef GST_DISABLE_GST_DEBUG
+#define GST_CAT_DEFAULT gst_debug_vaapidecode
+#else
+#define GST_CAT_DEFAULT NULL
+#endif
+
+#define GST_VAAPI_DECODE_PARAMS_QDATA \
+  g_quark_from_static_string("vaapidec-params")
+
+/* Default templates */
+#define GST_CAPS_CODEC(CODEC) CODEC "; "
+
+/* *INDENT-OFF* */
+char *gst_vaapidecode_sink_caps_str = NULL;
+
+static const char gst_vaapidecode_src_caps_str[] =
+    GST_VAAPI_MAKE_SURFACE_CAPS "; "
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+    GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS "; "
+#endif
+    GST_VIDEO_CAPS_MAKE(GST_VAAPI_FORMATS_ALL);
+
+static GstStaticPadTemplate gst_vaapidecode_src_factory =
+    GST_STATIC_PAD_TEMPLATE(
+        "src",
+        GST_PAD_SRC,
+        GST_PAD_ALWAYS,
+        GST_STATIC_CAPS(gst_vaapidecode_src_caps_str));
+/* *INDENT-ON* */
+
+typedef struct _GstVaapiDecoderMap GstVaapiDecoderMap;
+struct _GstVaapiDecoderMap
+{
+  guint codec;
+  guint rank;
+  const gchar *name;
+  const gchar *caps_str;
+
+  void (*install_properties) (GObjectClass * klass);
+};
+
+static const GstVaapiDecoderMap vaapi_decode_map[] = {
+  {GST_VAAPI_CODEC_JPEG, GST_RANK_MARGINAL, "jpeg", "image/jpeg", NULL},
+  {GST_VAAPI_CODEC_MPEG2, GST_RANK_PRIMARY, "mpeg2",
+      "video/mpeg, mpegversion=2, systemstream=(boolean)false", NULL},
+  {GST_VAAPI_CODEC_MPEG4, GST_RANK_PRIMARY, "mpeg4",
+      "video/mpeg, mpegversion=4", NULL},
+  {GST_VAAPI_CODEC_H263, GST_RANK_PRIMARY, "h263", "video/x-h263", NULL},
+  {GST_VAAPI_CODEC_H264, GST_RANK_PRIMARY, "h264", "video/x-h264",
+      gst_vaapi_decode_h264_install_properties},
+  {GST_VAAPI_CODEC_VC1, GST_RANK_PRIMARY, "vc1",
+      "video/x-wmv, wmvversion=3, format={WMV3,WVC1}", NULL},
+  {GST_VAAPI_CODEC_VP8, GST_RANK_PRIMARY, "vp8", "video/x-vp8", NULL},
+  {GST_VAAPI_CODEC_VP9, GST_RANK_PRIMARY, "vp9", "video/x-vp9", NULL},
+  {GST_VAAPI_CODEC_H265, GST_RANK_PRIMARY, "h265", "video/x-h265", NULL},
+  {GST_VAAPI_CODEC_AV1, GST_RANK_PRIMARY, "av1", "video/x-av1", NULL},
+  {0 /* the rest */ , GST_RANK_PRIMARY + 1, NULL, NULL, NULL},
+};
+
+static GstElementClass *parent_class = NULL;
+GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (parent_class);
+
+static gboolean gst_vaapidecode_update_sink_caps (GstVaapiDecode * decode,
+    GstCaps * caps);
+static gboolean gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode,
+    const GstVideoCodecState * new_state);
+
+/* invoked if actual VASurface size (not the cropped values)
+ * changed */
+static void
+gst_vaapi_decoder_state_changed (GstVaapiDecoder * decoder,
+    const GstVideoCodecState * codec_state, gpointer user_data)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (user_data);
+
+  g_assert (decode->decoder == decoder);
+
+  if (!gst_vaapi_decode_input_state_replace (decode, codec_state))
+    return;
+  if (!gst_vaapidecode_update_sink_caps (decode, decode->input_state->caps))
+    return;
+}
+
+static GstVideoCodecState *
+copy_video_codec_state (const GstVideoCodecState * in_state)
+{
+  GstVideoCodecState *state;
+
+  g_return_val_if_fail (in_state != NULL, NULL);
+
+  state = g_slice_new0 (GstVideoCodecState);
+  state->ref_count = 1;
+  state->info = in_state->info;
+  state->caps = gst_caps_copy (in_state->caps);
+  if (in_state->codec_data)
+    state->codec_data = gst_buffer_copy_deep (in_state->codec_data);
+
+  return state;
+}
+
+static gboolean
+gst_vaapi_decode_input_state_replace (GstVaapiDecode * decode,
+    const GstVideoCodecState * new_state)
+{
+  if (decode->input_state) {
+    if (new_state) {
+      const GstCaps *curcaps = decode->input_state->caps;
+      /* If existing caps are equal of the new state, keep the
+       * existing state without renegotiating. */
+      if (gst_caps_is_strictly_equal (curcaps, new_state->caps)) {
+        GST_DEBUG ("Ignoring new caps %" GST_PTR_FORMAT
+            " since are equal to current ones", new_state->caps);
+        return FALSE;
+      }
+    }
+    gst_video_codec_state_unref (decode->input_state);
+  }
+
+  if (new_state)
+    decode->input_state = copy_video_codec_state (new_state);
+  else
+    decode->input_state = NULL;
+
+  return TRUE;
+}
+
+static inline gboolean
+gst_vaapidecode_update_sink_caps (GstVaapiDecode * decode, GstCaps * caps)
+{
+  GST_INFO_OBJECT (decode, "new sink caps = %" GST_PTR_FORMAT, caps);
+  gst_caps_replace (&decode->sinkpad_caps, caps);
+  return TRUE;
+}
+
+static gboolean
+gst_vaapidecode_ensure_allowed_srcpad_caps (GstVaapiDecode * decode)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
+  GstCaps *out_caps, *raw_caps, *va_caps, *dma_caps, *gltexup_caps, *base_caps;
+  GArray *formats;
+  gint min_width, min_height, max_width, max_height;
+  guint mem_types;
+  gboolean ret = FALSE;
+
+  if (decode->allowed_srcpad_caps)
+    return TRUE;
+
+  if (!display)
+    return FALSE;
+
+  if (!decode->decoder)
+    return FALSE;
+
+  dma_caps = gltexup_caps = NULL;
+
+  formats = gst_vaapi_decoder_get_surface_attributes (decode->decoder,
+      &min_width, &min_height, &max_width, &max_height, &mem_types);
+  if (!formats)
+    return FALSE;
+
+  base_caps = gst_vaapi_video_format_new_template_caps_from_list (formats);
+  if (!base_caps)
+    goto bail;
+  gst_vaapi_caps_set_width_and_height_range (base_caps, min_width, min_height,
+      max_width, max_height);
+
+  {
+    GArray *img_formats = gst_vaapi_display_get_image_formats (display);
+    GstVideoFormat decoded_format =
+        GST_VIDEO_INFO_FORMAT (&decode->decoded_info);
+
+    if (!img_formats)
+      img_formats = g_array_ref (formats);
+
+    if (decoded_format != GST_VIDEO_FORMAT_UNKNOWN) {
+      guint decoded_chroma =
+          gst_vaapi_video_format_get_chroma_type (decoded_format);
+      GArray *new_img_formats =
+          g_array_new (FALSE, FALSE, sizeof (GstVideoFormat));
+      gint i;
+
+      for (i = 0; i < img_formats->len; i++) {
+        const GstVideoFormat fmt =
+            g_array_index (img_formats, GstVideoFormat, i);
+        if (gst_vaapi_video_format_get_chroma_type (fmt) == decoded_chroma)
+          g_array_append_val (new_img_formats, fmt);
+      }
+
+      if (new_img_formats->len == 0) {
+        g_clear_pointer (&new_img_formats, g_array_unref);
+      } else {
+        g_clear_pointer (&img_formats, g_array_unref);
+        img_formats = new_img_formats;
+      }
+    }
+
+    raw_caps = gst_vaapi_video_format_new_template_caps_from_list (img_formats);
+    gst_vaapi_caps_set_width_and_height_range (raw_caps, min_width, min_height,
+        max_width, max_height);
+    g_array_unref (img_formats);
+  }
+
+  va_caps = gst_caps_copy (base_caps);
+  gst_caps_set_features_simple (va_caps,
+      gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE));
+
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+  if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (decode)
+      && gst_vaapi_display_has_opengl (GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))) {
+    gltexup_caps = gst_caps_from_string (GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS);
+    if (gltexup_caps) {
+      gst_vaapi_caps_set_width_and_height_range (base_caps, min_width,
+          min_height, max_width, max_height);
+    }
+  }
+#endif
+
+  out_caps = va_caps;
+  if (dma_caps)
+    gst_caps_append (out_caps, dma_caps);
+  if (gltexup_caps)
+    gst_caps_append (out_caps, gltexup_caps);
+  gst_caps_append (out_caps, raw_caps);
+  decode->allowed_srcpad_caps = out_caps;
+
+  GST_INFO_OBJECT (decode, "allowed srcpad caps: %" GST_PTR_FORMAT,
+      decode->allowed_srcpad_caps);
+
+  ret = TRUE;
+
+bail:
+  if (formats)
+    g_array_unref (formats);
+  if (base_caps)
+    gst_caps_unref (base_caps);
+  return ret;
+}
+
+static GstCaps *
+gst_vaapidecode_get_allowed_srcpad_caps (GstVaapiDecode * decode)
+{
+  GstPad *const srcpad = GST_VIDEO_DECODER_SRC_PAD (decode);
+
+  if (gst_vaapidecode_ensure_allowed_srcpad_caps (decode))
+    return gst_caps_ref (decode->allowed_srcpad_caps);
+  return gst_pad_get_pad_template_caps (srcpad);
+}
+
+static gboolean
+gst_vaapidecode_update_src_caps (GstVaapiDecode * decode)
+{
+  GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
+  GstPad *const srcpad = GST_VIDEO_DECODER_SRC_PAD (vdec);
+  GstCaps *allowed;
+  GstVideoCodecState *state, *ref_state;
+  GstVaapiCapsFeature feature;
+  GstCapsFeatures *features;
+  GstCaps *allocation_caps;
+  GstVideoInfo *vi;
+  GstVideoFormat format;
+  GstClockTime latency;
+  gint fps_d, fps_n;
+  guint width, height;
+  const gchar *format_str, *feature_str;
+
+  if (!decode->input_state)
+    return FALSE;
+
+  ref_state = decode->input_state;
+
+  format = GST_VIDEO_INFO_FORMAT (&decode->decoded_info);
+  allowed = gst_vaapidecode_get_allowed_srcpad_caps (decode);
+  feature = gst_vaapi_find_preferred_caps_feature (srcpad, allowed, &format);
+  gst_caps_unref (allowed);
+
+  if (feature == GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED)
+    return FALSE;
+
+#if (!GST_VAAPI_USE_GLX && !GST_VAAPI_USE_EGL)
+  /* This is a very pathological situation. Should not happen. */
+  if (feature == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META)
+    return FALSE;
+#endif
+
+  if ((feature == GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY ||
+          feature == GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE)
+      && format != GST_VIDEO_INFO_FORMAT (&decode->decoded_info)) {
+    GST_FIXME_OBJECT (decode, "validate if driver can convert from %s to %s",
+        gst_video_format_to_string (GST_VIDEO_INFO_FORMAT
+            (&decode->decoded_info)), gst_video_format_to_string (format));
+  }
+
+  width = decode->display_width;
+  height = decode->display_height;
+
+  if (!width || !height) {
+    width = GST_VIDEO_INFO_WIDTH (&ref_state->info);
+    height = GST_VIDEO_INFO_HEIGHT (&ref_state->info);
+  }
+
+  state = gst_video_decoder_set_output_state (vdec, format, width, height,
+      ref_state);
+  if (!state)
+    return FALSE;
+
+  if (GST_VIDEO_INFO_WIDTH (&state->info) == 0
+      || GST_VIDEO_INFO_HEIGHT (&state->info) == 0) {
+    gst_video_codec_state_unref (state);
+    return FALSE;
+  }
+
+  vi = &state->info;
+  state->caps = gst_video_info_to_caps (vi);
+
+  switch (feature) {
+    case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
+    case GST_VAAPI_CAPS_FEATURE_DMABUF:
+    case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE:{
+      GstStructure *structure = gst_caps_get_structure (state->caps, 0);
+      if (!structure)
+        break;
+      feature_str = gst_vaapi_caps_feature_to_string (feature);
+      features = gst_caps_features_new (feature_str, NULL);
+      gst_caps_set_features (state->caps, 0, features);
+      break;
+    }
+    default:
+      break;
+  }
+
+  /* Allocation query is different from pad's caps */
+  allocation_caps = NULL;
+  if (GST_VIDEO_INFO_WIDTH (&decode->decoded_info) != width
+      || GST_VIDEO_INFO_HEIGHT (&decode->decoded_info) != height) {
+    allocation_caps = gst_caps_copy (state->caps);
+    format_str = gst_video_format_to_string (format);
+    gst_caps_set_simple (allocation_caps,
+        "width", G_TYPE_INT, GST_VIDEO_INFO_WIDTH (&decode->decoded_info),
+        "height", G_TYPE_INT, GST_VIDEO_INFO_HEIGHT (&decode->decoded_info),
+        "format", G_TYPE_STRING, format_str, NULL);
+    GST_INFO_OBJECT (decode, "new alloc caps = %" GST_PTR_FORMAT,
+        allocation_caps);
+  }
+  gst_caps_replace (&state->allocation_caps, allocation_caps);
+  if (allocation_caps)
+    gst_caps_unref (allocation_caps);
+
+  GST_INFO_OBJECT (decode, "new src caps = %" GST_PTR_FORMAT, state->caps);
+  gst_caps_replace (&decode->srcpad_caps, state->caps);
+  gst_video_codec_state_unref (state);
+
+  fps_n = GST_VIDEO_INFO_FPS_N (vi);
+  fps_d = GST_VIDEO_INFO_FPS_D (vi);
+  if (fps_n <= 0 || fps_d <= 0) {
+    GST_DEBUG_OBJECT (decode, "forcing 25/1 framerate for latency calculation");
+    fps_n = 25;
+    fps_d = 1;
+  }
+
+  /* For parsing/preparation purposes we'd need at least 1 frame
+   * latency in general, with perfectly known unit boundaries (NALU,
+   * AU), and up to 2 frames when we need to wait for the second frame
+   * start to determine the first frame is complete */
+  latency = gst_util_uint64_scale (2 * GST_SECOND, fps_d, fps_n);
+  gst_video_decoder_set_latency (vdec, latency, latency);
+
+  return TRUE;
+}
+
+/* check whether the decoded surface size has changed */
+static gboolean
+is_surface_resolution_changed (GstVaapiDecode * decode,
+    GstVaapiSurface * surface)
+{
+  GstVideoInfo *vinfo = &decode->decoded_info;
+  GstVideoFormat surface_format;
+  guint surface_width, surface_height;
+
+  g_return_val_if_fail (surface != NULL, FALSE);
+
+  gst_vaapi_surface_get_size (surface, &surface_width, &surface_height);
+
+  if (GST_VIDEO_INFO_WIDTH (vinfo) == surface_width
+      && GST_VIDEO_INFO_HEIGHT (vinfo) == surface_height)
+    return FALSE;
+
+  /* doing gst_vaapi_surface_get_format() only if necessary since it
+   * execute vaDeriveImage in the background. This will usually get
+   * executed only once */
+  surface_format = GST_VIDEO_INFO_FORMAT (vinfo);
+  if (surface_format == GST_VIDEO_FORMAT_UNKNOWN) {
+    surface_format = gst_vaapi_surface_get_format (surface);
+
+    /* if the VA context delivers a currently unrecognized format
+     * (ICM3, e.g.), we can assume one according surface chroma
+     * type. If fail, then use NV12 "safely" */
+    if (surface_format == GST_VIDEO_FORMAT_UNKNOWN
+        || surface_format == GST_VIDEO_FORMAT_ENCODED)
+      surface_format =
+          gst_vaapi_video_format_from_chroma (gst_vaapi_surface_get_chroma_type
+          (surface));
+    if (surface_format == GST_VIDEO_FORMAT_UNKNOWN)
+      surface_format = GST_VIDEO_FORMAT_NV12;
+  }
+
+  /* reset allowed source caps since they are dependant of the decoded
+   * surface format */
+  gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
+
+  gst_video_info_set_format (vinfo, surface_format, surface_width,
+      surface_height);
+
+  return TRUE;
+}
+
+/* check whether display resolution changed */
+static gboolean
+is_display_resolution_changed (GstVaapiDecode * decode,
+    const GstVaapiRectangle * crop_rect)
+{
+  GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
+  GstVideoCodecState *state;
+  guint display_width, display_height;
+  guint negotiated_width, negotiated_height;
+
+  display_width = GST_VIDEO_INFO_WIDTH (&decode->decoded_info);
+  display_height = GST_VIDEO_INFO_HEIGHT (&decode->decoded_info);
+  if (crop_rect) {
+    display_width = crop_rect->width;
+    display_height = crop_rect->height;
+  }
+
+  state = gst_video_decoder_get_output_state (vdec);
+  if (G_UNLIKELY (!state))
+    goto set_display_res;
+
+  negotiated_width = GST_VIDEO_INFO_WIDTH (&state->info);
+  negotiated_height = GST_VIDEO_INFO_HEIGHT (&state->info);
+  gst_video_codec_state_unref (state);
+
+  if ((display_width == negotiated_width && display_height == negotiated_height)
+      && (decode->display_width == negotiated_width
+          && decode->display_height == negotiated_height))
+    return FALSE;
+
+set_display_res:
+  decode->display_width = display_width;
+  decode->display_height = display_height;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapidecode_negotiate (GstVaapiDecode * decode)
+{
+  GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
+
+  GST_DEBUG_OBJECT (decode, "input codec state changed: renegotiating");
+
+  GST_VIDEO_DECODER_STREAM_LOCK (vdec);
+  if (!gst_vaapidecode_update_src_caps (decode))
+    goto caps_negotiation_failed;
+  if (!gst_vaapi_plugin_base_set_caps (plugin, NULL, decode->srcpad_caps))
+    goto caps_negotiation_failed;
+  GST_VIDEO_DECODER_STREAM_UNLOCK (vdec);
+
+  if (!gst_video_decoder_negotiate (vdec))
+    return FALSE;
+
+  return TRUE;
+
+caps_negotiation_failed:
+  {
+    GST_VIDEO_DECODER_STREAM_UNLOCK (vdec);
+    return FALSE;
+  }
+}
+
+static gboolean
+is_src_allocator_dmabuf (GstVaapiDecode * decode)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (decode);
+
+  if (!GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (plugin))
+    return FALSE;
+  return
+      gst_vaapi_is_dmabuf_allocator (GST_VAAPI_PLUGIN_BASE_SRC_PAD_ALLOCATOR
+      (plugin));
+}
+
+static GstFlowReturn
+gst_vaapidecode_push_decoded_frame (GstVideoDecoder * vdec,
+    GstVideoCodecFrame * out_frame)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+  GstVaapiSurfaceProxy *proxy;
+  GstVaapiSurface *surface;
+  GstFlowReturn ret;
+  const GstVaapiRectangle *crop_rect;
+  GstVaapiVideoMeta *meta;
+  GstBufferPoolAcquireParams *params = NULL;
+  GstVaapiVideoBufferPoolAcquireParams vaapi_params = { {0,}, };
+  guint flags, out_flags = 0;
+  gboolean alloc_renegotiate, caps_renegotiate;
+
+  if (!GST_VIDEO_CODEC_FRAME_IS_DECODE_ONLY (out_frame)) {
+    proxy = gst_video_codec_frame_get_user_data (out_frame);
+    surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
+    crop_rect = gst_vaapi_surface_proxy_get_crop_rect (proxy);
+
+    /* in theory, we are not supposed to check the surface resolution
+     * change here since it should be advertised before from ligstvaapi.
+     * But there are issues with it especially for some vp9 streams where
+     * upstream element set un-cropped values in set_format() which make
+     * everything a mess. So better doing the explicit check here irrespective
+     * of what notification we get from upstream or libgstvaapi.Also, even if
+     * we received notification from libgstvaapi, the frame we are going to
+     * be pushed at this point might not have the notified resolution if there
+     * are queued frames in decoded picture buffer. */
+    alloc_renegotiate = is_surface_resolution_changed (decode, surface);
+    caps_renegotiate = is_display_resolution_changed (decode, crop_rect);
+
+    if (gst_pad_needs_reconfigure (GST_VIDEO_DECODER_SRC_PAD (vdec))
+        || alloc_renegotiate || caps_renegotiate || decode->do_renego) {
+
+      g_atomic_int_set (&decode->do_renego, FALSE);
+      if (!gst_vaapidecode_negotiate (decode))
+        return GST_FLOW_ERROR;
+    }
+
+    if (is_src_allocator_dmabuf (decode)) {
+      vaapi_params.proxy = gst_vaapi_surface_proxy_ref (proxy);
+      params = (GstBufferPoolAcquireParams *) & vaapi_params;
+    }
+
+    ret = gst_video_decoder_allocate_output_frame_with_params (vdec, out_frame,
+        params);
+    if (params)
+      gst_vaapi_surface_proxy_unref (vaapi_params.proxy);
+    if (ret != GST_FLOW_OK)
+      goto error_create_buffer;
+
+    /* if not dmabuf is negotiated set the vaapi video meta in the
+     * proxy */
+    if (!params) {
+      meta = gst_buffer_get_vaapi_video_meta (out_frame->output_buffer);
+      if (!meta)
+        goto error_get_meta;
+      gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
+    }
+
+    flags = gst_vaapi_surface_proxy_get_flags (proxy);
+    if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_CORRUPTED)
+      out_flags |= GST_BUFFER_FLAG_CORRUPTED;
+    if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_INTERLACED) {
+      out_flags |= GST_VIDEO_BUFFER_FLAG_INTERLACED;
+      if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_TFF)
+        out_flags |= GST_VIDEO_BUFFER_FLAG_TFF;
+      if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_RFF)
+        out_flags |= GST_VIDEO_BUFFER_FLAG_RFF;
+      if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_ONEFIELD)
+        out_flags |= GST_VIDEO_BUFFER_FLAG_ONEFIELD;
+    }
+    GST_BUFFER_FLAG_SET (out_frame->output_buffer, out_flags);
+
+    if (flags & GST_VAAPI_SURFACE_PROXY_FLAG_FFB) {
+      GST_BUFFER_FLAG_SET (out_frame->output_buffer,
+          GST_VIDEO_BUFFER_FLAG_FIRST_IN_BUNDLE);
+    }
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+    if (decode->has_texture_upload_meta)
+      gst_buffer_ensure_texture_upload_meta (out_frame->output_buffer);
+#endif
+
+    /* Generate a system allocated output buffer if downstream doesn't
+     * support GstVideoMeta */
+    if (GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (vdec)) {
+      GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
+      GstBuffer *sys_buf, *va_buf;
+
+      va_buf = out_frame->output_buffer;
+      sys_buf =
+          gst_buffer_new_allocate (GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR
+          (plugin),
+          GST_VIDEO_INFO_SIZE (GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO (plugin)),
+          &GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR_PARAMS (plugin));
+      if (!sys_buf)
+        goto error_no_sys_buffer;
+
+      if (!gst_vaapi_plugin_copy_va_buffer (plugin, va_buf, sys_buf)) {
+        gst_buffer_unref (sys_buf);
+        goto error_cannot_copy;
+      }
+
+      gst_buffer_replace (&out_frame->output_buffer, sys_buf);
+      gst_buffer_unref (sys_buf);
+    }
+  }
+
+  ret = gst_video_decoder_finish_frame (vdec, out_frame);
+  if (ret != GST_FLOW_OK)
+    goto error_commit_buffer;
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_create_buffer:
+  {
+    const GstVaapiID surface_id =
+        gst_vaapi_surface_get_id (GST_VAAPI_SURFACE_PROXY_SURFACE (proxy));
+
+    GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
+        ("Failed to create sink buffer"),
+        ("video sink failed to create video buffer for proxy'ed "
+            "surface %" GST_VAAPI_ID_FORMAT, GST_VAAPI_ID_ARGS (surface_id)));
+    gst_video_decoder_drop_frame (vdec, out_frame);
+    return GST_FLOW_ERROR;
+  }
+error_get_meta:
+  {
+    GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
+        ("Failed to get vaapi video meta attached to video buffer"),
+        ("Failed to get vaapi video meta attached to video buffer"));
+    gst_video_decoder_drop_frame (vdec, out_frame);
+    return GST_FLOW_ERROR;
+  }
+error_no_sys_buffer:
+  {
+    GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
+        ("Failed to create system allocated buffer"),
+        ("Failed to create system allocated buffer"));
+    gst_video_decoder_drop_frame (vdec, out_frame);
+    return GST_FLOW_ERROR;
+  }
+error_cannot_copy:
+  {
+    GST_ELEMENT_ERROR (vdec, STREAM, FAILED,
+        ("Failed to copy system allocated buffer"),
+        ("Failed to copy system allocated buffer"));
+    gst_video_decoder_drop_frame (vdec, out_frame);
+    return GST_FLOW_ERROR;
+  }
+error_commit_buffer:
+  {
+    GST_LOG_OBJECT (decode, "downstream element rejected the frame (%s [%d])",
+        gst_flow_get_name (ret), ret);
+    return ret;
+  }
+}
+
+static GstFlowReturn
+gst_vaapidecode_push_all_decoded_frames (GstVaapiDecode * decode)
+{
+  GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
+  GstVaapiDecoderStatus status;
+  GstVideoCodecFrame *out_frame;
+  GstFlowReturn ret;
+
+  for (;;) {
+    status = gst_vaapi_decoder_get_frame (decode->decoder, &out_frame);
+
+    switch (status) {
+      case GST_VAAPI_DECODER_STATUS_SUCCESS:
+        /* GstVaapiDecode's queue adds an extra reference */
+        gst_video_codec_frame_unref (out_frame);
+        ret = gst_vaapidecode_push_decoded_frame (vdec, out_frame);
+        if (ret != GST_FLOW_OK)
+          return ret;
+        break;
+      case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
+        return GST_FLOW_OK;
+      default:
+        GST_VIDEO_DECODER_ERROR (vdec, 1, STREAM, DECODE, ("Decoding failed"),
+            ("Unknown decoding error"), ret);
+        return ret;
+    }
+  }
+  g_assert_not_reached ();
+}
+
+static GstFlowReturn
+gst_vaapidecode_handle_frame (GstVideoDecoder * vdec,
+    GstVideoCodecFrame * frame)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+  GstVaapiDecoderStatus status;
+
+  if (!decode->input_state)
+    goto not_negotiated;
+
+  /* Decode current frame */
+  for (;;) {
+    status = gst_vaapi_decoder_decode (decode->decoder, frame);
+    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+      goto error_decode;
+    break;
+  }
+
+  /* Note that gst_vaapi_decoder_decode cannot return success without
+     completing the decode and pushing all decoded frames into the output
+     queue */
+  return gst_vaapidecode_push_all_decoded_frames (decode);
+
+  /* ERRORS */
+error_decode:
+  {
+    GstFlowReturn ret = GST_FLOW_OK;
+
+    GST_WARNING_OBJECT (decode, "decode error %d", status);
+
+    switch (status) {
+      case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
+      case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
+      case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
+        ret = GST_FLOW_NOT_SUPPORTED;
+        break;
+      default:
+        GST_VIDEO_DECODER_ERROR (vdec, 1, STREAM, DECODE, ("Decoding error"),
+            ("Decode error %d", status), ret);
+        GST_INFO_OBJECT (decode, "requesting upstream a key unit");
+        gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decode),
+            gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
+                FALSE, 0));
+        break;
+    }
+    gst_video_decoder_drop_frame (vdec, frame);
+    return ret;
+  }
+not_negotiated:
+  {
+    GST_ERROR_OBJECT (decode, "not negotiated");
+    gst_video_decoder_drop_frame (vdec, frame);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+/* If there is something in GstVideoDecoder's output adapter, then
+   submit the frame for decoding */
+static inline void
+gst_vaapidecode_flush_output_adapter (GstVaapiDecode * decode)
+{
+  if (decode->current_frame_size == 0)
+    return;
+  gst_video_decoder_have_frame (GST_VIDEO_DECODER (decode));
+  decode->current_frame_size = 0;
+}
+
+static GstFlowReturn
+gst_vaapidecode_drain (GstVideoDecoder * vdec)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+
+  if (!decode->decoder)
+    return GST_FLOW_NOT_NEGOTIATED;
+
+  GST_LOG_OBJECT (decode, "drain");
+
+  gst_vaapidecode_flush_output_adapter (decode);
+  return gst_vaapidecode_push_all_decoded_frames (decode);
+}
+
+static GstFlowReturn
+gst_vaapidecode_finish (GstVideoDecoder * vdec)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+  GstVaapiDecoderStatus status;
+  GstFlowReturn ret;
+
+  if (!decode->decoder)
+    return GST_FLOW_OK;
+
+  gst_vaapidecode_flush_output_adapter (decode);
+  status = gst_vaapi_decoder_flush (decode->decoder);
+  ret = gst_vaapidecode_push_all_decoded_frames (decode);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    goto error_decoder_flush;
+  return ret;
+
+  /* ERRORS: */
+error_decoder_flush:
+  {
+    GST_WARNING_OBJECT (decode, "failed to flush decoder (status %d)", status);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+gst_vaapidecode_decide_allocation (GstVideoDecoder * vdec, GstQuery * query)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+  GstCaps *caps = NULL;
+
+  gst_query_parse_allocation (query, &caps, NULL);
+  if (!caps)
+    goto error_no_caps;
+
+  decode->has_texture_upload_meta = FALSE;
+
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+  decode->has_texture_upload_meta =
+      gst_query_find_allocation_meta (query,
+      GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL) &&
+      gst_vaapi_caps_feature_contains (caps,
+      GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META);
+#endif
+
+  return gst_vaapi_plugin_base_decide_allocation (GST_VAAPI_PLUGIN_BASE (vdec),
+      query);
+
+  /* ERRORS */
+error_no_caps:
+  {
+    GST_ERROR_OBJECT (decode, "no caps specified");
+    return FALSE;
+  }
+}
+
+static inline gboolean
+gst_vaapidecode_ensure_display (GstVaapiDecode * decode)
+{
+  return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode));
+}
+
+static gboolean
+gst_vaapidecode_create (GstVaapiDecode * decode, GstCaps * caps)
+{
+  GstVaapiDisplay *dpy;
+
+  if (!gst_vaapidecode_ensure_display (decode))
+    return FALSE;
+  dpy = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
+
+  switch (gst_vaapi_get_codec_from_caps (caps)) {
+    case GST_VAAPI_CODEC_MPEG2:
+      decode->decoder = gst_vaapi_decoder_mpeg2_new (dpy, caps);
+      break;
+    case GST_VAAPI_CODEC_MPEG4:
+    case GST_VAAPI_CODEC_H263:
+      decode->decoder = gst_vaapi_decoder_mpeg4_new (dpy, caps);
+      break;
+    case GST_VAAPI_CODEC_H264:
+      decode->decoder = gst_vaapi_decoder_h264_new (dpy, caps);
+
+      /* Set the stream buffer alignment for better optimizations */
+      if (decode->decoder && caps) {
+        GstVaapiDecodeH264Private *priv =
+            gst_vaapi_decode_h264_get_instance_private (decode);
+        GstStructure *const structure = gst_caps_get_structure (caps, 0);
+        const gchar *str = NULL;
+
+        if (!structure)
+          break;
+
+        if ((str = gst_structure_get_string (structure, "alignment"))) {
+          GstVaapiStreamAlignH264 alignment;
+          if (g_strcmp0 (str, "au") == 0)
+            alignment = GST_VAAPI_STREAM_ALIGN_H264_AU;
+          else if (g_strcmp0 (str, "nal") == 0)
+            alignment = GST_VAAPI_STREAM_ALIGN_H264_NALU;
+          else
+            alignment = GST_VAAPI_STREAM_ALIGN_H264_NONE;
+          gst_vaapi_decoder_h264_set_alignment (GST_VAAPI_DECODER_H264
+              (decode->decoder), alignment);
+        }
+
+        if (priv) {
+          gst_vaapi_decoder_h264_set_low_latency (GST_VAAPI_DECODER_H264
+              (decode->decoder), priv->is_low_latency);
+          gst_vaapi_decoder_h264_set_base_only (GST_VAAPI_DECODER_H264
+              (decode->decoder), priv->base_only);
+        }
+      }
+      break;
+    case GST_VAAPI_CODEC_H265:
+      decode->decoder = gst_vaapi_decoder_h265_new (dpy, caps);
+
+      /* Set the stream buffer alignment for better optimizations */
+      if (decode->decoder && caps) {
+        GstStructure *const structure = gst_caps_get_structure (caps, 0);
+        const gchar *str = NULL;
+
+        if (!structure)
+          break;
+
+        if ((str = gst_structure_get_string (structure, "alignment"))) {
+          GstVaapiStreamAlignH265 alignment;
+          if (g_strcmp0 (str, "au") == 0)
+            alignment = GST_VAAPI_STREAM_ALIGN_H265_AU;
+          else if (g_strcmp0 (str, "nal") == 0)
+            alignment = GST_VAAPI_STREAM_ALIGN_H265_NALU;
+          else
+            alignment = GST_VAAPI_STREAM_ALIGN_H265_NONE;
+          gst_vaapi_decoder_h265_set_alignment (GST_VAAPI_DECODER_H265
+              (decode->decoder), alignment);
+        }
+      }
+      break;
+    case GST_VAAPI_CODEC_WMV3:
+    case GST_VAAPI_CODEC_VC1:
+      decode->decoder = gst_vaapi_decoder_vc1_new (dpy, caps);
+      break;
+    case GST_VAAPI_CODEC_JPEG:
+      decode->decoder = gst_vaapi_decoder_jpeg_new (dpy, caps);
+      break;
+    case GST_VAAPI_CODEC_VP8:
+      decode->decoder = gst_vaapi_decoder_vp8_new (dpy, caps);
+      break;
+    case GST_VAAPI_CODEC_VP9:
+      decode->decoder = gst_vaapi_decoder_vp9_new (dpy, caps);
+      break;
+#if GST_VAAPI_USE_AV1_DECODER
+    case GST_VAAPI_CODEC_AV1:
+      decode->decoder = gst_vaapi_decoder_av1_new (dpy, caps);
+      break;
+#endif
+    default:
+      decode->decoder = NULL;
+      break;
+  }
+  if (!decode->decoder)
+    return FALSE;
+
+  gst_vaapi_decoder_set_codec_state_changed_func (decode->decoder,
+      gst_vaapi_decoder_state_changed, decode);
+
+  return TRUE;
+}
+
+static void
+gst_vaapidecode_purge (GstVaapiDecode * decode)
+{
+  GstVaapiDecoderStatus status;
+
+  if (!decode->decoder)
+    return;
+
+  status = gst_vaapi_decoder_flush (decode->decoder);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+    GST_INFO_OBJECT (decode, "failed to flush decoder (status %d)", status);
+
+  /* Purge all decoded frames as we don't need them (e.g. flush and close)
+   * Releasing the frames is important, otherwise the frames are not
+   * freed. */
+  do {
+    GstVideoCodecFrame *frame = NULL;
+
+    status =
+        gst_vaapi_decoder_get_frame_with_timeout (decode->decoder, &frame, 0);
+    if (frame) {
+      gst_video_decoder_release_frame (GST_VIDEO_DECODER (decode), frame);
+      gst_video_codec_frame_unref (frame);
+    }
+  } while (status == GST_VAAPI_DECODER_STATUS_SUCCESS);
+}
+
+static void
+gst_vaapidecode_destroy (GstVaapiDecode * decode)
+{
+  gst_vaapidecode_purge (decode);
+
+  gst_vaapi_decoder_replace (&decode->decoder, NULL);
+  /* srcpad caps are decoder's context dependant */
+  gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
+}
+
+static gboolean
+gst_vaapidecode_reset (GstVaapiDecode * decode, GstCaps * caps,
+    gboolean force_reset)
+{
+  /* Reset tracked frame size */
+  decode->current_frame_size = 0;
+
+  if (decode->decoder) {
+    if (!gst_caps_is_equal (caps, gst_vaapi_decoder_get_caps (decode->decoder))) {
+      if (gst_vaapi_decoder_update_caps (decode->decoder, caps)) {
+        g_atomic_int_set (&decode->do_renego, TRUE);
+        if (!force_reset)
+          return TRUE;
+      }
+    }
+    return (gst_vaapi_decoder_reset (decode->decoder) ==
+        GST_VAAPI_DECODER_STATUS_SUCCESS);
+  }
+
+  return gst_vaapidecode_create (decode, caps);
+}
+
+static void
+gst_vaapidecode_finalize (GObject * object)
+{
+  gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object));
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_vaapidecode_open (GstVideoDecoder * vdec)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+
+  if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (decode)))
+    return FALSE;
+
+  decode->display_width = 0;
+  decode->display_height = 0;
+  gst_video_info_init (&decode->decoded_info);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapidecode_close (GstVideoDecoder * vdec)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+
+  gst_vaapidecode_destroy (decode);
+  gst_caps_replace (&decode->allowed_srcpad_caps, NULL);
+  gst_caps_replace (&decode->allowed_sinkpad_caps, NULL);
+  gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (decode));
+  return TRUE;
+}
+
+static gboolean
+gst_vaapidecode_start (GstVideoDecoder * vdec)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+  GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
+  gboolean success;
+
+  /* Let GstVideoContext ask for a proper display to its neighbours */
+  /* Note: steal old display that may be allocated from get_caps()
+     so that to retain a reference to it, thus avoiding extra
+     initialization steps if we turn out to simply re-use the
+     existing (cached) VA display */
+  GST_VAAPI_PLUGIN_BASE_DISPLAY (decode) = NULL;
+  success =
+      gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (decode));
+  if (old_display)
+    gst_object_unref (old_display);
+
+  /* Disable errors on decode errors */
+  gst_video_decoder_set_max_errors (vdec, -1);
+
+  return success;
+}
+
+static gboolean
+gst_vaapidecode_stop (GstVideoDecoder * vdec)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+
+  gst_vaapidecode_purge (decode);
+  gst_vaapi_decode_input_state_replace (decode, NULL);
+  gst_vaapi_decoder_replace (&decode->decoder, NULL);
+  gst_caps_replace (&decode->sinkpad_caps, NULL);
+  gst_caps_replace (&decode->srcpad_caps, NULL);
+  return TRUE;
+}
+
+static gboolean
+gst_vaapidecode_flush (GstVideoDecoder * vdec)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+  if (!decode->decoder)
+    return FALSE;
+
+  GST_LOG_OBJECT (vdec, "flushing");
+
+  gst_vaapidecode_purge (decode);
+
+  /* There could be issues if we avoid the reset() while doing
+   * seeking: we have to reset the internal state */
+  return gst_vaapidecode_reset (decode, decode->sinkpad_caps, TRUE);
+}
+
+static gboolean
+gst_vaapidecode_set_format (GstVideoDecoder * vdec, GstVideoCodecState * state)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (vdec);
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+
+  if (!gst_vaapi_decode_input_state_replace (decode, state))
+    return TRUE;
+  if (gst_vaapidecode_drain (vdec) == GST_FLOW_ERROR)
+    return FALSE;
+  if (!gst_vaapidecode_update_sink_caps (decode, state->caps))
+    return FALSE;
+  if (!gst_vaapi_plugin_base_set_caps (plugin, decode->sinkpad_caps, NULL))
+    return FALSE;
+  if (!gst_vaapidecode_reset (decode, decode->sinkpad_caps, FALSE))
+    return FALSE;
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_vaapidecode_parse_frame (GstVideoDecoder * vdec,
+    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+  GstVaapiDecoderStatus status;
+  GstFlowReturn ret;
+  guint got_unit_size;
+  gboolean got_frame;
+
+  status = gst_vaapi_decoder_parse (decode->decoder, frame,
+      adapter, at_eos, &got_unit_size, &got_frame);
+
+  switch (status) {
+    case GST_VAAPI_DECODER_STATUS_SUCCESS:
+      if (got_unit_size > 0) {
+        gst_video_decoder_add_to_frame (vdec, got_unit_size);
+        decode->current_frame_size += got_unit_size;
+      }
+      if (got_frame) {
+        ret = gst_video_decoder_have_frame (vdec);
+        decode->current_frame_size = 0;
+      } else
+        ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
+      break;
+    case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
+      ret = GST_VIDEO_DECODER_FLOW_NEED_DATA;
+      break;
+    case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CODEC:
+    case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_PROFILE:
+    case GST_VAAPI_DECODER_STATUS_ERROR_UNSUPPORTED_CHROMA_FORMAT:
+      GST_WARNING ("parse error %d", status);
+      ret = GST_FLOW_NOT_SUPPORTED;
+      decode->current_frame_size = 0;
+      break;
+    default:
+      GST_WARNING ("parse error %d", status);
+      /* just keep parsing, the decoder should have flushed the broken unit */
+      ret = GST_VAAPI_DECODE_FLOW_PARSE_DATA;
+      decode->current_frame_size = 0;
+
+      GST_INFO ("requesting upstream a key unit");
+      gst_pad_push_event (GST_VIDEO_DECODER_SINK_PAD (decode),
+          gst_video_event_new_upstream_force_key_unit (GST_CLOCK_TIME_NONE,
+              FALSE, 0));
+      break;
+  }
+  return ret;
+}
+
+static GstFlowReturn
+gst_vaapidecode_parse (GstVideoDecoder * vdec,
+    GstVideoCodecFrame * frame, GstAdapter * adapter, gboolean at_eos)
+{
+  GstFlowReturn ret;
+
+  do {
+    ret = gst_vaapidecode_parse_frame (vdec, frame, adapter, at_eos);
+  } while (ret == GST_VAAPI_DECODE_FLOW_PARSE_DATA);
+  return ret;
+}
+
+static gboolean
+is_mvc_profile (GstVaapiProfile profile)
+{
+  return profile == GST_VAAPI_PROFILE_H264_MULTIVIEW_HIGH
+      || profile == GST_VAAPI_PROFILE_H264_STEREO_HIGH;
+}
+
+static gboolean
+is_svc_profile (GstVaapiProfile profile)
+{
+  return profile == GST_VAAPI_PROFILE_H264_SCALABLE_BASELINE
+      || profile == GST_VAAPI_PROFILE_H264_SCALABLE_HIGH;
+}
+
+static void
+find_mvc_and_svc (GArray * profiles, gboolean * have_mvc, gboolean * have_svc)
+{
+  guint i;
+
+  for (i = 0; i < profiles->len; i++) {
+    const GstVaapiProfile profile =
+        g_array_index (profiles, GstVaapiProfile, i);
+
+    *have_mvc |= is_mvc_profile (profile);
+    *have_svc |= is_svc_profile (profile);
+  }
+}
+
+static gboolean
+gst_vaapidecode_ensure_allowed_sinkpad_caps (GstVaapiDecode * decode)
+{
+  GstCaps *caps, *allowed_sinkpad_caps;
+  GstPad *const sinkpad = GST_VIDEO_DECODER_SINK_PAD (decode);
+  GArray *profiles;
+  GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (decode);
+  guint i;
+  gboolean base_only = FALSE;
+  gboolean have_mvc = FALSE;
+  gboolean have_svc = FALSE;
+
+  profiles = gst_vaapi_display_get_decode_profiles (display);
+  if (!profiles)
+    goto error_no_profiles;
+
+  allowed_sinkpad_caps = gst_caps_new_empty ();
+  if (!allowed_sinkpad_caps)
+    goto error_no_memory;
+
+  if (g_object_class_find_property (G_OBJECT_GET_CLASS (decode), "base-only")) {
+    g_object_get (decode, "base-only", &base_only, NULL);
+  }
+
+  find_mvc_and_svc (profiles, &have_mvc, &have_svc);
+
+  for (i = 0; i < profiles->len; i++) {
+    const GstVaapiProfile profile =
+        g_array_index (profiles, GstVaapiProfile, i);
+    const gchar *media_type_name;
+    const gchar *profile_name;
+    GstStructure *structure;
+
+    media_type_name = gst_vaapi_profile_get_media_type_name (profile);
+    if (!media_type_name)
+      continue;
+
+    caps = gst_caps_from_string (media_type_name);
+    if (!caps)
+      continue;
+    structure = gst_caps_get_structure (caps, 0);
+    if (!structure)
+      continue;
+
+    profile_name = gst_vaapi_profile_get_name (profile);
+    if (!profile_name)
+      goto merge_caps;
+
+    /* Add all according -intra profile for HEVC */
+    if (profile == GST_VAAPI_PROFILE_H265_MAIN
+        || profile == GST_VAAPI_PROFILE_H265_MAIN10
+        || profile == GST_VAAPI_PROFILE_H265_MAIN_422_10
+        || profile == GST_VAAPI_PROFILE_H265_MAIN_444
+        || profile == GST_VAAPI_PROFILE_H265_MAIN_444_10
+        || profile == GST_VAAPI_PROFILE_H265_MAIN12
+        || profile == GST_VAAPI_PROFILE_H265_MAIN_444_12
+        || profile == GST_VAAPI_PROFILE_H265_MAIN_422_12) {
+      gchar *profiles[3], *intra_name;
+
+      intra_name = g_strdup_printf ("%s-intra", profile_name);
+
+      profiles[0] = (gchar *) profile_name;
+      profiles[1] = intra_name;
+      profiles[2] = NULL;
+
+      gst_vaapi_structure_set_profiles (structure, profiles);
+      g_free (intra_name);
+
+    } else if (profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE) {
+      /* XXX: artificially adding baseline if constrained_baseline is
+       * available. */
+      gchar *profiles[] = { (gchar *) profile_name, "baseline", NULL };
+
+      gst_vaapi_structure_set_profiles (structure, profiles);
+    } else if (profile == GST_VAAPI_PROFILE_H264_HIGH) {
+      gchar *profiles[11] = { (gchar *) profile_name, "progressive-high",
+        "constrained-high"
+      };
+      gint i = 3;
+
+      if (base_only && !have_mvc) {
+        GST_DEBUG ("base_only: force adding MVC profiles in caps");
+
+        profiles[i++] = "multiview-high";
+        profiles[i++] = "stereo-high";
+      }
+
+      if (base_only && !have_svc) {
+        GST_DEBUG ("base_only: force adding SVC profiles in caps");
+
+        profiles[i++] = "scalable-constrained-baseline";
+        profiles[i++] = "scalable-baseline";
+        profiles[i++] = "scalable-high-intra";
+        profiles[i++] = "scalable-constrained-high";
+        profiles[i++] = "scalable-high";
+      }
+
+      profiles[i++] = NULL;
+
+      gst_vaapi_structure_set_profiles (structure, profiles);
+    } else {
+      gst_structure_set (structure, "profile", G_TYPE_STRING,
+          profile_name, NULL);
+    }
+
+  merge_caps:
+    gst_vaapi_profile_caps_append_decoder (display, profile, structure);
+    allowed_sinkpad_caps = gst_caps_merge (allowed_sinkpad_caps, caps);
+  }
+
+  caps = gst_pad_get_pad_template_caps (sinkpad);
+  decode->allowed_sinkpad_caps =
+      gst_caps_intersect (allowed_sinkpad_caps, caps);
+  gst_caps_unref (caps);
+  gst_caps_unref (allowed_sinkpad_caps);
+  decode->allowed_sinkpad_caps =
+      gst_caps_simplify (decode->allowed_sinkpad_caps);
+  GST_DEBUG_OBJECT (decode, "allowed sink caps %" GST_PTR_FORMAT,
+      decode->allowed_sinkpad_caps);
+
+  g_array_unref (profiles);
+  return TRUE;
+
+  /* ERRORS */
+error_no_profiles:
+  {
+    GST_ERROR ("failed to retrieve VA decode profiles");
+    return FALSE;
+  }
+error_no_memory:
+  {
+    GST_ERROR ("failed to allocate allowed-caps set");
+    g_array_unref (profiles);
+    return FALSE;
+  }
+}
+
+static GstCaps *
+gst_vaapidecode_sink_getcaps (GstVideoDecoder * vdec, GstCaps * filter)
+{
+  GstVaapiDecode *const decode = GST_VAAPIDECODE (vdec);
+  GstCaps *result;
+
+  if (decode->allowed_sinkpad_caps)
+    goto bail;
+
+  /* if we haven't a display yet, return our pad's template caps */
+  if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (decode))
+    goto bail;
+
+  /* if the allowed caps calculation fails, return an empty caps, so
+   * the auto-plug can try other decoder */
+  if (!gst_vaapidecode_ensure_allowed_sinkpad_caps (decode))
+    return gst_caps_new_empty ();
+
+bail:
+  result = gst_video_decoder_proxy_getcaps (vdec, decode->allowed_sinkpad_caps,
+      filter);
+
+  GST_DEBUG_OBJECT (decode, "Returning sink caps %" GST_PTR_FORMAT, result);
+
+  return result;
+}
+
+static gboolean
+gst_vaapidecode_sink_query (GstVideoDecoder * vdec, GstQuery * query)
+{
+  gboolean ret = TRUE;
+  GstElement *const element = GST_ELEMENT (vdec);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONTEXT:{
+      ret = gst_vaapi_handle_context_query (element, query);
+      break;
+    }
+    default:{
+      ret = GST_VIDEO_DECODER_CLASS (parent_class)->sink_query (vdec, query);
+      break;
+    }
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_vaapidecode_src_query (GstVideoDecoder * vdec, GstQuery * query)
+{
+  gboolean ret = TRUE;
+  GstElement *const element = GST_ELEMENT (vdec);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONTEXT:{
+      ret = gst_vaapi_handle_context_query (element, query);
+      break;
+    }
+    case GST_QUERY_CAPS:{
+      GstCaps *caps, *filter = NULL;
+      gboolean fixed_caps;
+
+      fixed_caps = GST_PAD_IS_FIXED_CAPS (GST_VIDEO_DECODER_SRC_PAD (vdec));
+      if (!fixed_caps) {
+        gst_query_parse_caps (query, &filter);
+        caps = gst_vaapidecode_get_allowed_srcpad_caps (GST_VAAPIDECODE (vdec));
+
+        if (filter) {
+          GstCaps *tmp = caps;
+          caps =
+              gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
+          gst_caps_unref (tmp);
+        }
+
+        gst_query_set_caps_result (query, caps);
+        gst_caps_unref (caps);
+        break;
+      }
+      /* else jump to default */
+    }
+    default:{
+      ret = GST_VIDEO_DECODER_CLASS (parent_class)->src_query (vdec, query);
+      break;
+    }
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_vaapidecode_transform_meta (GstVideoDecoder *
+    vdec, GstVideoCodecFrame * frame, GstMeta * meta)
+{
+  const GstMetaInfo *info = meta->info;
+
+  if (GST_VIDEO_DECODER_CLASS (parent_class)->transform_meta (vdec, frame,
+          meta))
+    return TRUE;
+
+  if (!g_strcmp0 (g_type_name (info->type), "GstVideoRegionOfInterestMeta"))
+    return TRUE;
+
+  return FALSE;
+}
+
+static void
+gst_vaapidecode_class_init (GstVaapiDecodeClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstVideoDecoderClass *const vdec_class = GST_VIDEO_DECODER_CLASS (klass);
+  GstPadTemplate *pad_template;
+  GstVaapiDecoderMap *map;
+  gchar *name, *longname, *description;
+  GstCaps *caps;
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_vaapidecode,
+      GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
+
+  parent_class = g_type_class_peek_parent (klass);
+
+  gst_vaapi_plugin_base_class_init (GST_VAAPI_PLUGIN_BASE_CLASS (klass));
+
+  object_class->finalize = gst_vaapidecode_finalize;
+
+  vdec_class->open = GST_DEBUG_FUNCPTR (gst_vaapidecode_open);
+  vdec_class->close = GST_DEBUG_FUNCPTR (gst_vaapidecode_close);
+  vdec_class->start = GST_DEBUG_FUNCPTR (gst_vaapidecode_start);
+  vdec_class->stop = GST_DEBUG_FUNCPTR (gst_vaapidecode_stop);
+  vdec_class->set_format = GST_DEBUG_FUNCPTR (gst_vaapidecode_set_format);
+  vdec_class->flush = GST_DEBUG_FUNCPTR (gst_vaapidecode_flush);
+  vdec_class->parse = GST_DEBUG_FUNCPTR (gst_vaapidecode_parse);
+  vdec_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vaapidecode_handle_frame);
+  vdec_class->finish = GST_DEBUG_FUNCPTR (gst_vaapidecode_finish);
+  vdec_class->drain = GST_DEBUG_FUNCPTR (gst_vaapidecode_drain);
+  vdec_class->decide_allocation =
+      GST_DEBUG_FUNCPTR (gst_vaapidecode_decide_allocation);
+  vdec_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_src_query);
+  vdec_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_query);
+  vdec_class->getcaps = GST_DEBUG_FUNCPTR (gst_vaapidecode_sink_getcaps);
+  vdec_class->transform_meta =
+      GST_DEBUG_FUNCPTR (gst_vaapidecode_transform_meta);
+
+  map = (GstVaapiDecoderMap *) g_type_get_qdata (G_OBJECT_CLASS_TYPE (klass),
+      GST_VAAPI_DECODE_PARAMS_QDATA);
+
+  if (map->codec) {
+    name = g_ascii_strup (map->name, -1);
+    longname = g_strdup_printf ("VA-API %s decoder", name);
+    description = g_strdup_printf ("A VA-API based %s video decoder", name);
+    g_free (name);
+  } else {
+    longname = g_strdup ("VA-API decoder");
+    description = g_strdup (GST_PLUGIN_DESC);
+  }
+
+  element_class->set_context = gst_vaapi_base_set_context;
+  gst_element_class_set_static_metadata (element_class, longname,
+      "Codec/Decoder/Video/Hardware", description,
+      "Gwenole Beauchesne <gwenole.beauchesne@intel.com>, "
+      "Halley Zhao <halley.zhao@intel.com>, "
+      "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
+      "Wind Yuan <feng.yuan@intel.com>, Junyan He <junyan.he@intel.com>");
+
+  g_free (longname);
+  g_free (description);
+
+  if (map->install_properties)
+    map->install_properties (object_class);
+
+  /* sink pad */
+  if (map->caps_str) {
+    caps = gst_caps_from_string (map->caps_str);
+  } else {
+    caps = gst_caps_from_string (gst_vaapidecode_sink_caps_str);
+    g_free (gst_vaapidecode_sink_caps_str);
+  }
+  pad_template = gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
+      caps);
+  gst_caps_unref (caps);
+  gst_element_class_add_pad_template (element_class, pad_template);
+
+  /* src pad */
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vaapidecode_src_factory);
+}
+
+static void
+gst_vaapidecode_init (GstVaapiDecode * decode)
+{
+  GstVideoDecoder *const vdec = GST_VIDEO_DECODER (decode);
+
+  gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (decode), GST_CAT_DEFAULT);
+
+  gst_video_decoder_set_packetized (vdec, FALSE);
+}
+
+gboolean
+gst_vaapidecode_register (GstPlugin * plugin, GArray * decoders)
+{
+  gboolean ret = FALSE;
+  guint i, codec, rank;
+  gchar *type_name, *element_name, *sink_caps_str;
+  const gchar *name;
+  GType type;
+  GTypeInfo typeinfo = {
+    sizeof (GstVaapiDecodeClass),
+    NULL,
+    NULL,
+    (GClassInitFunc) gst_vaapidecode_class_init,
+    NULL,
+    NULL,
+    sizeof (GstVaapiDecode),
+    0,
+    (GInstanceInitFunc) gst_vaapidecode_init,
+  };
+
+  for (i = 0; i < G_N_ELEMENTS (vaapi_decode_map); i++) {
+    codec = vaapi_decode_map[i].codec;
+    rank = vaapi_decode_map[i].rank;
+    name = vaapi_decode_map[i].name;
+
+    if (codec && !gst_vaapi_codecs_has_codec (decoders, codec))
+      continue;
+
+    if (!gst_vaapidecode_sink_caps_str) {
+      gst_vaapidecode_sink_caps_str = g_strdup (vaapi_decode_map[i].caps_str);
+    } else {
+      sink_caps_str = g_strconcat (gst_vaapidecode_sink_caps_str, "; ",
+          vaapi_decode_map[i].caps_str, NULL);
+      g_clear_pointer (&gst_vaapidecode_sink_caps_str, g_free);
+      if (!sink_caps_str)
+        break;
+      gst_vaapidecode_sink_caps_str = sink_caps_str;
+    }
+
+    if (codec) {
+      type_name = g_strdup_printf ("GstVaapiDecode_%s", name);
+      element_name = g_strdup_printf ("vaapi%sdec", name);
+    } else {
+      type_name = g_strdup ("GstVaapiDecode");
+      element_name = g_strdup_printf ("vaapidecode");
+    }
+
+    type = g_type_from_name (type_name);
+    if (!type) {
+      /* create the gtype now */
+      type = g_type_register_static (GST_TYPE_VIDEO_DECODER, type_name,
+          &typeinfo, 0);
+      gst_vaapi_plugin_base_init_interfaces (type);
+      g_type_set_qdata (type, GST_VAAPI_DECODE_PARAMS_QDATA,
+          (gpointer) & vaapi_decode_map[i]);
+    }
+
+    /* Register GstVaapiDecode as GObject type, but not in GStreamer, so
+     * vaapidecodebin can use it internally, but no exposed as a plugin
+     * feature */
+    if (codec)
+      ret |= gst_element_register (plugin, element_name, rank, type);
+
+    g_free (element_name);
+    g_free (type_name);
+  }
+
+  return ret;
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode.h
new file mode 100644 (file)
index 0000000..77ab3ce
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ *  gstvaapidecode.h - VA-API video decoder
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIDECODE_H
+#define GST_VAAPIDECODE_H
+
+#include "gstvaapipluginbase.h"
+#include <gst/vaapi/gstvaapidecoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPIDECODE(obj) ((GstVaapiDecode *)(obj))
+
+typedef struct _GstVaapiDecode                  GstVaapiDecode;
+typedef struct _GstVaapiDecodeClass             GstVaapiDecodeClass;
+
+struct _GstVaapiDecode {
+    /*< private >*/
+    GstVaapiPluginBase  parent_instance;
+
+    GstCaps            *sinkpad_caps;
+    GstCaps            *srcpad_caps;
+    GstVideoInfo        decoded_info;
+    GstVaapiDecoder    *decoder;
+    GstCaps            *allowed_sinkpad_caps;
+    GstCaps            *allowed_srcpad_caps;
+    guint               current_frame_size;
+    guint               has_texture_upload_meta : 1;
+
+    guint               display_width;
+    guint               display_height;
+
+    GstVideoCodecState *input_state;
+
+    gboolean            do_renego;
+};
+
+struct _GstVaapiDecodeClass {
+    /*< private >*/
+    GstVaapiPluginBaseClass parent_class;
+};
+
+gboolean gst_vaapidecode_register (GstPlugin * plugin, GArray * decoders);
+
+G_END_DECLS
+
+#endif /* GST_VAAPIDECODE_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode_props.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode_props.c
new file mode 100644 (file)
index 0000000..dc52677
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *  gstvaapidecode_props.c - VA-API decoders specific properties
+ *
+ *  Copyright (C) 2017 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *    Author: Victor Jaquez <vjaquez@igalia.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstvaapidecode_props.h"
+#include "gstvaapidecode.h"
+
+#include <gst/vaapi/gstvaapidecoder_h264.h>
+
+enum
+{
+  GST_VAAPI_DECODER_H264_PROP_FORCE_LOW_LATENCY = 1,
+  GST_VAAPI_DECODER_H264_PROP_BASE_ONLY,
+};
+
+static gint h264_private_offset;
+
+static void
+gst_vaapi_decode_h264_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDecodeH264Private *priv;
+
+  priv = gst_vaapi_decode_h264_get_instance_private (object);
+
+  switch (prop_id) {
+    case GST_VAAPI_DECODER_H264_PROP_FORCE_LOW_LATENCY:
+      g_value_set_boolean (value, priv->is_low_latency);
+      break;
+    case GST_VAAPI_DECODER_H264_PROP_BASE_ONLY:
+      g_value_set_boolean (value, priv->base_only);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_decode_h264_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDecodeH264Private *priv;
+  GstVaapiDecoderH264 *decoder;
+
+  priv = gst_vaapi_decode_h264_get_instance_private (object);
+
+  switch (prop_id) {
+    case GST_VAAPI_DECODER_H264_PROP_FORCE_LOW_LATENCY:
+      priv->is_low_latency = g_value_get_boolean (value);
+      decoder = GST_VAAPI_DECODER_H264 (GST_VAAPIDECODE (object)->decoder);
+      if (decoder)
+        gst_vaapi_decoder_h264_set_low_latency (decoder, priv->is_low_latency);
+      break;
+    case GST_VAAPI_DECODER_H264_PROP_BASE_ONLY:
+      priv->base_only = g_value_get_boolean (value);
+      decoder = GST_VAAPI_DECODER_H264 (GST_VAAPIDECODE (object)->decoder);
+      if (decoder)
+        gst_vaapi_decoder_h264_set_base_only (decoder, priv->base_only);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+void
+gst_vaapi_decode_h264_install_properties (GObjectClass * klass)
+{
+  h264_private_offset = sizeof (GstVaapiDecodeH264Private);
+  g_type_class_adjust_private_offset (klass, &h264_private_offset);
+
+  klass->get_property = gst_vaapi_decode_h264_get_property;
+  klass->set_property = gst_vaapi_decode_h264_set_property;
+
+  g_object_class_install_property (klass,
+      GST_VAAPI_DECODER_H264_PROP_FORCE_LOW_LATENCY,
+      g_param_spec_boolean ("low-latency", "Force low latency mode",
+          "When enabled, frames will be pushed as soon as they are available. "
+          "It might violate the H.264 spec.", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT));
+
+  g_object_class_install_property (klass, GST_VAAPI_DECODER_H264_PROP_BASE_ONLY,
+      g_param_spec_boolean ("base-only", "Decode base view only",
+          "Drop any NAL unit not defined in Annex.A", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+}
+
+GstVaapiDecodeH264Private *
+gst_vaapi_decode_h264_get_instance_private (gpointer self)
+{
+  if (h264_private_offset == 0)
+    return NULL;
+  return (G_STRUCT_MEMBER_P (self, h264_private_offset));
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode_props.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecode_props.h
new file mode 100644 (file)
index 0000000..b1f2fec
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ *  gstvaapidecode_props.h - VA-API decoders specific properties
+ *
+ *  Copyright (C) 2017 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *    Author: Victor Jaquez <vjaquez@igalia.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODE_PROPS_H
+#define GST_VAAPI_DECODE_PROPS_H
+
+#include "gstcompat.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiDecodeH264Private GstVaapiDecodeH264Private;
+
+struct _GstVaapiDecodeH264Private
+{
+  gboolean is_low_latency;
+  gboolean base_only;
+};
+
+void
+gst_vaapi_decode_h264_install_properties (GObjectClass * klass);
+
+GstVaapiDecodeH264Private *
+gst_vaapi_decode_h264_get_instance_private (gpointer self);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODE_PROPS_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecodebin.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecodebin.c
new file mode 100644 (file)
index 0000000..0756dd7
--- /dev/null
@@ -0,0 +1,434 @@
+/*
+ *  gstvaapidecodebin.c
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *    Author: Victor Jaquez <victorx.jaquez@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapidecodebin
+ * @short_description: A VA-API based video decoder with a
+ * post-processor
+ *
+ * vaapidecodebin is similar vaapi{CODEC}dec, but it is composed by
+ * the unregistered vaapidecode, a #GstQueue, and the
+ * #GstVaapiPostproc, if it is available and functional in the setup.
+ *
+ * It offers the functionality of GstVaapiDecoder and the many options
+ * of #GstVaapiPostproc.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 filesrc location=~/big_buck_bunny.mov ! qtdemux ! h264parse ! vaapidecodebin ! vaapisink
+ * ]|
+ */
+
+#include "gstcompat.h"
+#include <stdio.h>
+#include <string.h>
+#include <gst/gst.h>
+#include <gst/pbutils/pbutils.h>
+#include "gstvaapipluginutil.h"
+#include "gstvaapidecodebin.h"
+#include "gstvaapivideocontext.h"
+#include "gstvaapipluginbase.h"
+#include "gstvaapi.h"
+
+#define GST_PLUGIN_NAME "vaapidecodebin"
+#define GST_PLUGIN_DESC "A VA-API based bin with a decoder and a postprocessor"
+
+GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_decode_bin);
+#define GST_CAT_DEFAULT gst_debug_vaapi_decode_bin
+
+#define DEFAULT_QUEUE_MAX_SIZE_BUFFERS 1
+#define DEFAULT_QUEUE_MAX_SIZE_BYTES   0
+#define DEFAULT_QUEUE_MAX_SIZE_TIME    0
+#define DEFAULT_DEINTERLACE_METHOD     GST_VAAPI_DEINTERLACE_METHOD_BOB
+
+enum
+{
+  PROP_0,
+  PROP_MAX_SIZE_BUFFERS,
+  PROP_MAX_SIZE_BYTES,
+  PROP_MAX_SIZE_TIME,
+  PROP_DEINTERLACE_METHOD,
+  PROP_DISABLE_VPP,
+  PROP_LAST
+};
+
+static GParamSpec *properties[PROP_LAST];
+
+/* Default templates */
+#define GST_CAPS_CODEC(CODEC) CODEC "; "
+/* *INDENT-OFF* */
+static const char gst_vaapi_decode_bin_sink_caps_str[] =
+    GST_CAPS_CODEC("video/mpeg, mpegversion=2, systemstream=(boolean)false")
+    GST_CAPS_CODEC("video/mpeg, mpegversion=4")
+    GST_CAPS_CODEC("video/x-divx")
+    GST_CAPS_CODEC("video/x-xvid")
+    GST_CAPS_CODEC("video/x-h263")
+    GST_CAPS_CODEC("video/x-h264")
+    GST_CAPS_CODEC("video/x-h265")
+    GST_CAPS_CODEC("video/x-wmv")
+    GST_CAPS_CODEC("video/x-vp8")
+    GST_CAPS_CODEC("video/x-vp9")
+    ;
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+static const char gst_vaapi_decode_bin_src_caps_str[] =
+  GST_VAAPI_MAKE_SURFACE_CAPS ", "
+  GST_CAPS_INTERLACED_FALSE "; "
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+  GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS ", "
+  GST_CAPS_INTERLACED_FALSE "; "
+#endif
+  GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL) ", "
+  GST_CAPS_INTERLACED_FALSE;
+/* *INDENT-ON* */
+
+static GstStaticPadTemplate gst_vaapi_decode_bin_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (gst_vaapi_decode_bin_sink_caps_str));
+
+static GstStaticPadTemplate gst_vaapi_decode_bin_src_factory =
+GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (gst_vaapi_decode_bin_src_caps_str));
+
+G_DEFINE_TYPE (GstVaapiDecodeBin, gst_vaapi_decode_bin, GST_TYPE_BIN);
+
+extern gboolean _gst_vaapi_has_video_processing;
+
+static gboolean gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * self);
+
+static void
+gst_vaapi_decode_bin_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
+
+  switch (prop_id) {
+    case PROP_MAX_SIZE_BYTES:
+      vaapidecbin->max_size_bytes = g_value_get_uint (value);
+      g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-bytes",
+          vaapidecbin->max_size_bytes, NULL);
+      break;
+    case PROP_MAX_SIZE_BUFFERS:
+      vaapidecbin->max_size_buffers = g_value_get_uint (value);
+      g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-buffers",
+          vaapidecbin->max_size_buffers, NULL);
+      break;
+    case PROP_MAX_SIZE_TIME:
+      vaapidecbin->max_size_time = g_value_get_uint64 (value);
+      g_object_set (G_OBJECT (vaapidecbin->queue), "max-size-time",
+          vaapidecbin->max_size_time, NULL);
+      break;
+    case PROP_DEINTERLACE_METHOD:
+      vaapidecbin->deinterlace_method = g_value_get_enum (value);
+      if (vaapidecbin->postproc)
+        g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method",
+            vaapidecbin->deinterlace_method, NULL);
+      break;
+    case PROP_DISABLE_VPP:
+      /* @TODO: Add run-time disabling support */
+      vaapidecbin->disable_vpp = g_value_get_boolean (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_decode_bin_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (object);
+
+  switch (prop_id) {
+    case PROP_MAX_SIZE_BYTES:
+      g_value_set_uint (value, vaapidecbin->max_size_bytes);
+      break;
+    case PROP_MAX_SIZE_BUFFERS:
+      g_value_set_uint (value, vaapidecbin->max_size_buffers);
+      break;
+    case PROP_MAX_SIZE_TIME:
+      g_value_set_uint64 (value, vaapidecbin->max_size_time);
+      break;
+    case PROP_DEINTERLACE_METHOD:
+      g_value_set_enum (value, vaapidecbin->deinterlace_method);
+      break;
+    case PROP_DISABLE_VPP:
+      g_value_set_boolean (value, vaapidecbin->disable_vpp);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstStateChangeReturn
+gst_vaapi_decode_bin_change_state (GstElement * element,
+    GstStateChange transition)
+{
+  GstVaapiDecodeBin *vaapidecbin = GST_VAAPI_DECODE_BIN (element);
+  GstStateChangeReturn ret;
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (gst_vaapi_decode_bin_parent_class)->change_state
+      (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (!gst_vaapi_decode_bin_configure (vaapidecbin))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_vaapi_decode_bin_class_init (GstVaapiDecodeBinClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *element_class;
+
+  gobject_class = G_OBJECT_CLASS (klass);
+  element_class = GST_ELEMENT_CLASS (klass);
+
+  gobject_class->set_property = gst_vaapi_decode_bin_set_property;
+  gobject_class->get_property = gst_vaapi_decode_bin_get_property;
+
+  element_class->change_state = gst_vaapi_decode_bin_change_state;
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API Decode Bin",
+      "Codec/Decoder/Video/Hardware",
+      GST_PLUGIN_DESC,
+      "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
+      "Victor Jaquez <victorx.jaquez@intel.com>");
+
+  properties[PROP_MAX_SIZE_BYTES] = g_param_spec_uint ("max-size-bytes",
+      "Max. size (kB)", "Max. amount of data in the queue (bytes, 0=disable)",
+      0, G_MAXUINT, DEFAULT_QUEUE_MAX_SIZE_BYTES,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  properties[PROP_MAX_SIZE_BUFFERS] = g_param_spec_uint ("max-size-buffers",
+      "Max. size (buffers)", "Max. number of buffers in the queue (0=disable)",
+      0, G_MAXUINT, DEFAULT_QUEUE_MAX_SIZE_BUFFERS,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  properties[PROP_MAX_SIZE_TIME] = g_param_spec_uint64 ("max-size-time",
+      "Max. size (ns)", "Max. amount of data in the queue (in ns, 0=disable)",
+      0, G_MAXUINT64, DEFAULT_QUEUE_MAX_SIZE_TIME,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  properties[PROP_DEINTERLACE_METHOD] = g_param_spec_enum ("deinterlace-method",
+      "Deinterlace method", "Deinterlace method to use",
+      GST_VAAPI_TYPE_DEINTERLACE_METHOD, DEFAULT_DEINTERLACE_METHOD,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+  properties[PROP_DISABLE_VPP] = g_param_spec_boolean ("disable-vpp",
+      "Disable VPP",
+      "Disable Video Post Processing (No support for run time disabling)",
+      FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  g_object_class_install_properties (gobject_class, PROP_LAST, properties);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vaapi_decode_bin_sink_factory);
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vaapi_decode_bin_src_factory);
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_decode_bin,
+      GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
+}
+
+static gboolean
+gst_vaapi_decode_bin_configure (GstVaapiDecodeBin * vaapidecbin)
+{
+  GstElement *capsfilter;
+  GstCaps *caps;
+  GstPad *queue_srcpad, *bin_srcpad, *capsfilter_sinkpad, *vpp_srcpad;
+  gboolean res;
+  gboolean has_vpp;
+
+  g_object_set (G_OBJECT (vaapidecbin->queue),
+      "max-size-bytes", vaapidecbin->max_size_bytes,
+      "max-size-buffers", vaapidecbin->max_size_buffers,
+      "max-size-time", vaapidecbin->max_size_time, NULL);
+
+  if (vaapidecbin->disable_vpp || vaapidecbin->configured)
+    return TRUE;
+
+  has_vpp = _gst_vaapi_has_video_processing;
+
+  if (!has_vpp && (vaapidecbin->deinterlace_method ==
+          GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE
+          || vaapidecbin->deinterlace_method ==
+          GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED)) {
+    GST_ERROR_OBJECT (vaapidecbin,
+        "Don't have VPP support but advanced deinterlacing selected");
+    return FALSE;
+  }
+
+  if (!has_vpp)
+    return TRUE;
+
+  GST_INFO_OBJECT (vaapidecbin, "enabling VPP");
+
+  /* capsfilter to force memory:VASurface */
+  caps = gst_caps_from_string ("video/x-raw(memory:VASurface)");
+  if (!caps)
+    goto error_cannot_set_caps;
+  capsfilter = gst_element_factory_make ("capsfilter", NULL);
+  g_object_set (capsfilter, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  /* create the postproc */
+  vaapidecbin->postproc = gst_element_factory_make ("vaapipostproc", NULL);
+  if (!vaapidecbin->postproc)
+    goto error_vpp_missing;
+  g_object_set (G_OBJECT (vaapidecbin->postproc), "deinterlace-method",
+      vaapidecbin->deinterlace_method, NULL);
+
+  gst_bin_add_many (GST_BIN (vaapidecbin), capsfilter, vaapidecbin->postproc,
+      NULL);
+
+  if (!gst_element_link (capsfilter, vaapidecbin->postproc))
+    goto error_sync_state;
+  if (!gst_element_sync_state_with_parent (capsfilter))
+    goto error_sync_state;
+  if (!gst_element_sync_state_with_parent (vaapidecbin->postproc))
+    goto error_sync_state;
+
+  /* break source ghost pad target */
+  bin_srcpad =
+      gst_element_get_static_pad (GST_ELEMENT_CAST (vaapidecbin), "src");
+  if (!gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), NULL))
+    goto error_link_pad;
+
+  /* link decoder and queue */
+  queue_srcpad = gst_element_get_static_pad (vaapidecbin->queue, "src");
+  capsfilter_sinkpad = gst_element_get_static_pad (capsfilter, "sink");
+  res = (gst_pad_link (queue_srcpad, capsfilter_sinkpad) == GST_PAD_LINK_OK);
+  gst_object_unref (capsfilter_sinkpad);
+  gst_object_unref (queue_srcpad);
+  if (!res)
+    goto error_link_pad;
+
+  /* set vpp source pad as source ghost pad target */
+  vpp_srcpad = gst_element_get_static_pad (vaapidecbin->postproc, "src");
+  res = gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (bin_srcpad), vpp_srcpad);
+  gst_object_unref (vpp_srcpad);
+  if (!res)
+    goto error_link_pad;
+
+  gst_object_unref (bin_srcpad);
+  vaapidecbin->configured = TRUE;
+
+  return TRUE;
+
+  /* ERRORS */
+error_cannot_set_caps:
+  {
+    GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD,
+        ("Failed to configure caps for VA Surfaces."), (NULL));
+    return FALSE;
+  }
+error_vpp_missing:
+  {
+    GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD,
+        ("Failed to load vaapipostproc."), (NULL));
+    return FALSE;
+  }
+error_sync_state:
+  {
+    GST_ELEMENT_ERROR (vaapidecbin, CORE, STATE_CHANGE,
+        ("Failed to sync state of vaapipostproc."), (NULL));
+    return FALSE;
+  }
+error_link_pad:
+  {
+    gst_object_unref (bin_srcpad);
+    GST_ELEMENT_ERROR (vaapidecbin, CORE, PAD,
+        ("Failed to configure the vaapidecodebin."), (NULL));
+    return FALSE;
+  }
+}
+
+static void
+gst_vaapi_decode_bin_init (GstVaapiDecodeBin * vaapidecbin)
+{
+  GstPad *pad, *ghostpad;
+
+  vaapidecbin->max_size_bytes = DEFAULT_QUEUE_MAX_SIZE_BYTES;
+  vaapidecbin->max_size_buffers = DEFAULT_QUEUE_MAX_SIZE_BUFFERS;
+  vaapidecbin->max_size_time = DEFAULT_QUEUE_MAX_SIZE_TIME;
+  vaapidecbin->disable_vpp = (g_getenv ("GST_VAAPI_DISABLE_VPP") != NULL);
+
+  /* create the decoder */
+  vaapidecbin->decoder =
+      g_object_new (g_type_from_name ("GstVaapiDecode"), NULL);
+  g_assert (vaapidecbin->decoder);
+
+  /* create the queue */
+  vaapidecbin->queue = gst_element_factory_make ("queue", NULL);
+  g_assert (vaapidecbin->queue);
+
+  gst_bin_add_many (GST_BIN (vaapidecbin), vaapidecbin->decoder,
+      vaapidecbin->queue, NULL);
+
+  if (!gst_element_link (vaapidecbin->decoder, vaapidecbin->queue)) {
+    GST_WARNING_OBJECT (vaapidecbin, "Failed to link decoder and queue");
+    return;
+  }
+
+  /* create ghost pad sink */
+  pad = gst_element_get_static_pad (vaapidecbin->decoder, "sink");
+  if (!pad) {
+    GST_WARNING_OBJECT (vaapidecbin, "Failed to get decoder sink pad");
+    return;
+  }
+
+  ghostpad = gst_ghost_pad_new ("sink", pad);
+  gst_object_unref (pad);
+  if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad)) {
+    GST_WARNING_OBJECT (vaapidecbin, "Failed to add decoder sink pad to bin");
+    return;
+  }
+
+  /* create ghost pad src */
+  pad = gst_element_get_static_pad (GST_ELEMENT (vaapidecbin->queue), "src");
+  ghostpad = gst_ghost_pad_new_from_template ("src", pad,
+      GST_PAD_PAD_TEMPLATE (pad));
+  gst_object_unref (pad);
+  if (!gst_element_add_pad (GST_ELEMENT (vaapidecbin), ghostpad))
+    GST_WARNING_OBJECT (vaapidecbin, "Failed to add queue source pad to bin");
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecodebin.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecodebin.h
new file mode 100644 (file)
index 0000000..085a941
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *  gstvaapidecodebin.h
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_DECODE_BIN_H
+#define GST_VAAPI_DECODE_BIN_H
+
+#include <gst/vaapi/gstvaapifilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_DECODE_BIN (gst_vaapi_decode_bin_get_type ())
+#define GST_VAAPI_DECODE_BIN(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_DECODE_BIN, GstVaapiDecodeBin))
+#define GST_VAAPI_DECODE_BIN_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_DECODE_BIN, GstVaapiDecodeBinClass))
+#define GST_IS_AUTO_DETECT(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_DECODE_BIN))
+#define GST_IS_AUTO_DETECT_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_DECODE_BIN))
+#define GST_VAAPI_DECODE_BIN_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_DECODE_BIN, GstVaapiDecodeBinClass))
+
+typedef struct _GstVaapiDecodeBin {
+  /* < private > */
+  GstBin parent;
+
+  GstElement *decoder;
+  GstElement *queue;
+  GstElement *postproc;
+
+  /* properties */
+  guint   max_size_buffers;
+  guint   max_size_bytes;
+  guint64 max_size_time;
+  GstVaapiDeinterlaceMethod deinterlace_method;
+  gboolean disable_vpp;
+
+  gboolean configured;
+} GstVaapiDecodeBin;
+
+typedef struct _GstVaapiDecodeBinClass {
+  GstBinClass parent_class;
+
+} GstVaapiDecodeBinClass;
+
+GType   gst_vaapi_decode_bin_get_type    (void);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_DECODE_BIN_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecodedoc.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapidecodedoc.c
new file mode 100644 (file)
index 0000000..3deb2c4
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *  gstvaapidecodedoc.c - VA-API video decoders documentation
+ *
+ *  Copyright (C) 2016 Intel Corporation
+ *    Author: Victor Jaquez <victorx.jaquez@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapijpegdec
+ * @short_description: A VA-API based JPEG image decoder
+ *
+ * vaapijpegdec decodes a JPEG image to surfaces suitable for the
+ * vaapisink or vaapipostproc elements using the installed
+ * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end.
+ *
+ * In the case of OpenGL based elements, the buffers have the
+ * #GstVideoGLTextureUploadMeta meta, which efficiently copies the
+ * content of the VA-API surface into a GL texture.
+ *
+ * Also it can deliver normal video buffers that can be rendered or
+ * processed by other elements, but the performance would be rather
+ * bad.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 filesrc location=~/image.jpeg ! jpegparse ! vaapijpegdec ! imagefreeze ! vaapisink
+ * ]|
+ */
+
+/**
+ * SECTION:element-vaapimpeg2dec
+ * @short_description: A VA-API based MPEG2 video decoder
+ *
+ * vaapimpeg2dec decodes from MPEG2 bitstreams to surfaces suitable
+ * for the vaapisink or vaapipostproc elements using the installed
+ * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end.
+ *
+ * In the case of OpenGL based elements, the buffers have the
+ * #GstVideoGLTextureUploadMeta meta, which efficiently copies the
+ * content of the VA-API surface into a GL texture.
+ *
+ * Also it can deliver normal video buffers that can be rendered or
+ * processed by other elements, but the performance would be rather
+ * bad.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 filesrc location=~/sample.mpg ! mpegpsdemux ! vaapimpeg2dec ! vaapisink
+ * ]|
+ */
+
+/**
+ * SECTION:element-vaapimpeg4dec
+ * @short_description: A VA-API based MPEG4 video decoder
+ *
+ * vaapimpeg4dec decodes from MPEG4 bitstreams to surfaces suitable
+ * for the vaapisink or vaapipostproc elements using the installed
+ * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end.
+ *
+ * In the case of OpenGL based elements, the buffers have the
+ * #GstVideoGLTextureUploadMeta meta, which efficiently copies the
+ * content of the VA-API surface into a GL texture.
+ *
+ * Also it can deliver normal video buffers that can be rendered or
+ * processed by other elements, but the performance would be rather
+ * bad.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 filesrc location=~/sample.mpeg4 ! mpeg4videoparse ! vaapimpeg4dec ! vaapisink
+ * ]|
+ */
+
+/**
+ * SECTION:element-vaapih263dec
+ * @short_description: A VA-API based H263 video decoder
+ *
+ * vaapih263dec decodes from H263 bitstreams to surfaces suitable
+ * for the vaapisink or vaapipostproc elements using the installed
+ * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end.
+ *
+ * In the case of OpenGL based elements, the buffers have the
+ * #GstVideoGLTextureUploadMeta meta, which efficiently copies the
+ * content of the VA-API surface into a GL texture.
+ *
+ * Also it can deliver normal video buffers that can be rendered or
+ * processed by other elements, but the performance would be rather
+ * bad.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 filesrc location=~/sample.h263 ! h263parse ! vaapih263dec ! vaapisink
+ * ]|
+ */
+
+/**
+ * SECTION:element-vaapih264dec
+ * @short_description: A VA-API based H264 video decoder
+ *
+ * vaapih264dec decodes from H264 bitstreams to surfaces suitable
+ * for the vaapisink or vaapipostproc elements using the installed
+ * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end.
+ *
+ * In the case of OpenGL based elements, the buffers have the
+ * #GstVideoGLTextureUploadMeta meta, which efficiently copies the
+ * content of the VA-API surface into a GL texture.
+ *
+ * Also it can deliver normal video buffers that can be rendered or
+ * processed by other elements, but the performance would be rather
+ * bad.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 filesrc location=~/big_buck_bunny.mov ! qtdemux ! h264parse ! vaapih264dec ! vaapisink
+ * ]|
+ */
+
+/**
+ * SECTION:element-vaapih265dec
+ * @short_description: A VA-API based H265 video decoder
+ *
+ * vaapih265dec decodes from H265 bitstreams to surfaces suitable
+ * for the vaapisink or vaapipostproc elements using the installed
+ * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end.
+ *
+ * In the case of OpenGL based elements, the buffers have the
+ * #GstVideoGLTextureUploadMeta meta, which efficiently copies the
+ * content of the VA-API surface into a GL texture.
+ *
+ * Also it can deliver normal video buffers that can be rendered or
+ * processed by other elements, but the performance would be rather
+ * bad.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 filesrc location=./sample.bin ! h265parse ! vaapih265dec ! vaapisink
+ * ]|
+ */
+
+/**
+ * SECTION:element-vaapivc1dec
+ * @short_description: A VA-API based VC1 video decoder
+ *
+ * vaapivc1dec decodes from VC1 bitstreams to surfaces suitable
+ * for the vaapisink or vaapipostproc elements using the installed
+ * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end.
+ *
+ * In the case of OpenGL based elements, the buffers have the
+ * #GstVideoGLTextureUploadMeta meta, which efficiently copies the
+ * content of the VA-API surface into a GL texture.
+ *
+ * Also it can deliver normal video buffers that can be rendered or
+ * processed by other elements, but the performance would be rather
+ * bad.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 filesrc location=~/elephants_dream.wmv  ! asfdemux ! vaapivc1dec ! vaapisink
+ * ]|
+ */
+
+/**
+ * SECTION:element-vaapivp8dec
+ * @short_description: A VA-API based VP8 video decoder
+ *
+ * vaapivp8dec decodes from VP8 bitstreams to surfaces suitable
+ * for the vaapisink or vaapipostproc elements using the installed
+ * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end.
+ *
+ * In the case of OpenGL based elements, the buffers have the
+ * #GstVideoGLTextureUploadMeta meta, which efficiently copies the
+ * content of the VA-API surface into a GL texture.
+ *
+ * Also it can deliver normal video buffers that can be rendered or
+ * processed by other elements, but the performance would be rather
+ * bad.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 filesrc location=./sample.webm ! matroskademux ! vaapivp8dec ! vaapisink
+ * ]|
+ */
+
+/**
+ * SECTION:element-vaapivp9dec
+ * @short_description: A VA-API based VP9 video decoder
+ *
+ * vaapivp9dec decodes from VP9 bitstreams to surfaces suitable
+ * for the vaapisink or vaapipostproc elements using the installed
+ * [VA-API](https://wiki.freedesktop.org/www/Software/vaapi/) back-end.
+ *
+ * In the case of OpenGL based elements, the buffers have the
+ * #GstVideoGLTextureUploadMeta meta, which efficiently copies the
+ * content of the VA-API surface into a GL texture.
+ *
+ * Also it can deliver normal video buffers that can be rendered or
+ * processed by other elements, but the performance would be rather
+ * bad.
+ *
+ * ## Example launch line
+ * |[
+ * gst-launch-1.0 filesrc location=./sample.vp9.webm ! ivfparse ! vaapivp9dec ! vaapisink
+ * ]|
+ */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode.c
new file mode 100644 (file)
index 0000000..e86d55b
--- /dev/null
@@ -0,0 +1,1044 @@
+/*
+ *  gstvaapiencode.c - VA-API video encoder
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapivalue.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiprofilecaps.h>
+#include "gstvaapiencode.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideometa.h"
+#include "gstvaapivideomemory.h"
+#include "gstvaapivideobufferpool.h"
+
+#define GST_PLUGIN_NAME "vaapiencode"
+#define GST_PLUGIN_DESC "A VA-API based video encoder"
+
+#define GST_VAAPI_ENCODE_FLOW_TIMEOUT           GST_FLOW_CUSTOM_SUCCESS
+#define GST_VAAPI_ENCODE_FLOW_MEM_ERROR         GST_FLOW_CUSTOM_ERROR
+#define GST_VAAPI_ENCODE_FLOW_CONVERT_ERROR     GST_FLOW_CUSTOM_ERROR_1
+
+GST_DEBUG_CATEGORY_STATIC (gst_vaapiencode_debug);
+#ifndef GST_DISABLE_GST_DEBUG
+#define GST_CAT_DEFAULT gst_vaapiencode_debug
+#else
+#define GST_CAT_DEFAULT NULL
+#endif
+
+G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GstVaapiEncode,
+    gst_vaapiencode, GST_TYPE_VIDEO_ENCODER,
+    GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES);
+
+GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (gst_vaapiencode_parent_class);
+
+enum
+{
+  PROP_0,
+
+  PROP_BASE,
+};
+
+static inline gboolean
+ensure_display (GstVaapiEncode * encode)
+{
+  return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (encode));
+}
+
+static gboolean
+gst_vaapiencode_sink_query (GstVideoEncoder * encoder, GstQuery * query)
+{
+  gboolean ret = TRUE;
+  GstElement *const element = GST_ELEMENT (encoder);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONTEXT:
+      ret = gst_vaapi_handle_context_query (element, query);
+      break;
+    default:
+      ret = GST_VIDEO_ENCODER_CLASS (gst_vaapiencode_parent_class)->sink_query
+          (encoder, query);
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_vaapiencode_src_query (GstVideoEncoder * encoder, GstQuery * query)
+{
+  gboolean ret = TRUE;
+  GstElement *const element = GST_ELEMENT (encoder);
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONTEXT:
+      ret = gst_vaapi_handle_context_query (element, query);
+      break;
+    default:
+      ret = GST_VIDEO_ENCODER_CLASS (gst_vaapiencode_parent_class)->src_query
+          (encoder, query);
+      break;
+  }
+
+  return ret;
+}
+
+typedef struct
+{
+  guint id;
+  GParamSpec *pspec;
+  GValue value;
+} PropValue;
+
+static void
+prop_value_free (PropValue * prop_value)
+{
+  if (!prop_value)
+    return;
+
+  if (G_VALUE_TYPE (&prop_value->value))
+    g_value_unset (&prop_value->value);
+
+  if (prop_value->pspec) {
+    g_param_spec_unref (prop_value->pspec);
+    prop_value->pspec = NULL;
+  }
+  g_slice_free (PropValue, prop_value);
+}
+
+static PropValue *
+prop_value_new_entry (guint id, GParamSpec * pspec, const GValue * value)
+{
+  PropValue *prop_value;
+
+  if (!pspec)
+    return NULL;
+
+  prop_value = g_slice_new0 (PropValue);
+  if (!prop_value)
+    return NULL;
+
+  prop_value->id = id;
+  prop_value->pspec = g_param_spec_ref (pspec);
+  g_value_init (&prop_value->value, pspec->value_type);
+
+  g_assert (g_value_type_compatible (pspec->value_type, G_VALUE_TYPE (value)));
+  g_value_copy (value, &prop_value->value);
+
+  return prop_value;
+}
+
+static inline PropValue *
+prop_value_lookup_entry (GPtrArray * prop_values, guint prop_id)
+{
+  guint i;
+  PropValue *prop_value;
+
+  if (prop_values == NULL)
+    return NULL;
+
+  for (i = 0; i < prop_values->len; i++) {
+    prop_value = g_ptr_array_index (prop_values, i);
+    if (prop_value->id == prop_id)
+      return prop_value;
+  }
+
+  return NULL;
+}
+
+static GstFlowReturn
+gst_vaapiencode_default_alloc_buffer (GstVaapiEncode * encode,
+    GstVaapiCodedBuffer * coded_buf, GstBuffer ** outbuf_ptr)
+{
+  GstBuffer *buf;
+  gint32 buf_size;
+
+  g_return_val_if_fail (coded_buf != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR);
+
+  buf_size = gst_vaapi_coded_buffer_get_size (coded_buf);
+  if (buf_size <= 0)
+    goto error_invalid_buffer;
+
+  buf =
+      gst_video_encoder_allocate_output_buffer (GST_VIDEO_ENCODER_CAST (encode),
+      buf_size);
+  if (!buf)
+    goto error_create_buffer;
+  if (!gst_vaapi_coded_buffer_copy_into (buf, coded_buf))
+    goto error_copy_buffer;
+
+  *outbuf_ptr = buf;
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_invalid_buffer:
+  {
+    GST_ERROR ("invalid GstVaapiCodedBuffer size (%d bytes)", buf_size);
+    return GST_VAAPI_ENCODE_FLOW_MEM_ERROR;
+  }
+error_create_buffer:
+  {
+    GST_ERROR ("failed to create output buffer of size %d", buf_size);
+    return GST_VAAPI_ENCODE_FLOW_MEM_ERROR;
+  }
+error_copy_buffer:
+  {
+    GST_ERROR ("failed to copy GstVaapiCodedBuffer data");
+    gst_buffer_unref (buf);
+    return GST_VAAPI_ENCODE_FLOW_MEM_ERROR;
+  }
+}
+
+static gboolean
+ensure_output_state (GstVaapiEncode * encode)
+{
+  GstVideoEncoder *const venc = GST_VIDEO_ENCODER_CAST (encode);
+  GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode);
+  GstVaapiEncoderStatus status;
+  GstCaps *out_caps;
+
+  if (!encode->input_state_changed)
+    return TRUE;
+
+  out_caps = klass->get_caps (encode);
+  if (!out_caps)
+    return FALSE;
+
+  if (encode->output_state)
+    gst_video_codec_state_unref (encode->output_state);
+  encode->output_state = gst_video_encoder_set_output_state (venc, out_caps,
+      encode->input_state);
+
+  if (encode->need_codec_data) {
+    status = gst_vaapi_encoder_get_codec_data (encode->encoder,
+        &encode->output_state->codec_data);
+    if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+      return FALSE;
+  }
+
+  if (!gst_video_encoder_negotiate (venc))
+    return FALSE;
+
+  encode->input_state_changed = FALSE;
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_vaapiencode_push_frame (GstVaapiEncode * encode, gint64 timeout)
+{
+  GstVideoEncoder *const venc = GST_VIDEO_ENCODER_CAST (encode);
+  GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode);
+  GstVideoCodecFrame *out_frame;
+  GstVaapiCodedBufferProxy *codedbuf_proxy = NULL;
+  GstVaapiEncoderStatus status;
+  GstBuffer *out_buffer;
+  GstFlowReturn ret;
+
+  status = gst_vaapi_encoder_get_buffer_with_timeout (encode->encoder,
+      &codedbuf_proxy, timeout);
+  if (status == GST_VAAPI_ENCODER_STATUS_NO_BUFFER)
+    return GST_VAAPI_ENCODE_FLOW_TIMEOUT;
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    goto error_get_buffer;
+
+  out_frame = gst_vaapi_coded_buffer_proxy_get_user_data (codedbuf_proxy);
+  if (!out_frame)
+    goto error_get_buffer;
+  gst_video_codec_frame_ref (out_frame);
+  gst_video_codec_frame_set_user_data (out_frame, NULL, NULL);
+
+  /* Update output state */
+  GST_VIDEO_ENCODER_STREAM_LOCK (encode);
+  if (!ensure_output_state (encode))
+    goto error_output_state;
+  GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+
+  /* Allocate and copy buffer into system memory */
+  out_buffer = NULL;
+  ret = klass->alloc_buffer (encode,
+      GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (codedbuf_proxy), &out_buffer);
+
+  gst_vaapi_coded_buffer_proxy_replace (&codedbuf_proxy, NULL);
+  if (ret != GST_FLOW_OK)
+    goto error_allocate_buffer;
+
+  gst_buffer_replace (&out_frame->output_buffer, out_buffer);
+  gst_buffer_unref (out_buffer);
+
+  GST_TRACE_OBJECT (encode, "output:%" GST_TIME_FORMAT ", size:%zu",
+      GST_TIME_ARGS (out_frame->pts), gst_buffer_get_size (out_buffer));
+
+  return gst_video_encoder_finish_frame (venc, out_frame);
+
+  /* ERRORS */
+error_get_buffer:
+  {
+    GST_ERROR ("failed to get encoded buffer (status %d)", status);
+    if (codedbuf_proxy)
+      gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy);
+    return GST_FLOW_ERROR;
+  }
+error_allocate_buffer:
+  {
+    GST_ERROR ("failed to allocate encoded buffer in system memory");
+    if (out_buffer)
+      gst_buffer_unref (out_buffer);
+    gst_video_codec_frame_unref (out_frame);
+    return ret;
+  }
+error_output_state:
+  {
+    GST_ERROR ("failed to negotiate output state (status %d)", status);
+    GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+    gst_video_codec_frame_unref (out_frame);
+    return GST_FLOW_NOT_NEGOTIATED;
+  }
+}
+
+static void
+gst_vaapiencode_buffer_loop (GstVaapiEncode * encode)
+{
+  GstFlowReturn ret;
+  const gint64 timeout = 50000; /* microseconds */
+
+  ret = gst_vaapiencode_push_frame (encode, timeout);
+  if (ret == GST_FLOW_OK || ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT)
+    return;
+
+  GST_LOG_OBJECT (encode, "pausing task, reason %s", gst_flow_get_name (ret));
+  gst_pad_pause_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
+}
+
+static GArray *
+get_profiles (GstVaapiEncode * encode)
+{
+  GstVaapiEncodeClass *klass = GST_VAAPIENCODE_GET_CLASS (encode);
+  GArray *profiles = NULL;
+
+  if (klass->get_allowed_profiles) {
+    GstCaps *allowed =
+        gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
+    GST_LOG_OBJECT (encode,
+        "Get allowed sink caps from downstream %" GST_PTR_FORMAT, allowed);
+    if (allowed && !gst_caps_is_empty (allowed) && !gst_caps_is_any (allowed))
+      profiles = klass->get_allowed_profiles (encode, allowed);
+
+    if (allowed)
+      gst_caps_unref (allowed);
+
+    if (profiles)
+      return profiles;
+  }
+
+  profiles = gst_vaapi_encoder_get_available_profiles (encode->encoder);
+  return profiles;
+}
+
+static gboolean
+ensure_allowed_sinkpad_caps (GstVaapiEncode * encode)
+{
+  GstCaps *out_caps = NULL;
+  GArray *formats = NULL;
+  gboolean ret = FALSE;
+  GArray *profiles = NULL;
+  gint min_width, min_height, max_width, max_height;
+  guint mem_types;
+
+  if (encode->allowed_sinkpad_caps)
+    return TRUE;
+  if (!encode->encoder)
+    return TRUE;
+
+  /* First, get all possible profiles. */
+  profiles = get_profiles (encode);
+  if (profiles == NULL)
+    goto failed_get_profiles;
+
+  /* Then get all supported formats, all these formats should be recognized
+     in video-format map. */
+  formats = gst_vaapi_encoder_get_surface_attributes (encode->encoder, profiles,
+      &min_width, &min_height, &max_width, &max_height, &mem_types);
+  if (!formats)
+    goto failed_get_attributes;
+
+  out_caps = gst_vaapi_build_caps_from_formats (formats, min_width, min_height,
+      max_width, max_height, mem_types);
+  if (!out_caps)
+    goto failed_create_caps;
+
+  gst_caps_replace (&encode->allowed_sinkpad_caps, out_caps);
+  GST_INFO_OBJECT (encode, "Allowed sink caps %" GST_PTR_FORMAT,
+      encode->allowed_sinkpad_caps);
+
+  ret = TRUE;
+
+bail:
+  if (!encode->allowed_sinkpad_caps)
+    encode->allowed_sinkpad_caps = gst_caps_new_empty ();
+
+  if (profiles)
+    g_array_unref (profiles);
+  if (out_caps)
+    gst_caps_unref (out_caps);
+  if (formats)
+    g_array_unref (formats);
+  return ret;
+
+failed_get_attributes:
+  {
+    GST_WARNING_OBJECT (encode, "failed to get surface attributes");
+    goto bail;
+  }
+failed_create_caps:
+  {
+    GST_WARNING_OBJECT (encode, "failed to create sink caps");
+    goto bail;
+  }
+failed_get_profiles:
+  {
+    GST_WARNING_OBJECT (encode, "failed to get supported profiles");
+    goto bail;
+  }
+}
+
+static GstCaps *
+gst_vaapiencode_get_caps (GstVideoEncoder * venc, GstCaps * filter)
+{
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
+  GstCaps *result;
+
+  ensure_allowed_sinkpad_caps (encode);
+  result = gst_video_encoder_proxy_getcaps (venc, encode->allowed_sinkpad_caps,
+      filter);
+
+  GST_DEBUG_OBJECT (venc, "Negotiated sink caps %" GST_PTR_FORMAT, result);
+  return result;
+}
+
+static gboolean
+gst_vaapiencode_destroy (GstVaapiEncode * encode)
+{
+  if (encode->input_state) {
+    gst_video_codec_state_unref (encode->input_state);
+    encode->input_state = NULL;
+  }
+
+  if (encode->output_state) {
+    gst_video_codec_state_unref (encode->output_state);
+    encode->output_state = NULL;
+  }
+
+  gst_caps_replace (&encode->allowed_sinkpad_caps, NULL);
+  gst_vaapi_encoder_replace (&encode->encoder, NULL);
+  return TRUE;
+}
+
+static void
+gst_vaapiencode_purge (GstVaapiEncode * encode)
+{
+  GstVaapiCodedBufferProxy *codedbuf_proxy = NULL;
+  GstVaapiEncoderStatus status;
+  GstVideoCodecFrame *out_frame;
+
+  do {
+    status = gst_vaapi_encoder_get_buffer_with_timeout (encode->encoder,
+        &codedbuf_proxy, 0);
+    if (status == GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+      out_frame = gst_vaapi_coded_buffer_proxy_get_user_data (codedbuf_proxy);
+      if (out_frame)
+        gst_video_codec_frame_set_user_data (out_frame, NULL, NULL);
+
+      gst_vaapi_coded_buffer_proxy_unref (codedbuf_proxy);
+    }
+  } while (status == GST_VAAPI_ENCODER_STATUS_SUCCESS);
+}
+
+static gboolean
+ensure_encoder (GstVaapiEncode * encode)
+{
+  GstVaapiEncodeClass *klass = GST_VAAPIENCODE_GET_CLASS (encode);
+  guint i;
+
+  g_return_val_if_fail (klass->alloc_encoder, FALSE);
+
+  if (encode->encoder)
+    return FALSE;
+
+  encode->encoder = klass->alloc_encoder (encode,
+      GST_VAAPI_PLUGIN_BASE_DISPLAY (encode));
+  if (!encode->encoder)
+    return FALSE;
+
+  if (encode->prop_values && encode->prop_values->len) {
+    for (i = 0; i < encode->prop_values->len; i++) {
+      PropValue *const prop_value = g_ptr_array_index (encode->prop_values, i);
+      g_object_set_property ((GObject *) encode->encoder,
+          g_param_spec_get_name (prop_value->pspec), &prop_value->value);
+    }
+    /* clear alll the cache */
+    g_ptr_array_unref (encode->prop_values);
+    encode->prop_values = NULL;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapiencode_open (GstVideoEncoder * venc)
+{
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
+  GstVaapiDisplay *const old_display = GST_VAAPI_PLUGIN_BASE_DISPLAY (encode);
+  gboolean success;
+
+  if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (encode)))
+    return FALSE;
+
+  GST_VAAPI_PLUGIN_BASE_DISPLAY (encode) = NULL;
+  success = ensure_display (encode);
+  if (old_display)
+    gst_object_unref (old_display);
+  return success;
+}
+
+static gboolean
+gst_vaapiencode_start (GstVideoEncoder * venc)
+{
+  return ensure_encoder (GST_VAAPIENCODE_CAST (venc));
+}
+
+static gboolean
+gst_vaapiencode_stop (GstVideoEncoder * venc)
+{
+  return gst_vaapiencode_destroy (GST_VAAPIENCODE_CAST (venc));
+}
+
+static gboolean
+gst_vaapiencode_close (GstVideoEncoder * venc)
+{
+  gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (venc));
+  return TRUE;
+}
+
+static gboolean
+set_codec_state (GstVaapiEncode * encode, GstVideoCodecState * state)
+{
+  GstVaapiEncodeClass *const klass = GST_VAAPIENCODE_GET_CLASS (encode);
+  GstVaapiEncoderStatus status;
+
+  g_return_val_if_fail (encode->encoder, FALSE);
+
+  /* Initialize codec specific parameters */
+  if (klass->set_config && !klass->set_config (encode))
+    return FALSE;
+
+  status = gst_vaapi_encoder_set_codec_state (encode->encoder, state);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapiencode_set_format (GstVideoEncoder * venc, GstVideoCodecState * state)
+{
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
+  GstVaapiEncoderStatus status;
+
+  g_return_val_if_fail (state->caps != NULL, FALSE);
+
+  if (!set_codec_state (encode, state))
+    return FALSE;
+
+  if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (encode),
+          state->caps, NULL))
+    return FALSE;
+
+  GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+  status = gst_vaapi_encoder_flush (encode->encoder);
+  GST_VIDEO_ENCODER_STREAM_LOCK (encode);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return FALSE;
+
+  gst_vaapiencode_purge (encode);
+
+  if (encode->input_state)
+    gst_video_codec_state_unref (encode->input_state);
+  encode->input_state = gst_video_codec_state_ref (state);
+  encode->input_state_changed = TRUE;
+
+  /* Store some tags */
+  {
+    GstTagList *tags = gst_tag_list_new_empty ();
+    const gchar *encoder, *codec;
+    guint bitrate = 0;
+
+    g_object_get (encode, "bitrate", &bitrate, NULL);
+    gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_NOMINAL_BITRATE,
+        bitrate, NULL);
+
+    if ((encoder =
+            gst_element_class_get_metadata (GST_ELEMENT_GET_CLASS (encode),
+                GST_ELEMENT_METADATA_LONGNAME)))
+      gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_ENCODER, encoder,
+          NULL);
+
+    if ((codec = gst_vaapi_codec_get_name
+            (gst_vaapi_get_codec_from_caps (state->caps))))
+      gst_tag_list_add (tags, GST_TAG_MERGE_REPLACE, GST_TAG_CODEC, codec,
+          NULL);
+
+    gst_video_encoder_merge_tags (venc, tags, GST_TAG_MERGE_REPLACE);
+    gst_tag_list_unref (tags);
+  }
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_vaapiencode_handle_frame (GstVideoEncoder * venc,
+    GstVideoCodecFrame * frame)
+{
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
+  GstPad *const srcpad = GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode);
+  GstVaapiEncoderStatus status;
+  GstVaapiVideoMeta *meta;
+  GstVaapiSurfaceProxy *proxy;
+  GstFlowReturn ret;
+  GstBuffer *buf;
+  GstTaskState task_state;
+
+  task_state = gst_pad_get_task_state (srcpad);
+  if (task_state == GST_TASK_STOPPED || task_state == GST_TASK_PAUSED)
+    if (!gst_pad_start_task (srcpad,
+            (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL))
+      goto error_task_failed;
+
+  buf = NULL;
+  ret = gst_vaapi_plugin_base_get_input_buffer (GST_VAAPI_PLUGIN_BASE (encode),
+      frame->input_buffer, &buf);
+  if (ret != GST_FLOW_OK)
+    goto error_buffer_invalid;
+
+  gst_buffer_replace (&frame->input_buffer, buf);
+  gst_buffer_unref (buf);
+
+  meta = gst_buffer_get_vaapi_video_meta (buf);
+  if (!meta)
+    goto error_buffer_no_meta;
+
+  proxy = gst_vaapi_video_meta_get_surface_proxy (meta);
+  if (!proxy)
+    goto error_buffer_no_surface_proxy;
+
+  gst_video_codec_frame_set_user_data (frame,
+      gst_vaapi_surface_proxy_ref (proxy),
+      (GDestroyNotify) gst_vaapi_surface_proxy_unref);
+
+  GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+  status = gst_vaapi_encoder_put_frame (encode->encoder, frame);
+  GST_VIDEO_ENCODER_STREAM_LOCK (encode);
+  if (status < GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    goto error_encode_frame;
+
+  gst_video_codec_frame_unref (frame);
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_task_failed:
+  {
+    GST_ELEMENT_ERROR (venc, RESOURCE, FAILED,
+        ("Failed to start encoding thread."), (NULL));
+    gst_video_codec_frame_unref (frame);
+    return GST_FLOW_ERROR;
+  }
+error_buffer_invalid:
+  {
+    if (buf)
+      gst_buffer_unref (buf);
+    gst_video_codec_frame_unref (frame);
+    return ret;
+  }
+error_buffer_no_meta:
+  {
+    GST_ERROR ("failed to get GstVaapiVideoMeta information");
+    gst_video_codec_frame_unref (frame);
+    return GST_FLOW_ERROR;
+  }
+error_buffer_no_surface_proxy:
+  {
+    GST_ERROR ("failed to get VA surface proxy");
+    gst_video_codec_frame_unref (frame);
+    return GST_FLOW_ERROR;
+  }
+error_encode_frame:
+  {
+    GST_ERROR ("failed to encode frame %d (status %d)",
+        frame->system_frame_number, status);
+    gst_video_codec_frame_unref (frame);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_vaapiencode_finish (GstVideoEncoder * venc)
+{
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
+  GstVaapiEncoderStatus status;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  /* Don't try to destroy encoder if none was created in the first place.
+     Return "not-negotiated" error since this means we did not even reach
+     GstVideoEncoder::set_format() state, where the encoder could have
+     been created */
+  if (!encode->encoder)
+    return GST_FLOW_NOT_NEGOTIATED;
+
+  GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+
+  status = gst_vaapi_encoder_flush (encode->encoder);
+
+  gst_pad_stop_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
+
+  GST_VIDEO_ENCODER_STREAM_LOCK (encode);
+
+  while (status == GST_VAAPI_ENCODER_STATUS_SUCCESS && ret == GST_FLOW_OK)
+    ret = gst_vaapiencode_push_frame (encode, 0);
+
+  if (ret == GST_VAAPI_ENCODE_FLOW_TIMEOUT)
+    ret = GST_FLOW_OK;
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_vaapiencode_change_state (GstElement * element, GstStateChange transition)
+{
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (element);
+  GstVaapiEncoderStatus status;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      gst_pad_stop_task (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
+
+      status = gst_vaapi_encoder_flush (encode->encoder);
+      if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+        goto flush_error;
+
+      GST_VIDEO_ENCODER_STREAM_LOCK (encode);
+      gst_vaapiencode_purge (encode);
+      GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+      break;
+    default:
+      break;
+  }
+  return
+      GST_ELEMENT_CLASS (gst_vaapiencode_parent_class)->change_state (element,
+      transition);
+
+flush_error:
+  {
+    GST_ERROR ("failed to flush pending encoded frames");
+    return GST_STATE_CHANGE_FAILURE;
+  }
+}
+
+static gboolean
+gst_vaapiencode_propose_allocation (GstVideoEncoder * venc, GstQuery * query)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (venc);
+
+  if (!gst_vaapi_plugin_base_propose_allocation (plugin, query))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapiencode_sink_event (GstVideoEncoder * venc, GstEvent * event)
+{
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
+  GstPad *const srcpad = GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode);
+  gboolean ret;
+
+  ret = GST_VIDEO_ENCODER_CLASS (gst_vaapiencode_parent_class)->sink_event
+      (venc, event);
+  if (!ret)
+    return FALSE;
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_FLUSH_START:
+      gst_pad_pause_task (srcpad);
+      break;
+    case GST_EVENT_FLUSH_STOP:
+      ret = gst_pad_start_task (srcpad,
+          (GstTaskFunction) gst_vaapiencode_buffer_loop, encode, NULL);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static gboolean
+gst_vaapiencode_flush (GstVideoEncoder * venc)
+{
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (venc);
+  GstVaapiEncoderStatus status;
+
+  if (!encode->encoder)
+    return FALSE;
+
+  GST_LOG_OBJECT (encode, "flushing");
+
+  GST_VIDEO_ENCODER_STREAM_UNLOCK (encode);
+  status = gst_vaapi_encoder_flush (encode->encoder);
+  GST_VIDEO_ENCODER_STREAM_LOCK (encode);
+  if (status != GST_VAAPI_ENCODER_STATUS_SUCCESS)
+    return FALSE;
+
+  gst_vaapiencode_purge (encode);
+
+  gst_vaapi_encoder_replace (&encode->encoder, NULL);
+  if (!ensure_encoder (encode))
+    return FALSE;
+  if (!set_codec_state (encode, encode->input_state))
+    return FALSE;
+
+  return TRUE;
+}
+
+static void
+gst_vaapiencode_finalize (GObject * object)
+{
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (object);
+
+  gst_vaapiencode_destroy (encode);
+
+  if (encode->prop_values) {
+    g_ptr_array_unref (encode->prop_values);
+    encode->prop_values = NULL;
+  }
+
+  gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object));
+  G_OBJECT_CLASS (gst_vaapiencode_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapiencode_init (GstVaapiEncode * encode)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (encode);
+
+  gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (encode), GST_CAT_DEFAULT);
+  gst_pad_use_fixed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (plugin));
+}
+
+static void
+gst_vaapiencode_class_init (GstVaapiEncodeClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstVideoEncoderClass *const venc_class = GST_VIDEO_ENCODER_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_vaapiencode_debug,
+      GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
+
+  gst_vaapi_plugin_base_class_init (GST_VAAPI_PLUGIN_BASE_CLASS (klass));
+
+  object_class->finalize = gst_vaapiencode_finalize;
+
+  element_class->set_context = gst_vaapi_base_set_context;
+  element_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_vaapiencode_change_state);
+
+  venc_class->open = GST_DEBUG_FUNCPTR (gst_vaapiencode_open);
+  venc_class->close = GST_DEBUG_FUNCPTR (gst_vaapiencode_close);
+  venc_class->start = GST_DEBUG_FUNCPTR (gst_vaapiencode_start);
+  venc_class->stop = GST_DEBUG_FUNCPTR (gst_vaapiencode_stop);
+  venc_class->set_format = GST_DEBUG_FUNCPTR (gst_vaapiencode_set_format);
+  venc_class->handle_frame = GST_DEBUG_FUNCPTR (gst_vaapiencode_handle_frame);
+  venc_class->finish = GST_DEBUG_FUNCPTR (gst_vaapiencode_finish);
+  venc_class->getcaps = GST_DEBUG_FUNCPTR (gst_vaapiencode_get_caps);
+  venc_class->propose_allocation =
+      GST_DEBUG_FUNCPTR (gst_vaapiencode_propose_allocation);
+  venc_class->flush = GST_DEBUG_FUNCPTR (gst_vaapiencode_flush);
+  venc_class->sink_event = GST_DEBUG_FUNCPTR (gst_vaapiencode_sink_event);
+
+  klass->alloc_buffer = gst_vaapiencode_default_alloc_buffer;
+
+  venc_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapiencode_src_query);
+  venc_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapiencode_sink_query);
+
+  gst_type_mark_as_plugin_api (GST_TYPE_VAAPIENCODE, 0);
+}
+
+/* Only used by the drived class */
+void
+gst_vaapiencode_set_property_subclass (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_GET_CLASS (object);
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (object);
+  PropValue *prop_value;
+
+  if (prop_id <= PROP_BASE || prop_id >= encode_class->prop_num) {
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    return;
+  }
+
+  /* direct forward the property to encoder */
+  if (encode->encoder) {
+    g_object_set_property ((GObject *) encode->encoder,
+        g_param_spec_get_name (pspec), value);
+    return;
+  }
+
+  if (encode->prop_values) {
+    /* Delete the same prop already in cache */
+    prop_value = prop_value_lookup_entry (encode->prop_values, prop_id);
+    if (prop_value)
+      g_ptr_array_remove (encode->prop_values, prop_value);
+  } else {
+    encode->prop_values =
+        g_ptr_array_new_with_free_func ((GDestroyNotify) prop_value_free);
+  }
+
+  /* The encoder is delay created, we need to cache the property setting */
+  prop_value = prop_value_new_entry (prop_id, pspec, value);
+  g_ptr_array_add (encode->prop_values, prop_value);
+}
+
+/* Only used by the drived class */
+void
+gst_vaapiencode_get_property_subclass (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_GET_CLASS (object);
+  GstVaapiEncode *const encode = GST_VAAPIENCODE_CAST (object);
+  PropValue *prop_value = NULL;
+
+  if (prop_id <= PROP_BASE || prop_id >= encode_class->prop_num) {
+    G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+    return;
+  }
+
+  /* direct forward the property to encoder */
+  if (encode->encoder) {
+    g_object_get_property ((GObject *) encode->encoder,
+        g_param_spec_get_name (pspec), value);
+    return;
+  }
+
+  if (encode->prop_values)
+    prop_value = prop_value_lookup_entry (encode->prop_values, prop_id);
+
+  if (prop_value) {
+    /* In the cache */
+    g_value_copy (&prop_value->value, value);
+  } else {
+    /* set the default value */
+    g_param_value_set_default (pspec, value);
+  }
+}
+
+/* Called by drived class to install all properties. The encode base class
+   does not have any property, all the properties of the according encoderXXX
+   class are installed to encodeXXX class. */
+gboolean
+gst_vaapiencode_class_install_properties (GstVaapiEncodeClass * klass,
+    GObjectClass * encoder_class)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  guint i, n_props, installed;
+  GParamSpec **specs = NULL;
+  GParamSpec *pspec;
+  GParamSpec *new_spec;
+  GParamFlags flags;
+
+  if (encoder_class)
+    specs = g_object_class_list_properties (encoder_class, &n_props);
+  if (!specs)
+    return FALSE;
+
+  installed = 0;
+  for (i = 0; i < n_props; i++) {
+    pspec = specs[i];
+
+    /* Encoder do not want to expose */
+    if (!(pspec->flags & GST_VAAPI_PARAM_ENCODER_EXPOSURE))
+      continue;
+    /* Can only set on encoder init time */
+    if (pspec->flags & G_PARAM_CONSTRUCT_ONLY)
+      continue;
+
+    /* filter out the G_PARAM_CONSTRUCT, the encoder created later, no need
+       to set the init value in encode.
+       Also no GST_VAAPI_PARAM_ENCODER_EXPOSURE */
+    flags = pspec->flags & (~(GST_VAAPI_PARAM_ENCODER_EXPOSURE |
+            G_PARAM_CONSTRUCT));
+
+    if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_UINT) {
+      GParamSpecUInt *pspecuint = G_PARAM_SPEC_UINT (pspec);
+      new_spec = g_param_spec_uint (g_param_spec_get_name (pspec),
+          g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec),
+          pspecuint->minimum, pspecuint->maximum,
+          pspecuint->default_value, flags);
+    } else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT) {
+      GParamSpecInt *pspecint = G_PARAM_SPEC_INT (pspec);
+      new_spec = g_param_spec_int (g_param_spec_get_name (pspec),
+          g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec),
+          pspecint->minimum, pspecint->maximum, pspecint->default_value, flags);
+    } else if (G_IS_PARAM_SPEC_ENUM (pspec)) {
+      GParamSpecEnum *pspecenum = G_PARAM_SPEC_ENUM (pspec);
+      new_spec = g_param_spec_enum (g_param_spec_get_name (pspec),
+          g_param_spec_get_nick (pspec),
+          g_param_spec_get_blurb (pspec),
+          pspec->value_type, pspecenum->default_value, flags);
+    } else if (G_IS_PARAM_SPEC_BOOLEAN (pspec)) {
+      GParamSpecBoolean *pspecbool = G_PARAM_SPEC_BOOLEAN (pspec);
+      new_spec = g_param_spec_boolean (g_param_spec_get_name (pspec),
+          g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec),
+          pspecbool->default_value, flags);
+    } else if (G_IS_PARAM_SPEC_FLAGS (pspec)) {
+      GParamSpecFlags *pspecflags = G_PARAM_SPEC_FLAGS (pspec);
+      new_spec = g_param_spec_flags (g_param_spec_get_name (pspec),
+          g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec),
+          pspec->value_type, pspecflags->default_value, flags);
+    } else if (GST_IS_PARAM_SPEC_ARRAY_LIST (pspec)) {
+      GstParamSpecArray *pspecarray = GST_PARAM_SPEC_ARRAY_LIST (pspec);
+      new_spec = gst_param_spec_array (g_param_spec_get_name (pspec),
+          g_param_spec_get_nick (pspec), g_param_spec_get_blurb (pspec),
+          pspecarray->element_spec, flags);
+    } else {
+      GST_WARNING ("encoder's %s property has a unimplemented"
+          " type to expose to encode, the encode may lose the %s property",
+          g_param_spec_get_name (pspec), g_param_spec_get_name (pspec));
+      continue;
+    }
+
+    g_object_class_install_property (object_class, PROP_BASE + 1 + installed,
+        new_spec);
+    installed++;
+  }
+
+  g_free (specs);
+  klass->prop_num = PROP_BASE + 1 + installed;
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode.h
new file mode 100644 (file)
index 0000000..9c3fc1b
--- /dev/null
@@ -0,0 +1,217 @@
+/*
+ *  gstvaapiencode.h - VA-API video encoder
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIENCODE_H
+#define GST_VAAPIENCODE_H
+
+#include "gstvaapipluginbase.h"
+#include <gst/vaapi/gstvaapiencoder.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPIENCODE \
+  (gst_vaapiencode_get_type ())
+#define GST_VAAPIENCODE_CAST(obj) \
+  ((GstVaapiEncode *)(obj))
+#define GST_VAAPIENCODE(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE, GstVaapiEncode))
+#define GST_VAAPIENCODE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE, GstVaapiEncodeClass))
+#define GST_VAAPIENCODE_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE, GstVaapiEncodeClass))
+#define GST_IS_VAAPIENCODE(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE))
+#define GST_IS_VAAPIENCODE_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE))
+
+typedef struct _GstVaapiEncodeInitData GstVaapiEncodeInitData;
+struct _GstVaapiEncodeInitData
+{
+  GstCaps *sink_caps;
+  GstCaps *src_caps;
+};
+
+/* *INDENT-OFF* */
+#define GST_VAAPI_ENCODE_STATIC_SINK_CAPS                \
+  GST_VAAPI_MAKE_SURFACE_CAPS ", "                       \
+  GST_CAPS_INTERLACED_FALSE "; "                         \
+  GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL) ", "       \
+  GST_CAPS_INTERLACED_FALSE ";"                          \
+  GST_VIDEO_CAPS_MAKE_WITH_FEATURES(                     \
+      GST_CAPS_FEATURE_MEMORY_DMABUF,                    \
+      GST_VAAPI_FORMATS_ALL) ","                         \
+  GST_CAPS_INTERLACED_FALSE
+/* *INDENT-ON* */
+
+#define GST_VAAPI_ENCODE_REGISTER_TYPE(NAME, CODEC, CLASS, _EXT_FMT_, FUN) \
+  static GstVaapiEncodeInitData encode_init_data = { NULL, NULL };         \
+  static GType encode_type = G_TYPE_INVALID;                               \
+  static gpointer gst_vaapiencode_##NAME##_parent_class = NULL;            \
+  static void                                                              \
+  gst_vaapiencode_##NAME##_class_init (                                    \
+      GstVaapiEncode##CLASS##Class * klass, gpointer data);                \
+  static void gst_vaapiencode_##NAME##_class_intern_init (gpointer klass,  \
+      gpointer data)                                                       \
+  {                                                                        \
+    gst_vaapiencode_##NAME##_parent_class =                                \
+        g_type_class_peek_parent (klass);                                  \
+    gst_vaapiencode_##NAME##_class_init (klass, data);                     \
+  }                                                                        \
+  static void                                                              \
+  gst_vaapiencode_##NAME##_init (GstVaapiEncode##CLASS * encode);          \
+  GType                                                                    \
+  gst_vaapiencode_##NAME##_register_type (GstVaapiDisplay * display)       \
+  {                                                                        \
+    GstCaps *caps;                                                         \
+    guint i, n;                                                            \
+    GTypeInfo type_info = {                                                \
+      sizeof (GstVaapiEncodeClass),                                        \
+      NULL,                                                                \
+      NULL,                                                                \
+      (GClassInitFunc) gst_vaapiencode_##NAME##_class_intern_init,         \
+      NULL,                                                                \
+      NULL,                                                                \
+      sizeof (GstVaapiEncode##CLASS),                                      \
+      0,                                                                   \
+      (GInstanceInitFunc) gst_vaapiencode_##NAME##_init,                   \
+    };                                                                     \
+    GArray *extra_fmts = NULL;                                             \
+    GstVideoFormat ext_video_fmts[] = _EXT_FMT_;                           \
+                                                                           \
+    GST_DEBUG_CATEGORY_INIT (gst_vaapi_##NAME##_encode_debug,              \
+        GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);                              \
+                                                                           \
+    if ((n =  G_N_ELEMENTS (ext_video_fmts)))  {                           \
+      extra_fmts =                                                         \
+          g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat), n);    \
+      for (i = 0; i < n; i++)                                              \
+        g_array_append_val (extra_fmts, ext_video_fmts[i]);                \
+    }                                                                      \
+    caps = gst_vaapi_build_template_raw_caps_by_codec (display,            \
+        GST_VAAPI_CONTEXT_USAGE_ENCODE,                                    \
+        GST_VAAPI_CODEC_##CODEC, extra_fmts);                              \
+    g_clear_pointer (&extra_fmts, g_array_unref);                          \
+    if (!caps) {                                                           \
+      GST_ERROR ("failed to get sink caps for " #CODEC                     \
+          " encode, can not register");                                    \
+      return G_TYPE_INVALID;                                               \
+    }                                                                      \
+                                                                           \
+    for (i = 0; i < gst_caps_get_size (caps); i++) {                       \
+      GstStructure *structure = gst_caps_get_structure (caps, i);          \
+      if (!structure)                                                      \
+        continue;                                                          \
+      gst_structure_set (structure, "interlace-mode", G_TYPE_STRING,       \
+          "progressive", NULL);                                            \
+    }                                                                      \
+    GST_DEBUG (#CODEC" encode's sink caps %" GST_PTR_FORMAT, caps);        \
+                                                                           \
+    /* class data will be leaked if the element never gets instantiated */ \
+    GST_MINI_OBJECT_FLAG_SET (caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);   \
+    encode_init_data.sink_caps = caps;                                     \
+                                                                           \
+    caps = gst_vaapi_build_template_coded_caps_by_codec (display,          \
+        GST_VAAPI_CONTEXT_USAGE_ENCODE,                                    \
+        GST_VAAPI_CODEC_##CODEC, GST_CODEC_CAPS,                           \
+        FUN);                                                              \
+    if (!caps) {                                                           \
+      GST_ERROR ("failed to get src caps for " #CODEC                      \
+          " encode, can not register");                                    \
+      gst_caps_unref (encode_init_data.sink_caps);                         \
+      return G_TYPE_INVALID;                                               \
+    }                                                                      \
+    GST_DEBUG (#CODEC" encode's src caps %" GST_PTR_FORMAT, caps);         \
+    /* class data will be leaked if the element never gets instantiated */ \
+    GST_MINI_OBJECT_FLAG_SET (caps, GST_MINI_OBJECT_FLAG_MAY_BE_LEAKED);   \
+    encode_init_data.src_caps = caps;                                      \
+    type_info.class_data = &encode_init_data;                              \
+    encode_type = g_type_register_static (GST_TYPE_VAAPIENCODE,            \
+        "GstVaapiEncode"#CLASS, &type_info, 0);                            \
+                                                                           \
+    return encode_type;                                                    \
+  }                                                                        \
+                                                                           \
+  GType                                                                    \
+  gst_vaapiencode_##NAME##_get_type (void)                                 \
+  {                                                                        \
+    g_assert (encode_type != G_TYPE_INVALID);                              \
+    return encode_type;                                                    \
+  }
+
+typedef struct _GstVaapiEncode GstVaapiEncode;
+typedef struct _GstVaapiEncodeClass GstVaapiEncodeClass;
+
+struct _GstVaapiEncode
+{
+  /*< private >*/
+  GstVaapiPluginBase parent_instance;
+
+  GstVaapiEncoder *encoder;
+  GstVideoCodecState *input_state;
+  gboolean input_state_changed;
+  /* needs to be set by the subclass implementation */
+  gboolean need_codec_data;
+  GstVideoCodecState *output_state;
+  GPtrArray *prop_values;
+  GstCaps *allowed_sinkpad_caps;
+};
+
+struct _GstVaapiEncodeClass
+{
+  /*< private >*/
+  GstVaapiPluginBaseClass parent_class;
+
+  guint               prop_num;
+  gboolean            (*set_config)     (GstVaapiEncode * encode);
+  GstCaps *           (*get_caps)       (GstVaapiEncode * encode);
+  GstVaapiEncoder *   (*alloc_encoder)  (GstVaapiEncode * encode,
+                                         GstVaapiDisplay * display);
+  GstFlowReturn       (*alloc_buffer)   (GstVaapiEncode * encode,
+                                         GstVaapiCodedBuffer * coded_buf,
+                                         GstBuffer ** outbuf_ptr);
+  /* Get all possible profiles based on allowed caps */
+  GArray *            (*get_allowed_profiles)  (GstVaapiEncode * encode,
+                                                GstCaps * allowed);
+};
+
+GType
+gst_vaapiencode_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+void
+gst_vaapiencode_set_property_subclass (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+
+G_GNUC_INTERNAL
+void
+gst_vaapiencode_get_property_subclass (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapiencode_class_install_properties (GstVaapiEncodeClass * klass,
+    GObjectClass * encoder_class);
+
+G_END_DECLS
+
+#endif /* GST_VAAPIENCODE_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h264.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h264.c
new file mode 100644 (file)
index 0000000..d58faaf
--- /dev/null
@@ -0,0 +1,587 @@
+/*
+ *  gstvaapiencode_h264.c - VA-API H.264 encoder
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapih264enc
+ * @short_description: A VA-API based H.264 video encoder
+ *
+ * Encodes raw video streams into H.264 bitstreams.
+ *
+ * The #GstVaapiEncodeH264:rate-control property controls the type of
+ * encoding.  In case of Constant Bitrate Encoding (CBR), the
+ * #GstVaapiEncodeH264:bitrate will determine the quality of the
+ * encoding.  Alternatively, one may choose to perform Constant
+ * Quantizer or Variable Bitrate Encoding (VBR), in which case the
+ * #GstVaapiEncodeH264:bitrate is the maximum bitrate.
+ *
+ * The H264 profile that is eventually used depends on a few settings.
+ * If #GstVaapiEncodeH264:dct8x8 is enabled, then High profile is
+ * used.  Otherwise, if #GstVaapiEncodeH264:cabac entropy coding is
+ * enabled or #GstVaapiEncodeH264:max-bframes are allowed, then Main
+ * Profile is in effect. The element will alway go with the maximal
+ * profile available in the caps negotation and otherwise Baseline
+ * profile applies. But in some cases (e.g. hardware platforms) a more
+ * restrictedprofile/level may be necessary. The recommended way to
+ * set a profile is to set it in the downstream caps.
+ *
+ * You can also set parameters to adjust the latency of encoding:
+ * #GstVaapiEncodeH264:quality-level is a number between 1-7, in the
+ * case of the Intel VAAPI driver, where a lower value will produce a
+ * higher quality output but with more latency; meanwhile a hihg
+ * number will produce a lower quality output with less latency. Also
+ * you can set #GstVaapiEncodeH264:tune, if your backend supports it,
+ * for low-power mode or high compression.
+ *
+ * ## Example launch line
+ *
+ * |[
+ *  gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapih264enc ! h264parse ! mp4mux ! filesink location=test.mp4
+ * ]|
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiencoder_h264.h>
+#include <gst/vaapi/gstvaapiutils_h264.h>
+#include "gstvaapiencode_h264.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideomemory.h"
+
+#define GST_PLUGIN_NAME "vaapih264enc"
+#define GST_PLUGIN_DESC "A VA-API based H264 video encoder"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h264_encode_debug);
+#define GST_CAT_DEFAULT gst_vaapi_h264_encode_debug
+
+#define GST_CODEC_CAPS                              \
+  "video/x-h264, "                                  \
+  "stream-format = (string) { avc, byte-stream }, " \
+  "alignment = (string) au"
+
+#define EXTRA_FORMATS {}
+
+/* h264 encode */
+GST_VAAPI_ENCODE_REGISTER_TYPE (h264, H264, H264, EXTRA_FORMATS,
+    gst_vaapi_utils_h264_get_profile_string);
+
+static void
+gst_vaapiencode_h264_init (GstVaapiEncodeH264 * encode)
+{
+  /* nothing to do here */
+}
+
+static void
+gst_vaapiencode_h264_finalize (GObject * object)
+{
+  GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (object);
+
+  gst_caps_replace (&encode->available_caps, NULL);
+  G_OBJECT_CLASS (gst_vaapiencode_h264_parent_class)->finalize (object);
+}
+
+static GArray *
+gst_vaapiencode_h264_get_allowed_profiles (GstVaapiEncode * encode,
+    GstCaps * allowed)
+{
+  return gst_vaapi_encoder_get_profiles_from_caps (allowed,
+      gst_vaapi_utils_h264_get_profile_from_string);
+}
+
+typedef struct
+{
+  GstVaapiProfile best_profile;
+  guint best_score;
+} FindBestProfileData;
+
+static void
+find_best_profile_value (FindBestProfileData * data, const GValue * value)
+{
+  const gchar *str;
+  GstVaapiProfile profile;
+  guint score;
+
+  if (!value || !G_VALUE_HOLDS_STRING (value))
+    return;
+
+  str = g_value_get_string (value);
+  if (!str)
+    return;
+  profile = gst_vaapi_utils_h264_get_profile_from_string (str);
+  if (!profile)
+    return;
+  score = gst_vaapi_utils_h264_get_profile_score (profile);
+  if (score < data->best_score)
+    return;
+  data->best_profile = profile;
+  data->best_score = score;
+}
+
+static GstVaapiProfile
+find_best_profile (GstCaps * caps)
+{
+  FindBestProfileData data;
+  guint i, j, num_structures, num_values;
+
+  data.best_profile = GST_VAAPI_PROFILE_UNKNOWN;
+  data.best_score = 0;
+
+  num_structures = gst_caps_get_size (caps);
+  for (i = 0; i < num_structures; i++) {
+    GstStructure *const structure = gst_caps_get_structure (caps, i);
+    const GValue *const value = gst_structure_get_value (structure, "profile");
+
+    if (!value)
+      continue;
+    if (G_VALUE_HOLDS_STRING (value))
+      find_best_profile_value (&data, value);
+    else if (GST_VALUE_HOLDS_LIST (value)) {
+      num_values = gst_value_list_get_size (value);
+      for (j = 0; j < num_values; j++)
+        find_best_profile_value (&data, gst_value_list_get_value (value, j));
+    }
+  }
+  return data.best_profile;
+}
+
+static GstCaps *
+get_available_caps (GstVaapiEncodeH264 * encode)
+{
+  GstVaapiEncode *const base_encode = GST_VAAPIENCODE_CAST (encode);
+  GstVaapiEncoderH264 *const encoder =
+      GST_VAAPI_ENCODER_H264 (base_encode->encoder);
+  GstCaps *out_caps;
+  GArray *profiles;
+  GstVaapiProfile profile;
+  const gchar *profile_str;
+  GValue profile_v = G_VALUE_INIT;
+  GValue profile_list = G_VALUE_INIT;
+  guint i;
+
+  if (encode->available_caps)
+    return encode->available_caps;
+
+  g_value_init (&profile_list, GST_TYPE_LIST);
+  g_value_init (&profile_v, G_TYPE_STRING);
+
+  profiles =
+      gst_vaapi_display_get_encode_profiles
+      (GST_VAAPI_PLUGIN_BASE_DISPLAY (encode));
+  if (!profiles)
+    return NULL;
+
+  for (i = 0; i < profiles->len; i++) {
+    profile = g_array_index (profiles, GstVaapiProfile, i);
+    if (gst_vaapi_profile_get_codec (profile) != GST_VAAPI_CODEC_H264)
+      continue;
+    profile_str = gst_vaapi_profile_get_name (profile);
+    if (!profile_str)
+      continue;
+    g_value_set_string (&profile_v, profile_str);
+    gst_value_list_append_value (&profile_list, &profile_v);
+  }
+  g_array_unref (profiles);
+
+  out_caps = gst_caps_from_string (GST_CODEC_CAPS);
+  gst_caps_set_value (out_caps, "profile", &profile_list);
+  g_value_unset (&profile_list);
+  g_value_unset (&profile_v);
+
+  if (!gst_vaapi_encoder_h264_supports_avc (encoder)) {
+    GST_INFO_OBJECT (encode,
+        "avc requires packed header support, outputting byte-stream");
+    gst_caps_set_simple (out_caps, "stream-format", G_TYPE_STRING,
+        "byte-stream", NULL);
+  }
+
+  encode->available_caps = out_caps;
+
+  return encode->available_caps;
+}
+
+static gboolean
+gst_vaapiencode_h264_set_config (GstVaapiEncode * base_encode)
+{
+  GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base_encode);
+  GstVaapiEncoderH264 *const encoder =
+      GST_VAAPI_ENCODER_H264 (base_encode->encoder);
+  GstCaps *template_caps, *allowed_caps;
+  gboolean ret = TRUE;
+
+  template_caps =
+      gst_pad_get_pad_template_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
+  allowed_caps =
+      gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
+
+  if (allowed_caps == template_caps) {
+    GST_INFO_OBJECT (encode, "downstream has ANY caps, outputting byte-stream");
+    encode->is_avc = FALSE;
+    gst_caps_unref (allowed_caps);
+  } else if (!allowed_caps) {
+    GST_INFO_OBJECT (encode,
+        "downstream has NULL caps, outputting byte-stream");
+    encode->is_avc = FALSE;
+  } else if (gst_caps_is_empty (allowed_caps)) {
+    GST_INFO_OBJECT (encode, "downstream has EMPTY caps");
+    goto fail;
+  } else {
+    const char *stream_format = NULL;
+    GstStructure *structure;
+    GstVaapiProfile profile = GST_VAAPI_PROFILE_UNKNOWN;
+    GstCaps *available_caps;
+    GstCaps *profile_caps;
+
+    available_caps = get_available_caps (encode);
+    if (!available_caps)
+      goto fail;
+
+    if (!gst_caps_can_intersect (allowed_caps, available_caps)) {
+      GstCaps *tmp_caps;
+
+      GST_INFO_OBJECT (encode, "downstream may have requested an unsupported "
+          "profile. Encoder will try to output a compatible one");
+
+      /* Let's try the best profile in the allowed caps.
+       * The internal encoder will fail later if it can't handle it */
+      profile = find_best_profile (allowed_caps);
+      if (profile == GST_VAAPI_PROFILE_UNKNOWN)
+        goto fail;
+
+      /* if allwed caps request baseline (which is deprecated), the
+       * encoder will try with constrained baseline which is
+       * compatible. */
+      if (profile == GST_VAAPI_PROFILE_H264_BASELINE)
+        profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
+
+      tmp_caps = gst_caps_from_string (GST_CODEC_CAPS);
+      gst_caps_set_simple (tmp_caps, "profile", G_TYPE_STRING,
+          gst_vaapi_profile_get_name (profile), NULL);
+      if (!gst_vaapi_encoder_h264_supports_avc (encoder)) {
+        gst_caps_set_simple (tmp_caps, "stream-format", G_TYPE_STRING,
+            "byte-stream", NULL);
+      }
+
+      profile_caps = gst_caps_intersect (available_caps, tmp_caps);
+      gst_caps_unref (tmp_caps);
+      if (gst_caps_is_empty (profile_caps)) {
+        gst_caps_unref (profile_caps);
+        goto fail;
+      }
+    } else {
+      profile_caps = gst_caps_intersect (allowed_caps, available_caps);
+      profile = find_best_profile (profile_caps);
+    }
+
+    profile_caps = gst_caps_fixate (profile_caps);
+    structure = gst_caps_get_structure (profile_caps, 0);
+    stream_format = gst_structure_get_string (structure, "stream-format");
+    encode->is_avc = (g_strcmp0 (stream_format, "avc") == 0);
+
+    if (profile != GST_VAAPI_PROFILE_UNKNOWN) {
+      GST_INFO ("using %s profile as target decoder constraints",
+          gst_vaapi_utils_h264_get_profile_string (profile));
+      ret = gst_vaapi_encoder_h264_set_max_profile (encoder, profile);
+    } else {
+      ret = FALSE;
+    }
+
+    gst_caps_unref (profile_caps);
+    gst_caps_unref (allowed_caps);
+  }
+  gst_caps_unref (template_caps);
+
+  base_encode->need_codec_data = encode->is_avc;
+
+  return ret;
+
+fail:
+  {
+    gst_caps_unref (template_caps);
+    gst_caps_unref (allowed_caps);
+    return FALSE;
+  }
+}
+
+static void
+set_compatible_profile (GstVaapiEncodeH264 * encode, GstCaps * caps,
+    GstVaapiProfile profile, GstVaapiLevelH264 level)
+{
+  GstCaps *allowed_caps, *tmp_caps;
+  gboolean ret = FALSE;
+
+  allowed_caps =
+      gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
+  if (!allowed_caps || gst_caps_is_empty (allowed_caps)) {
+    if (allowed_caps)
+      gst_caps_unref (allowed_caps);
+    return;
+  }
+
+  tmp_caps = gst_caps_from_string (GST_CODEC_CAPS);
+
+  /* If profile doesn't exist in the allowed caps, let's find
+   * compatible profile in the caps.
+   *
+   * If there is one, we can set it as a compatible profile and make
+   * the negotiation.  We consider baseline compatible with
+   * constrained-baseline, which is a strict subset of baseline
+   * profile.
+   */
+retry:
+  gst_caps_set_simple (tmp_caps, "profile", G_TYPE_STRING,
+      gst_vaapi_utils_h264_get_profile_string (profile), NULL);
+
+  if (!gst_caps_can_intersect (allowed_caps, tmp_caps)) {
+    if (profile == GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE) {
+      profile = GST_VAAPI_PROFILE_H264_BASELINE;
+      GST_WARNING_OBJECT (GST_VAAPIENCODE_CAST (encode), "user might requested "
+          "baseline profile, trying constrained-baseline instead");
+      goto retry;
+    }
+  } else {
+    gst_caps_set_simple (caps, "profile", G_TYPE_STRING,
+        gst_vaapi_utils_h264_get_profile_string (profile),
+        "level", G_TYPE_STRING, gst_vaapi_utils_h264_get_level_string (level),
+        NULL);
+    ret = TRUE;
+  }
+
+  if (!ret)
+    GST_LOG ("There is no compatible profile in the requested caps.");
+
+  gst_caps_unref (tmp_caps);
+  gst_caps_unref (allowed_caps);
+  return;
+}
+
+static GstCaps *
+gst_vaapiencode_h264_get_caps (GstVaapiEncode * base_encode)
+{
+  GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base_encode);
+  GstVaapiEncoderH264 *const encoder =
+      GST_VAAPI_ENCODER_H264 (base_encode->encoder);
+  GstVaapiProfile profile;
+  GstVaapiLevelH264 level;
+  GstCaps *caps;
+
+  caps = gst_caps_from_string (GST_CODEC_CAPS);
+
+  gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING,
+      encode->is_avc ? "avc" : "byte-stream", NULL);
+
+  /* Update profile determined by encoder */
+  gst_vaapi_encoder_h264_get_profile_and_level (encoder, &profile, &level);
+  if (profile != GST_VAAPI_PROFILE_UNKNOWN)
+    set_compatible_profile (encode, caps, profile, level);
+
+  GST_INFO_OBJECT (base_encode, "out caps %" GST_PTR_FORMAT, caps);
+  return caps;
+}
+
+static GstVaapiEncoder *
+gst_vaapiencode_h264_alloc_encoder (GstVaapiEncode * base,
+    GstVaapiDisplay * display)
+{
+  return gst_vaapi_encoder_h264_new (display);
+}
+
+/* h264 NAL byte stream operations */
+static guint8 *
+_h264_byte_stream_next_nal (guint8 * buffer, guint32 len, guint32 * nal_size)
+{
+  const guint8 *cur = buffer;
+  const guint8 *const end = buffer + len;
+  guint8 *nal_start = NULL;
+  guint32 flag = 0xFFFFFFFF;
+  guint32 nal_start_len = 0;
+
+  g_assert (buffer && nal_size);
+  if (len < 3) {
+    *nal_size = len;
+    nal_start = (len ? buffer : NULL);
+    return nal_start;
+  }
+
+  /*locate head postion */
+  if (!buffer[0] && !buffer[1]) {
+    if (buffer[2] == 1) {       /* 0x000001 */
+      nal_start_len = 3;
+    } else if (!buffer[2] && len >= 4 && buffer[3] == 1) {      /* 0x00000001 */
+      nal_start_len = 4;
+    }
+  }
+  nal_start = buffer + nal_start_len;
+  cur = nal_start;
+
+  /*find next nal start position */
+  while (cur < end) {
+    flag = ((flag << 8) | ((*cur++) & 0xFF));
+    if ((flag & 0x00FFFFFF) == 0x00000001) {
+      if (flag == 0x00000001)
+        *nal_size = cur - 4 - nal_start;
+      else
+        *nal_size = cur - 3 - nal_start;
+      break;
+    }
+  }
+  if (cur >= end) {
+    *nal_size = end - nal_start;
+    if (nal_start >= end) {
+      nal_start = NULL;
+    }
+  }
+  return nal_start;
+}
+
+static inline void
+_start_code_to_size (guint8 nal_start_code[4], guint32 nal_size)
+{
+  nal_start_code[0] = ((nal_size >> 24) & 0xFF);
+  nal_start_code[1] = ((nal_size >> 16) & 0xFF);
+  nal_start_code[2] = ((nal_size >> 8) & 0xFF);
+  nal_start_code[3] = (nal_size & 0xFF);
+}
+
+static gboolean
+_h264_convert_byte_stream_to_avc (GstBuffer * buf)
+{
+  GstMapInfo info;
+  guint32 nal_size;
+  guint8 *nal_start_code, *nal_body;
+  guint8 *frame_end;
+
+  g_assert (buf);
+
+  if (!gst_buffer_map (buf, &info, GST_MAP_READ | GST_MAP_WRITE))
+    return FALSE;
+
+  nal_start_code = info.data;
+  frame_end = info.data + info.size;
+  nal_size = 0;
+
+  while ((frame_end > nal_start_code) &&
+      (nal_body = _h264_byte_stream_next_nal (nal_start_code,
+              frame_end - nal_start_code, &nal_size)) != NULL) {
+    if (!nal_size)
+      goto error;
+
+    g_assert (nal_body - nal_start_code == 4);
+    _start_code_to_size (nal_start_code, nal_size);
+    nal_start_code = nal_body + nal_size;
+  }
+  gst_buffer_unmap (buf, &info);
+  return TRUE;
+
+  /* ERRORS */
+error:
+  {
+    gst_buffer_unmap (buf, &info);
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_vaapiencode_h264_alloc_buffer (GstVaapiEncode * base_encode,
+    GstVaapiCodedBuffer * coded_buf, GstBuffer ** out_buffer_ptr)
+{
+  GstVaapiEncodeH264 *const encode = GST_VAAPIENCODE_H264_CAST (base_encode);
+  GstVaapiEncoderH264 *const encoder =
+      GST_VAAPI_ENCODER_H264 (base_encode->encoder);
+  GstFlowReturn ret;
+
+  g_return_val_if_fail (encoder != NULL, GST_FLOW_ERROR);
+
+  ret =
+      GST_VAAPIENCODE_CLASS (gst_vaapiencode_h264_parent_class)->alloc_buffer
+      (base_encode, coded_buf, out_buffer_ptr);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  if (!encode->is_avc)
+    return GST_FLOW_OK;
+
+  /* Convert to avcC format */
+  if (!_h264_convert_byte_stream_to_avc (*out_buffer_ptr))
+    goto error_convert_buffer;
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_convert_buffer:
+  {
+    GST_ERROR ("failed to convert from bytestream format to avcC format");
+    gst_buffer_replace (out_buffer_ptr, NULL);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_vaapiencode_h264_class_init (GstVaapiEncodeH264Class * klass, gpointer data)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass);
+  GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps;
+  GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps;
+  GstPadTemplate *templ;
+  GstCaps *static_caps;
+  gpointer encoder_class;
+
+  object_class->finalize = gst_vaapiencode_h264_finalize;
+  object_class->set_property = gst_vaapiencode_set_property_subclass;
+  object_class->get_property = gst_vaapiencode_get_property_subclass;
+
+  encode_class->get_allowed_profiles =
+      gst_vaapiencode_h264_get_allowed_profiles;
+  encode_class->set_config = gst_vaapiencode_h264_set_config;
+  encode_class->get_caps = gst_vaapiencode_h264_get_caps;
+  encode_class->alloc_encoder = gst_vaapiencode_h264_alloc_encoder;
+  encode_class->alloc_buffer = gst_vaapiencode_h264_alloc_buffer;
+
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API H264 encoder",
+      "Codec/Encoder/Video/Hardware",
+      GST_PLUGIN_DESC, "Wind Yuan <feng.yuan@intel.com>");
+
+  /* sink pad */
+  g_assert (sink_caps);
+  static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS);
+  templ =
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (sink_caps);
+
+  /* src pad */
+  g_assert (src_caps);
+  static_caps = gst_caps_from_string (GST_CODEC_CAPS);
+  templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (src_caps);
+
+  encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_H264);
+  g_assert (encoder_class);
+  gst_vaapiencode_class_install_properties (encode_class, encoder_class);
+  g_type_class_unref (encoder_class);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h264.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h264.h
new file mode 100644 (file)
index 0000000..f59797e
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ *  gstvaapiencode_h264.h - VA-API H.264 encoder
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Wind Yuan <feng.yuan@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIENCODE_H264_H
+#define GST_VAAPIENCODE_H264_H
+
+#include <gst/gst.h>
+#include "gstvaapiencode.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPIENCODE_H264 \
+    (gst_vaapiencode_h264_get_type ())
+#define GST_VAAPIENCODE_H264_CAST(obj) \
+  ((GstVaapiEncodeH264 *)(obj))
+#define GST_VAAPIENCODE_H264(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_H264, \
+      GstVaapiEncodeH264))
+#define GST_VAAPIENCODE_H264_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_H264, \
+      GstVaapiEncodeH264Class))
+#define GST_VAAPIENCODE_H264_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_H264, \
+      GstVaapiEncodeH264Class))
+#define GST_IS_VAAPIENCODE_H264(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_H264))
+#define GST_IS_VAAPIENCODE_H264_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_H264))
+
+typedef struct _GstVaapiEncodeH264 GstVaapiEncodeH264;
+typedef struct _GstVaapiEncodeH264Class GstVaapiEncodeH264Class;
+
+struct _GstVaapiEncodeH264
+{
+  /*< private >*/
+  GstVaapiEncode parent_instance;
+
+  guint is_avc:1; /* [FALSE]=byte-stream (default); [TRUE]=avcC */
+  GstCaps *available_caps;
+};
+
+struct _GstVaapiEncodeH264Class
+{
+  /*< private >*/
+  GstVaapiEncodeClass parent_class;
+};
+
+GType
+gst_vaapiencode_h264_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapiencode_h264_register_type (GstVaapiDisplay * display);
+
+G_END_DECLS
+
+#endif /* GST_VAAPIENCODE_H264_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h265.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h265.c
new file mode 100644 (file)
index 0000000..b0ed413
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ *  gstvaapiencode_h265.c - VA-API H.265 encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapih265enc
+ * @short_description: A VA-API based HEVC video encoder
+ *
+ * Encodes raw video streams into HEVC bitstreams.
+ *
+ * ## Example launch line
+ *
+ * |[
+ *  gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapih265enc ! h265parse ! matroskamux ! filesink location=test.mkv
+ * ]|
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiencoder_h265.h>
+#include <gst/vaapi/gstvaapiutils_h265.h>
+#include "gstvaapiencode_h265.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideomemory.h"
+
+#define GST_PLUGIN_NAME "vaapih265enc"
+#define GST_PLUGIN_DESC "A VA-API based H265 video encoder"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vaapi_h265_encode_debug);
+#define GST_CAT_DEFAULT gst_vaapi_h265_encode_debug
+
+#define GST_CODEC_CAPS                              \
+  "video/x-h265, "                                  \
+  "stream-format = (string) { hvc1, byte-stream }, " \
+  "alignment = (string) au"
+
+#define EXTRA_FORMATS {}
+
+/* h265 encode */
+GST_VAAPI_ENCODE_REGISTER_TYPE (h265, H265, H265, EXTRA_FORMATS,
+    gst_vaapi_utils_h265_get_profile_string);
+
+static void
+gst_vaapiencode_h265_init (GstVaapiEncodeH265 * encode)
+{
+  /* nothing to do here */
+}
+
+static void
+gst_vaapiencode_h265_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (gst_vaapiencode_h265_parent_class)->finalize (object);
+}
+
+static GArray *
+gst_vaapiencode_h265_get_allowed_profiles (GstVaapiEncode * encode,
+    GstCaps * allowed)
+{
+  return gst_vaapi_encoder_get_profiles_from_caps (allowed,
+      gst_vaapi_utils_h265_get_profile_from_string);
+}
+
+static gboolean
+gst_vaapiencode_h265_set_config (GstVaapiEncode * base_encode)
+{
+  GstVaapiEncoderH265 *const encoder =
+      GST_VAAPI_ENCODER_H265 (base_encode->encoder);
+  GstCaps *allowed_caps = NULL;
+  GstCaps *template_caps = NULL;
+  GArray *profiles = NULL;
+  GArray *profiles_hw = NULL;
+  GArray *profiles_allowed = NULL;
+  GstVaapiProfile profile;
+  gboolean ret = TRUE;
+  guint i, j;
+
+  profiles_hw = gst_vaapi_display_get_encode_profiles_by_codec
+      (GST_VAAPI_PLUGIN_BASE_DISPLAY (base_encode), GST_VAAPI_CODEC_H265);
+  if (!profiles_hw) {
+    ret = FALSE;
+    goto out;
+  }
+
+  template_caps =
+      gst_pad_get_pad_template_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD
+      (base_encode));
+  allowed_caps =
+      gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (base_encode));
+  if (!allowed_caps || allowed_caps == template_caps) {
+    ret = gst_vaapi_encoder_h265_set_allowed_profiles (encoder, profiles_hw);
+    goto out;
+  } else if (gst_caps_is_empty (allowed_caps)) {
+    ret = FALSE;
+    goto out;
+  }
+
+  profiles = gst_vaapi_encoder_get_profiles_from_caps (allowed_caps,
+      gst_vaapi_utils_h265_get_profile_from_string);
+  if (!profiles) {
+    ret = FALSE;
+    goto out;
+  }
+
+  profiles_allowed = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile));
+  if (!profiles_allowed) {
+    ret = FALSE;
+    goto out;
+  }
+
+  for (i = 0; i < profiles->len; i++) {
+    profile = g_array_index (profiles, GstVaapiProfile, i);
+    for (j = 0; j < profiles_hw->len; j++) {
+      GstVaapiProfile p = g_array_index (profiles_hw, GstVaapiProfile, j);
+      if (p == profile) {
+        g_array_append_val (profiles_allowed, profile);
+        break;
+      }
+    }
+  }
+  if (profiles_allowed->len == 0) {
+    ret = FALSE;
+    goto out;
+  }
+
+  ret = gst_vaapi_encoder_h265_set_allowed_profiles (encoder, profiles_allowed);
+
+out:
+  if (allowed_caps)
+    gst_caps_unref (allowed_caps);
+  if (template_caps)
+    gst_caps_unref (template_caps);
+  if (profiles)
+    g_array_unref (profiles);
+  if (profiles_hw)
+    g_array_unref (profiles_hw);
+  if (profiles_allowed)
+    g_array_unref (profiles_allowed);
+
+  return ret;
+}
+
+static GstCaps *
+gst_vaapiencode_h265_get_caps (GstVaapiEncode * base_encode)
+{
+  GstVaapiEncodeH265 *const encode = GST_VAAPIENCODE_H265_CAST (base_encode);
+  GstVaapiEncoderH265 *const encoder =
+      GST_VAAPI_ENCODER_H265 (base_encode->encoder);
+  GstCaps *caps, *allowed_caps;
+  GstVaapiProfile profile = GST_VAAPI_PROFILE_UNKNOWN;
+  GstVaapiLevelH265 level = 0;
+  GstVaapiTierH265 tier = GST_VAAPI_TIER_H265_UNKNOWN;
+
+  caps = gst_caps_from_string (GST_CODEC_CAPS);
+
+  /* Check whether "stream-format" is hvcC mode */
+  allowed_caps =
+      gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (encode));
+  if (allowed_caps) {
+    const char *stream_format = NULL;
+    GstStructure *structure;
+    guint i, num_structures;
+
+    num_structures = gst_caps_get_size (allowed_caps);
+    for (i = 0; !stream_format && i < num_structures; i++) {
+      structure = gst_caps_get_structure (allowed_caps, i);
+      if (!gst_structure_has_field_typed (structure, "stream-format",
+              G_TYPE_STRING))
+        continue;
+      stream_format = gst_structure_get_string (structure, "stream-format");
+    }
+    encode->is_hvc = stream_format && strcmp (stream_format, "hvc1") == 0;
+    gst_caps_unref (allowed_caps);
+  }
+  gst_caps_set_simple (caps, "stream-format", G_TYPE_STRING,
+      encode->is_hvc ? "hvc1" : "byte-stream", NULL);
+
+  base_encode->need_codec_data = encode->is_hvc;
+
+  gst_vaapi_encoder_h265_get_profile_tier_level (encoder,
+      &profile, &tier, &level);
+  if (profile != GST_VAAPI_PROFILE_UNKNOWN) {
+    gst_caps_set_simple (caps, "profile", G_TYPE_STRING,
+        gst_vaapi_utils_h265_get_profile_string (profile), NULL);
+
+    if (level) {
+      gst_caps_set_simple (caps, "level", G_TYPE_STRING,
+          gst_vaapi_utils_h265_get_level_string (level), NULL);
+
+      if (tier != GST_VAAPI_TIER_H265_UNKNOWN)
+        gst_caps_set_simple (caps, "tier", G_TYPE_STRING,
+            gst_vaapi_utils_h265_get_tier_string (tier), NULL);
+    }
+  }
+
+  return caps;
+}
+
+static GstVaapiEncoder *
+gst_vaapiencode_h265_alloc_encoder (GstVaapiEncode * base,
+    GstVaapiDisplay * display)
+{
+  return gst_vaapi_encoder_h265_new (display);
+}
+
+/* h265 NAL byte stream operations */
+static guint8 *
+_h265_byte_stream_next_nal (guint8 * buffer, guint32 len, guint32 * nal_size)
+{
+  const guint8 *cur = buffer;
+  const guint8 *const end = buffer + len;
+  guint8 *nal_start = NULL;
+  guint32 flag = 0xFFFFFFFF;
+  guint32 nal_start_len = 0;
+
+  g_assert (len != 0U && buffer && nal_size);
+  if (len < 3) {
+    *nal_size = len;
+    nal_start = (len ? buffer : NULL);
+    return nal_start;
+  }
+
+  /*locate head postion */
+  if (!buffer[0] && !buffer[1]) {
+    if (buffer[2] == 1) {       /* 0x000001 */
+      nal_start_len = 3;
+    } else if (!buffer[2] && len >= 4 && buffer[3] == 1) {      /* 0x00000001 */
+      nal_start_len = 4;
+    }
+  }
+  nal_start = buffer + nal_start_len;
+  cur = nal_start;
+
+  /*find next nal start position */
+  while (cur < end) {
+    flag = ((flag << 8) | ((*cur++) & 0xFF));
+    if ((flag & 0x00FFFFFF) == 0x00000001) {
+      if (flag == 0x00000001)
+        *nal_size = cur - 4 - nal_start;
+      else
+        *nal_size = cur - 3 - nal_start;
+      break;
+    }
+  }
+  if (cur >= end) {
+    *nal_size = end - nal_start;
+    if (nal_start >= end) {
+      nal_start = NULL;
+    }
+  }
+  return nal_start;
+}
+
+static inline void
+_start_code_to_size (guint8 nal_start_code[4], guint32 nal_size)
+{
+  nal_start_code[0] = ((nal_size >> 24) & 0xFF);
+  nal_start_code[1] = ((nal_size >> 16) & 0xFF);
+  nal_start_code[2] = ((nal_size >> 8) & 0xFF);
+  nal_start_code[3] = (nal_size & 0xFF);
+}
+
+static gboolean
+_h265_convert_byte_stream_to_hvc (GstBuffer * buf)
+{
+  GstMapInfo info;
+  guint32 nal_size;
+  guint8 *nal_start_code, *nal_body;
+  guint8 *frame_end;
+
+  g_assert (buf);
+
+  if (!gst_buffer_map (buf, &info, GST_MAP_READ | GST_MAP_WRITE))
+    return FALSE;
+
+  nal_start_code = info.data;
+  frame_end = info.data + info.size;
+  nal_size = 0;
+
+  while ((frame_end > nal_start_code) &&
+      (nal_body = _h265_byte_stream_next_nal (nal_start_code,
+              frame_end - nal_start_code, &nal_size)) != NULL) {
+    if (!nal_size)
+      goto error;
+
+    g_assert (nal_body - nal_start_code == 4);
+    _start_code_to_size (nal_start_code, nal_size);
+    nal_start_code = nal_body + nal_size;
+  }
+  gst_buffer_unmap (buf, &info);
+  return TRUE;
+
+  /* ERRORS */
+error:
+  {
+    gst_buffer_unmap (buf, &info);
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_vaapiencode_h265_alloc_buffer (GstVaapiEncode * base_encode,
+    GstVaapiCodedBuffer * coded_buf, GstBuffer ** out_buffer_ptr)
+{
+  GstVaapiEncodeH265 *const encode = GST_VAAPIENCODE_H265_CAST (base_encode);
+  GstVaapiEncoderH265 *const encoder =
+      GST_VAAPI_ENCODER_H265 (base_encode->encoder);
+  GstFlowReturn ret;
+
+  g_return_val_if_fail (encoder != NULL, GST_FLOW_ERROR);
+
+  ret =
+      GST_VAAPIENCODE_CLASS (gst_vaapiencode_h265_parent_class)->alloc_buffer
+      (base_encode, coded_buf, out_buffer_ptr);
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  if (!encode->is_hvc)
+    return GST_FLOW_OK;
+
+  /* Convert to hvcC format */
+  if (!_h265_convert_byte_stream_to_hvc (*out_buffer_ptr))
+    goto error_convert_buffer;
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_convert_buffer:
+  {
+    GST_ERROR ("failed to convert from bytestream format to hvcC format");
+    gst_buffer_replace (out_buffer_ptr, NULL);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_vaapiencode_h265_class_init (GstVaapiEncodeH265Class * klass, gpointer data)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass);
+  GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps;
+  GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps;
+  GstPadTemplate *templ;
+  GstCaps *static_caps;
+  gpointer encoder_class;
+
+  object_class->finalize = gst_vaapiencode_h265_finalize;
+  object_class->set_property = gst_vaapiencode_set_property_subclass;
+  object_class->get_property = gst_vaapiencode_get_property_subclass;
+
+  encode_class->get_allowed_profiles =
+      gst_vaapiencode_h265_get_allowed_profiles;
+  encode_class->set_config = gst_vaapiencode_h265_set_config;
+  encode_class->get_caps = gst_vaapiencode_h265_get_caps;
+  encode_class->alloc_encoder = gst_vaapiencode_h265_alloc_encoder;
+  encode_class->alloc_buffer = gst_vaapiencode_h265_alloc_buffer;
+
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API H265 encoder",
+      "Codec/Encoder/Video/Hardware",
+      GST_PLUGIN_DESC,
+      "Sreerenj Balachandran <sreerenj.balachandran@intel.com>");
+
+  /* sink pad */
+  g_assert (sink_caps);
+  static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS);
+  templ =
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (sink_caps);
+
+  /* src pad */
+  g_assert (src_caps);
+  static_caps = gst_caps_from_string (GST_CODEC_CAPS);
+  templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (src_caps);
+
+  encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_H265);
+  g_assert (encoder_class);
+  gst_vaapiencode_class_install_properties (encode_class, encoder_class);
+  g_type_class_unref (encoder_class);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h265.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_h265.h
new file mode 100644 (file)
index 0000000..4371dcf
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ *  gstvaapiencode_h265.h - VA-API H.265 encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIENCODE_H265_H
+#define GST_VAAPIENCODE_H265_H
+
+#include <gst/gst.h>
+#include "gstvaapiencode.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPIENCODE_H265 \
+    (gst_vaapiencode_h265_get_type ())
+#define GST_VAAPIENCODE_H265_CAST(obj) \
+  ((GstVaapiEncodeH265 *)(obj))
+#define GST_VAAPIENCODE_H265(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_H265, \
+      GstVaapiEncodeH265))
+#define GST_VAAPIENCODE_H265_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_H265, \
+      GstVaapiEncodeH265Class))
+#define GST_VAAPIENCODE_H265_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_H265, \
+      GstVaapiEncodeH265Class))
+#define GST_IS_VAAPIENCODE_H265(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_H265))
+#define GST_IS_VAAPIENCODE_H265_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_H265))
+
+typedef struct _GstVaapiEncodeH265 GstVaapiEncodeH265;
+typedef struct _GstVaapiEncodeH265Class GstVaapiEncodeH265Class;
+
+struct _GstVaapiEncodeH265
+{
+  /*< private >*/
+  GstVaapiEncode parent_instance;
+
+  guint is_hvc:1; /* [FALSE]=byte-stream (default); [TRUE]=hvcC */
+};
+
+struct _GstVaapiEncodeH265Class
+{
+  /*< private >*/
+  GstVaapiEncodeClass parent_class;
+};
+
+GType
+gst_vaapiencode_h265_get_type (void) G_GNUC_CONST;
+GType
+gst_vaapiencode_h265_register_type (GstVaapiDisplay * display);
+
+G_END_DECLS
+
+#endif /* GST_VAAPIENCODE_H265_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_jpeg.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_jpeg.c
new file mode 100644 (file)
index 0000000..667a184
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *  gstvaapiencode_jpeg.c - VA-API JPEG encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapijpegenc
+ * @short_description: A VA-API based JPEG image encoder
+ *
+ * Encodes raw images into JPEG images.
+ *
+ * ## Example launch line
+ *
+ * |[
+ *  gst-launch-1.0 -ev videotestsrc num-buffers=1 ! timeoverlay ! vaapijpegenc ! filesink location=test.jpg
+ * ]|
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiencoder_jpeg.h>
+#include "gstvaapiencode_jpeg.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideomemory.h"
+
+#define GST_PLUGIN_NAME "vaapijpegenc"
+#define GST_PLUGIN_DESC "A VA-API based JPEG video encoder"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vaapi_jpeg_encode_debug);
+#define GST_CAT_DEFAULT gst_vaapi_jpeg_encode_debug
+
+#define GST_CODEC_CAPS                          \
+  "image/jpeg"
+
+#define EXTRA_FORMATS { GST_VIDEO_FORMAT_BGRA, }
+
+/* jpeg encode */
+GST_VAAPI_ENCODE_REGISTER_TYPE (jpeg, JPEG, Jpeg, EXTRA_FORMATS, NULL);
+
+static void
+gst_vaapiencode_jpeg_init (GstVaapiEncodeJpeg * encode)
+{
+  /* nothing to do here */
+}
+
+static void
+gst_vaapiencode_jpeg_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (gst_vaapiencode_jpeg_parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_vaapiencode_jpeg_get_caps (GstVaapiEncode * base_encode)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_from_string (GST_CODEC_CAPS);
+
+  return caps;
+}
+
+static GstVaapiEncoder *
+gst_vaapiencode_jpeg_alloc_encoder (GstVaapiEncode * base,
+    GstVaapiDisplay * display)
+{
+  return gst_vaapi_encoder_jpeg_new (display);
+}
+
+static void
+gst_vaapiencode_jpeg_class_init (GstVaapiEncodeJpegClass * klass, gpointer data)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass);
+  GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps;
+  GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps;
+  GstPadTemplate *templ;
+  GstCaps *static_caps;
+  gpointer encoder_class;
+
+  object_class->finalize = gst_vaapiencode_jpeg_finalize;
+  object_class->set_property = gst_vaapiencode_set_property_subclass;
+  object_class->get_property = gst_vaapiencode_get_property_subclass;
+
+  encode_class->get_caps = gst_vaapiencode_jpeg_get_caps;
+  encode_class->alloc_encoder = gst_vaapiencode_jpeg_alloc_encoder;
+
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API JPEG encoder",
+      "Codec/Encoder/Image/Hardware",
+      GST_PLUGIN_DESC,
+      "Sreerenj Balachandran <sreerenj.balachandran@intel.com>");
+
+  /* sink pad */
+  g_assert (sink_caps);
+  static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS);
+  templ =
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (sink_caps);
+
+  /* src pad */
+  g_assert (src_caps);
+  static_caps = gst_caps_from_string (GST_CODEC_CAPS);
+  templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (src_caps);
+
+  encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_JPEG);
+  g_assert (encoder_class);
+  gst_vaapiencode_class_install_properties (encode_class, encoder_class);
+  g_type_class_unref (encoder_class);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_jpeg.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_jpeg.h
new file mode 100644 (file)
index 0000000..f0bab68
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  gstvaapiencode_jpeg.h - VA-API JPEG encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIENCODE_JPEG_H
+#define GST_VAAPIENCODE_JPEG_H
+
+#include <gst/gst.h>
+#include "gstvaapiencode.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPIENCODE_JPEG \
+    (gst_vaapiencode_jpeg_get_type ())
+#define GST_VAAPIENCODE_JPEG_CAST(obj) \
+  ((GstVaapiEncodeJpeg *)(obj))
+#define GST_VAAPIENCODE_JPEG(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_JPEG, \
+      GstVaapiEncodeJpeg))
+#define GST_VAAPIENCODE_JPEG_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_JPEG, \
+      GstVaapiEncodeJpegClass))
+#define GST_VAAPIENCODE_JPEG_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_JPEG, \
+      GstVaapiEncodeJpegClass))
+#define GST_IS_VAAPIENCODE_JPEG(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_JPEG))
+#define GST_IS_VAAPIENCODE_JPEG_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_JPEG))
+
+typedef struct _GstVaapiEncodeJpeg GstVaapiEncodeJpeg;
+typedef struct _GstVaapiEncodeJpegClass GstVaapiEncodeJpegClass;
+
+struct _GstVaapiEncodeJpeg
+{
+  /*< private >*/
+  GstVaapiEncode parent_instance;
+};
+
+struct _GstVaapiEncodeJpegClass
+{
+  /*< private >*/
+  GstVaapiEncodeClass parent_class;
+};
+
+GType
+gst_vaapiencode_jpeg_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapiencode_jpeg_register_type (GstVaapiDisplay * display);
+
+G_END_DECLS
+
+#endif /* GST_VAAPIENCODE_JPEG_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_mpeg2.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_mpeg2.c
new file mode 100644 (file)
index 0000000..0701a10
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ *  gstvaapiencode_mpeg2.c - VA-API MPEG2 encoder
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Guangxin Xu <guangxin.xu@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapimpeg2enc
+ * @short_description: A VA-API based MPEG2 video encoder
+ *
+ * Encodes raw video streams into MPEG2 bitstreams.
+ *
+ * ## Example launch line
+ *
+ * |[
+ *  gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapimpeg2enc ! matroskamux ! filesink location=test.mkv
+ * ]|
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiencoder_mpeg2.h>
+#include <gst/vaapi/gstvaapiutils_mpeg2.h>
+#include "gstvaapiencode_mpeg2.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideomemory.h"
+
+#define GST_PLUGIN_NAME "vaapimpeg2enc"
+#define GST_PLUGIN_DESC "A VA-API based MPEG-2 video encoder"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vaapi_mpeg2_encode_debug);
+#define GST_CAT_DEFAULT gst_vaapi_mpeg2_encode_debug
+
+#define GST_CODEC_CAPS                          \
+  "video/mpeg, mpegversion = (int) 2, "         \
+  "systemstream = (boolean) false"
+
+#define EXTRA_FORMATS {}
+
+/* mpeg2 encode */
+GST_VAAPI_ENCODE_REGISTER_TYPE (mpeg2, MPEG2, Mpeg2, EXTRA_FORMATS,
+    gst_vaapi_utils_mpeg2_get_profile_string);
+
+static void
+gst_vaapiencode_mpeg2_init (GstVaapiEncodeMpeg2 * encode)
+{
+  /* nothing to do here */
+}
+
+static void
+gst_vaapiencode_mpeg2_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (gst_vaapiencode_mpeg2_parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_vaapiencode_mpeg2_get_caps (GstVaapiEncode * base_encode)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_from_string (GST_CODEC_CAPS);
+
+  /* XXX: update profile and level information */
+  return caps;
+}
+
+static GstVaapiEncoder *
+gst_vaapiencode_mpeg2_alloc_encoder (GstVaapiEncode * base,
+    GstVaapiDisplay * display)
+{
+  return gst_vaapi_encoder_mpeg2_new (display);
+}
+
+static void
+gst_vaapiencode_mpeg2_class_init (GstVaapiEncodeMpeg2Class * klass,
+    gpointer data)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass);
+  GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps;
+  GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps;
+  GstPadTemplate *templ;
+  GstCaps *static_caps;
+  gpointer encoder_class;
+
+  object_class->finalize = gst_vaapiencode_mpeg2_finalize;
+  object_class->set_property = gst_vaapiencode_set_property_subclass;
+  object_class->get_property = gst_vaapiencode_get_property_subclass;
+
+  encode_class->get_caps = gst_vaapiencode_mpeg2_get_caps;
+  encode_class->alloc_encoder = gst_vaapiencode_mpeg2_alloc_encoder;
+
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API MPEG-2 encoder",
+      "Codec/Encoder/Video/Hardware",
+      GST_PLUGIN_DESC, "Guangxin Xu <guangxin.xu@intel.com>");
+
+  /* sink pad */
+  g_assert (sink_caps);
+  static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS);
+  templ =
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (sink_caps);
+
+  /* src pad */
+  g_assert (src_caps);
+  static_caps = gst_caps_from_string (GST_CODEC_CAPS);
+  templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (src_caps);
+
+  encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_MPEG2);
+  g_assert (encoder_class);
+  gst_vaapiencode_class_install_properties (encode_class, encoder_class);
+  g_type_class_unref (encoder_class);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_mpeg2.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_mpeg2.h
new file mode 100644 (file)
index 0000000..a8c7659
--- /dev/null
@@ -0,0 +1,77 @@
+/*
+ *  gstvaapiencode_mpeg2.h - VA-API MPEG2 encoder
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Guangxin Xu <guangxin.xu@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIENCODE_MPEG2_H
+#define GST_VAAPIENCODE_MPEG2_H
+
+#include <gst/gst.h>
+#include "gstvaapiencode.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPIENCODE_MPEG2 \
+    (gst_vaapiencode_mpeg2_get_type ())
+#define GST_VAAPIENCODE_MPEG2_CAST(obj) \
+  ((GstVaapiEncodeMpeg2 *)(obj))
+#define GST_VAAPIENCODE_MPEG2(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_MPEG2, \
+      GstVaapiEncodeMpeg2))
+#define GST_VAAPIENCODE_MPEG2_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_MPEG2, \
+      GstVaapiEncodeMpeg2Class))
+#define GST_VAAPIENCODE_MPEG2_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_MPEG2, \
+      GstVaapiEncodeMpeg2Class))
+#define GST_IS_VAAPIENCODE_MPEG2(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_MPEG2))
+#define GST_IS_VAAPIENCODE_MPEG2_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_MPEG2))
+
+typedef struct _GstVaapiEncodeMpeg2 GstVaapiEncodeMpeg2;
+typedef struct _GstVaapiEncodeMpeg2Class GstVaapiEncodeMpeg2Class;
+
+struct _GstVaapiEncodeMpeg2
+{
+  /*< private >*/
+  GstVaapiEncode parent_instance;
+
+  guint32 quantizer;
+  guint32 intra_period;
+  guint32 ip_period;
+};
+
+struct _GstVaapiEncodeMpeg2Class
+{
+  /*< private >*/
+  GstVaapiEncodeClass parent_class;
+};
+
+GType
+gst_vaapiencode_mpeg2_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapiencode_mpeg2_register_type (GstVaapiDisplay * display);
+
+G_END_DECLS
+
+#endif /* GST_VAAPIENCODE_MPEG2_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp8.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp8.c
new file mode 100644 (file)
index 0000000..a8f0d34
--- /dev/null
@@ -0,0 +1,134 @@
+/*
+ *  gstvaapiencode_vp8.c - VA-API VP8 encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapivp8enc
+ * @short_description: A VA-API based VP8 video encoder
+ *
+ * Encodes raw video streams into VP8 bitstreams.
+ *
+ * ## Example launch line
+ *
+ * |[
+ *  gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapivp8enc ! matroskamux ! filesink location=test.mkv
+ * ]|
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiencoder_vp8.h>
+#include "gstvaapiencode_vp8.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideomemory.h"
+
+#define GST_PLUGIN_NAME "vaapivp8enc"
+#define GST_PLUGIN_DESC "A VA-API based VP8 video encoder"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vaapi_vp8_encode_debug);
+#define GST_CAT_DEFAULT gst_vaapi_vp8_encode_debug
+
+#define GST_CODEC_CAPS                          \
+  "video/x-vp8"
+
+#define EXTRA_FORMATS {}
+
+/* vp8 encode */
+GST_VAAPI_ENCODE_REGISTER_TYPE (vp8, VP8, VP8, EXTRA_FORMATS, NULL);
+
+static void
+gst_vaapiencode_vp8_init (GstVaapiEncodeVP8 * encode)
+{
+  /* nothing to do here */
+}
+
+static void
+gst_vaapiencode_vp8_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (gst_vaapiencode_vp8_parent_class)->finalize (object);
+}
+
+static GstCaps *
+gst_vaapiencode_vp8_get_caps (GstVaapiEncode * base_encode)
+{
+  GstCaps *caps;
+
+  caps = gst_caps_from_string (GST_CODEC_CAPS);
+
+  return caps;
+}
+
+static GstVaapiEncoder *
+gst_vaapiencode_vp8_alloc_encoder (GstVaapiEncode * base,
+    GstVaapiDisplay * display)
+{
+  return gst_vaapi_encoder_vp8_new (display);
+}
+
+static void
+gst_vaapiencode_vp8_class_init (GstVaapiEncodeVP8Class * klass, gpointer data)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass);
+  GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps;
+  GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps;
+  GstPadTemplate *templ;
+  GstCaps *static_caps;
+  gpointer encoder_class;
+
+  object_class->finalize = gst_vaapiencode_vp8_finalize;
+  object_class->set_property = gst_vaapiencode_set_property_subclass;
+  object_class->get_property = gst_vaapiencode_get_property_subclass;
+
+  encode_class->get_caps = gst_vaapiencode_vp8_get_caps;
+  encode_class->alloc_encoder = gst_vaapiencode_vp8_alloc_encoder;
+
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API VP8 encoder",
+      "Codec/Encoder/Video/Hardware",
+      GST_PLUGIN_DESC,
+      "Sreerenj Balachandran <sreerenj.balachandran@intel.com>");
+
+  /* sink pad */
+  g_assert (sink_caps);
+  static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS);
+  templ =
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (sink_caps);
+
+  /* src pad */
+  g_assert (src_caps);
+  static_caps = gst_caps_from_string (GST_CODEC_CAPS);
+  templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (src_caps);
+
+  encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_VP8);
+  g_assert (encoder_class);
+  gst_vaapiencode_class_install_properties (encode_class, encoder_class);
+  g_type_class_unref (encoder_class);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp8.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp8.h
new file mode 100644 (file)
index 0000000..1523a9d
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  gstvaapiencode_vp8.h - VA-API VP8 encoder
+ *
+ *  Copyright (C) 2015 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIENCODE_VP8_H
+#define GST_VAAPIENCODE_VP8_H
+
+#include <gst/gst.h>
+#include "gstvaapiencode.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPIENCODE_VP8 \
+    (gst_vaapiencode_vp8_get_type ())
+#define GST_VAAPIENCODE_VP8_CAST(obj) \
+  ((GstVaapiEncodeVP8 *)(obj))
+#define GST_VAAPIENCODE_VP8(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_VP8, \
+      GstVaapiEncodeVP8))
+#define GST_VAAPIENCODE_VP8_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_VP8, \
+      GstVaapiEncodeVP8Class))
+#define GST_VAAPIENCODE_VP8_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_VP8, \
+      GstVaapiEncodeVP8Class))
+#define GST_IS_VAAPIENCODE_VP8(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_VP8))
+#define GST_IS_VAAPIENCODE_VP8_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_VP8))
+
+typedef struct _GstVaapiEncodeVP8 GstVaapiEncodeVP8;
+typedef struct _GstVaapiEncodeVP8Class GstVaapiEncodeVP8Class;
+
+struct _GstVaapiEncodeVP8
+{
+  /*< private >*/
+  GstVaapiEncode parent_instance;
+};
+
+struct _GstVaapiEncodeVP8Class
+{
+  /*< private >*/
+  GstVaapiEncodeClass parent_class;
+};
+
+GType
+gst_vaapiencode_vp8_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapiencode_vp8_register_type (GstVaapiDisplay * display);
+
+G_END_DECLS
+
+#endif /* GST_VAAPIENCODE_VP8_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp9.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp9.c
new file mode 100644 (file)
index 0000000..a7cf7c2
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+ *  gstvaapiencode_vp9.c - VA-API VP9 encoder
+ *
+ *  Copyright (C) 2016 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapivp9enc
+ * @short_description: A VA-API based VP9 video encoder
+ *
+ * Encodes raw video streams into VP9 bitstreams.
+ *
+ * ## Example launch line
+ *
+ * |[
+ *  gst-launch-1.0 -ev videotestsrc num-buffers=60 ! timeoverlay ! vaapivp9enc ! matroskamux ! filesink location=test.mkv
+ * ]|
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiencoder_vp9.h>
+#include <gst/vaapi/gstvaapiutils_vpx.h>
+#include "gstvaapiencode_vp9.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideomemory.h"
+
+#define GST_PLUGIN_NAME "vaapivp9enc"
+#define GST_PLUGIN_DESC "A VA-API based VP9 video encoder"
+
+GST_DEBUG_CATEGORY_STATIC (gst_vaapi_vp9_encode_debug);
+#define GST_CAT_DEFAULT gst_vaapi_vp9_encode_debug
+
+#define GST_CODEC_CAPS                          \
+  "video/x-vp9"
+
+#define EXTRA_FORMATS {}
+
+/* vp9 encode */
+GST_VAAPI_ENCODE_REGISTER_TYPE (vp9, VP9, VP9, EXTRA_FORMATS,
+    gst_vaapi_utils_vp9_get_profile_string);
+
+static void
+gst_vaapiencode_vp9_init (GstVaapiEncodeVP9 * encode)
+{
+  /* nothing to do here */
+}
+
+static void
+gst_vaapiencode_vp9_finalize (GObject * object)
+{
+  G_OBJECT_CLASS (gst_vaapiencode_vp9_parent_class)->finalize (object);
+}
+
+static GArray *
+gst_vaapiencode_vp9_get_allowed_profiles (GstVaapiEncode * encode,
+    GstCaps * allowed)
+{
+  return gst_vaapi_encoder_get_profiles_from_caps (allowed,
+      gst_vaapi_utils_vp9_get_profile_from_string);
+}
+
+static GstCaps *
+gst_vaapiencode_vp9_get_caps (GstVaapiEncode * base_encode)
+{
+  GstCaps *caps;
+  GstVaapiProfile profile;
+  const gchar *profile_str;
+
+  caps = gst_caps_from_string (GST_CODEC_CAPS);
+  profile = gst_vaapi_encoder_get_profile (base_encode->encoder);
+  profile_str = gst_vaapi_utils_vp9_get_profile_string (profile);
+  if (profile_str)
+    gst_caps_set_simple (caps, "profile", G_TYPE_STRING, profile_str, NULL);
+
+  return caps;
+}
+
+static GstVaapiEncoder *
+gst_vaapiencode_vp9_alloc_encoder (GstVaapiEncode * base,
+    GstVaapiDisplay * display)
+{
+  return gst_vaapi_encoder_vp9_new (display);
+}
+
+static gboolean
+gst_vaapiencode_vp9_set_config (GstVaapiEncode * base_encode)
+{
+  GstVaapiEncoderVP9 *const encoder =
+      GST_VAAPI_ENCODER_VP9 (base_encode->encoder);
+  GstCaps *allowed_caps = NULL;
+  GstCaps *template_caps = NULL;
+  GArray *profiles = NULL;
+  GArray *profiles_hw = NULL;
+  GArray *profiles_allowed = NULL;
+  GstVaapiProfile profile;
+  gboolean ret = TRUE;
+  guint i, j;
+
+  profiles_hw = gst_vaapi_display_get_encode_profiles_by_codec
+      (GST_VAAPI_PLUGIN_BASE_DISPLAY (base_encode), GST_VAAPI_CODEC_VP9);
+  if (!profiles_hw) {
+    ret = FALSE;
+    goto out;
+  }
+
+  template_caps =
+      gst_pad_get_pad_template_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD
+      (base_encode));
+  allowed_caps =
+      gst_pad_get_allowed_caps (GST_VAAPI_PLUGIN_BASE_SRC_PAD (base_encode));
+  if (!allowed_caps || allowed_caps == template_caps) {
+    ret = gst_vaapi_encoder_vp9_set_allowed_profiles (encoder, profiles_hw);
+    goto out;
+  } else if (gst_caps_is_empty (allowed_caps)) {
+    ret = FALSE;
+    goto out;
+  }
+
+  profiles = gst_vaapi_encoder_get_profiles_from_caps (allowed_caps,
+      gst_vaapi_utils_vp9_get_profile_from_string);
+  if (!profiles) {
+    ret = FALSE;
+    goto out;
+  }
+
+  profiles_allowed = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile));
+  if (!profiles_allowed) {
+    ret = FALSE;
+    goto out;
+  }
+
+  for (i = 0; i < profiles->len; i++) {
+    profile = g_array_index (profiles, GstVaapiProfile, i);
+    for (j = 0; j < profiles_hw->len; j++) {
+      GstVaapiProfile p = g_array_index (profiles_hw, GstVaapiProfile, j);
+      if (p == profile) {
+        g_array_append_val (profiles_allowed, profile);
+        break;
+      }
+    }
+  }
+  if (profiles_allowed->len == 0) {
+    ret = FALSE;
+    goto out;
+  }
+
+  ret = gst_vaapi_encoder_vp9_set_allowed_profiles (encoder, profiles_allowed);
+
+out:
+  if (allowed_caps)
+    gst_caps_unref (allowed_caps);
+  if (template_caps)
+    gst_caps_unref (template_caps);
+  if (profiles)
+    g_array_unref (profiles);
+  if (profiles_hw)
+    g_array_unref (profiles_hw);
+  if (profiles_allowed)
+    g_array_unref (profiles_allowed);
+
+  return ret;
+}
+
+static void
+gst_vaapiencode_vp9_class_init (GstVaapiEncodeVP9Class * klass, gpointer data)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstVaapiEncodeClass *const encode_class = GST_VAAPIENCODE_CLASS (klass);
+  GstCaps *sink_caps = ((GstVaapiEncodeInitData *) data)->sink_caps;
+  GstCaps *src_caps = ((GstVaapiEncodeInitData *) data)->src_caps;
+  GstPadTemplate *templ;
+  GstCaps *static_caps;
+  gpointer encoder_class;
+
+  object_class->finalize = gst_vaapiencode_vp9_finalize;
+  object_class->set_property = gst_vaapiencode_set_property_subclass;
+  object_class->get_property = gst_vaapiencode_get_property_subclass;
+
+  encode_class->get_allowed_profiles = gst_vaapiencode_vp9_get_allowed_profiles;
+  encode_class->get_caps = gst_vaapiencode_vp9_get_caps;
+  encode_class->alloc_encoder = gst_vaapiencode_vp9_alloc_encoder;
+  encode_class->set_config = gst_vaapiencode_vp9_set_config;
+
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API VP9 encoder",
+      "Codec/Encoder/Video/Hardware",
+      GST_PLUGIN_DESC,
+      "Sreerenj Balachandran <sreerenj.balachandran@intel.com>");
+
+  /* sink pad */
+  g_assert (sink_caps);
+  static_caps = gst_caps_from_string (GST_VAAPI_ENCODE_STATIC_SINK_CAPS);
+  templ =
+      gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, sink_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (sink_caps);
+
+  /* src pad */
+  g_assert (src_caps);
+  static_caps = gst_caps_from_string (GST_CODEC_CAPS);
+  templ = gst_pad_template_new ("src", GST_PAD_SRC, GST_PAD_ALWAYS, src_caps);
+  gst_pad_template_set_documentation_caps (templ, static_caps);
+  gst_element_class_add_pad_template (element_class, templ);
+  gst_caps_unref (static_caps);
+  gst_caps_unref (src_caps);
+
+  encoder_class = g_type_class_ref (GST_TYPE_VAAPI_ENCODER_VP9);
+  g_assert (encoder_class);
+  gst_vaapiencode_class_install_properties (encode_class, encoder_class);
+  g_type_class_unref (encoder_class);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp9.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapiencode_vp9.h
new file mode 100644 (file)
index 0000000..8d57bda
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ *  gstvaapiencode_vp9.h - VA-API VP9 encoder
+ *
+ *  Copyright (C) 2016 Intel Corporation
+ *    Author: Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIENCODE_VP9_H
+#define GST_VAAPIENCODE_VP9_H
+
+#include <gst/gst.h>
+#include "gstvaapiencode.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPIENCODE_VP9 \
+    (gst_vaapiencode_vp9_get_type ())
+#define GST_VAAPIENCODE_VP9_CAST(obj) \
+  ((GstVaapiEncodeVP9 *)(obj))
+#define GST_VAAPIENCODE_VP9(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIENCODE_VP9, \
+      GstVaapiEncodeVP9))
+#define GST_VAAPIENCODE_VP9_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIENCODE_VP9, \
+      GstVaapiEncodeVP9Class))
+#define GST_VAAPIENCODE_VP9_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPIENCODE_VP9, \
+      GstVaapiEncodeVP9Class))
+#define GST_IS_VAAPIENCODE_VP9(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPIENCODE_VP9))
+#define GST_IS_VAAPIENCODE_VP9_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPIENCODE_VP9))
+
+typedef struct _GstVaapiEncodeVP9 GstVaapiEncodeVP9;
+typedef struct _GstVaapiEncodeVP9Class GstVaapiEncodeVP9Class;
+
+struct _GstVaapiEncodeVP9
+{
+  /*< private >*/
+  GstVaapiEncode parent_instance;
+};
+
+struct _GstVaapiEncodeVP9Class
+{
+  /*< private >*/
+  GstVaapiEncodeClass parent_class;
+};
+
+GType
+gst_vaapiencode_vp9_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapiencode_vp9_register_type (GstVaapiDisplay * display);
+
+G_END_DECLS
+
+#endif /* GST_VAAPIENCODE_VP9_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapioverlay.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapioverlay.c
new file mode 100644 (file)
index 0000000..384b865
--- /dev/null
@@ -0,0 +1,721 @@
+/*
+ *  gstvaapioverlay.c - VA-API vpp overlay
+ *
+ *  Copyright (C) 2019 Intel Corporation
+ *    Author: U. Artie Eoff <ullysses.a.eoff@intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+*/
+
+/**
+ * SECTION:element-vaapioverlay
+ * @title: vaapioverlay
+ * @short_description: a VA-API base video compositor
+ *
+ * The vaapioverlay element is similar to the base compositor element
+ * but uses VA-API VPP blend functions to accelerate the
+ * overlay/compositing.
+ *
+ * Currently this element only works with iHD driver.
+ *
+ * ## Example launch line
+ *
+ * |[
+ *   gst-launch-1.0 -vf videotestsrc ! vaapipostproc      \
+ *     ! tee name=testsrc ! queue                         \
+ *     ! vaapioverlay sink_1::xpos=300 sink_1::alpha=0.75 \
+ *     name=overlay ! vaapisink testsrc. ! queue ! overlay.
+ * ]|
+ */
+
+#include "gstvaapioverlay.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideobufferpool.h"
+
+#define GST_PLUGIN_NAME "vaapioverlay"
+#define GST_PLUGIN_DESC "A VA-API overlay filter"
+
+GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapi_overlay);
+#ifndef GST_DISABLE_GST_DEBUG
+#define GST_CAT_DEFAULT gst_debug_vaapi_overlay
+#else
+#define GST_CAT_DEFAULT NULL
+#endif
+
+/* Default templates */
+/* *INDENT-OFF* */
+static const char gst_vaapi_overlay_sink_caps_str[] =
+  GST_VAAPI_MAKE_SURFACE_CAPS ";"
+  GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL);
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+static const char gst_vaapi_overlay_src_caps_str[] =
+  GST_VAAPI_MAKE_SURFACE_CAPS ";"
+  GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL);
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+static GstStaticPadTemplate gst_vaapi_overlay_sink_factory =
+  GST_STATIC_PAD_TEMPLATE ("sink_%u",
+    GST_PAD_SINK,
+    GST_PAD_REQUEST,
+    GST_STATIC_CAPS (gst_vaapi_overlay_sink_caps_str));
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+static GstStaticPadTemplate gst_vaapi_overlay_src_factory =
+  GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (gst_vaapi_overlay_src_caps_str));
+/* *INDENT-ON* */
+
+G_DEFINE_TYPE (GstVaapiOverlaySinkPad, gst_vaapi_overlay_sink_pad,
+    GST_TYPE_VIDEO_AGGREGATOR_PAD);
+
+typedef struct _GstVaapiOverlaySurfaceGenerator GstVaapiOverlaySurfaceGenerator;
+struct _GstVaapiOverlaySurfaceGenerator
+{
+  GstVaapiOverlay *overlay;
+  GList *current;
+  GstVaapiBlendSurface blend_surface;
+};
+
+#define DEFAULT_PAD_XPOS   0
+#define DEFAULT_PAD_YPOS   0
+#define DEFAULT_PAD_ALPHA  1.0
+#define DEFAULT_PAD_WIDTH  0
+#define DEFAULT_PAD_HEIGHT 0
+
+enum
+{
+  PROP_PAD_0,
+  PROP_PAD_XPOS,
+  PROP_PAD_YPOS,
+  PROP_PAD_ALPHA,
+  PROP_PAD_WIDTH,
+  PROP_PAD_HEIGHT,
+};
+
+static void
+gst_vaapi_overlay_sink_pad_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (object);
+
+  switch (prop_id) {
+    case PROP_PAD_XPOS:
+      g_value_set_int (value, pad->xpos);
+      break;
+    case PROP_PAD_YPOS:
+      g_value_set_int (value, pad->ypos);
+      break;
+    case PROP_PAD_ALPHA:
+      g_value_set_double (value, pad->alpha);
+      break;
+    case PROP_PAD_WIDTH:
+      g_value_set_int (value, pad->width);
+      break;
+    case PROP_PAD_HEIGHT:
+      g_value_set_int (value, pad->height);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_overlay_sink_pad_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (object);
+
+  switch (prop_id) {
+    case PROP_PAD_XPOS:
+      pad->xpos = g_value_get_int (value);
+      break;
+    case PROP_PAD_YPOS:
+      pad->ypos = g_value_get_int (value);
+      break;
+    case PROP_PAD_ALPHA:
+      pad->alpha = g_value_get_double (value);
+      break;
+    case PROP_PAD_WIDTH:
+      pad->width = g_value_get_int (value);
+      break;
+    case PROP_PAD_HEIGHT:
+      pad->height = g_value_get_int (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_overlay_sink_pad_finalize (GObject * object)
+{
+  gst_vaapi_pad_private_finalize (GST_VAAPI_OVERLAY_SINK_PAD (object)->priv);
+
+  G_OBJECT_CLASS (gst_vaapi_overlay_sink_pad_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_overlay_sink_pad_class_init (GstVaapiOverlaySinkPadClass * klass)
+{
+  GObjectClass *const gobject_class = G_OBJECT_CLASS (klass);
+
+  gobject_class->finalize = gst_vaapi_overlay_sink_pad_finalize;
+  gobject_class->set_property = gst_vaapi_overlay_sink_pad_set_property;
+  gobject_class->get_property = gst_vaapi_overlay_sink_pad_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_PAD_XPOS,
+      g_param_spec_int ("xpos", "X Position", "X Position of the picture",
+          G_MININT, G_MAXINT, DEFAULT_PAD_XPOS,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PAD_YPOS,
+      g_param_spec_int ("ypos", "Y Position", "Y Position of the picture",
+          G_MININT, G_MAXINT, DEFAULT_PAD_YPOS,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PAD_ALPHA,
+      g_param_spec_double ("alpha", "Alpha", "Alpha of the picture", 0.0, 1.0,
+          DEFAULT_PAD_ALPHA,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PAD_WIDTH,
+      g_param_spec_int ("width", "Width",
+          "Width of the picture (0, to use the width of the input frame)",
+          0, G_MAXINT, DEFAULT_PAD_WIDTH,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+  g_object_class_install_property (gobject_class, PROP_PAD_HEIGHT,
+      g_param_spec_int ("height", "Height",
+          "Height of the picture (0, to use the height of the input frame)",
+          0, G_MAXINT, DEFAULT_PAD_HEIGHT,
+          G_PARAM_READWRITE | GST_PARAM_CONTROLLABLE | G_PARAM_STATIC_STRINGS));
+}
+
+static void
+gst_vaapi_overlay_sink_pad_init (GstVaapiOverlaySinkPad * pad)
+{
+  pad->xpos = DEFAULT_PAD_XPOS;
+  pad->ypos = DEFAULT_PAD_YPOS;
+  pad->alpha = DEFAULT_PAD_ALPHA;
+  pad->width = DEFAULT_PAD_WIDTH;
+  pad->height = DEFAULT_PAD_HEIGHT;
+  pad->priv = gst_vaapi_pad_private_new ();
+}
+
+static void
+gst_vaapi_overlay_child_proxy_init (gpointer g_iface, gpointer iface_data);
+
+G_DEFINE_TYPE_WITH_CODE (GstVaapiOverlay, gst_vaapi_overlay,
+    GST_TYPE_VIDEO_AGGREGATOR, GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES
+    G_IMPLEMENT_INTERFACE (GST_TYPE_CHILD_PROXY,
+        gst_vaapi_overlay_child_proxy_init));
+
+GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (gst_vaapi_overlay_parent_class);
+
+static GstPad *
+gst_vaapi_overlay_request_new_pad (GstElement * element, GstPadTemplate * templ,
+    const gchar * req_name, const GstCaps * caps)
+{
+  GstPad *newpad = GST_PAD (GST_ELEMENT_CLASS
+      (gst_vaapi_overlay_parent_class)->request_new_pad (element, templ,
+          req_name, caps));
+
+  if (!newpad)
+    GST_DEBUG_OBJECT (element, "could not create/add pad");
+  else
+    gst_child_proxy_child_added (GST_CHILD_PROXY (element), G_OBJECT (newpad),
+        GST_OBJECT_NAME (newpad));
+
+  return newpad;
+}
+
+static void
+gst_vaapi_overlay_release_pad (GstElement * element, GstPad * pad)
+{
+  GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (element);
+
+  gst_child_proxy_child_removed (GST_CHILD_PROXY (overlay), G_OBJECT (pad),
+      GST_OBJECT_NAME (pad));
+
+  GST_ELEMENT_CLASS (gst_vaapi_overlay_parent_class)->release_pad (element,
+      pad);
+}
+
+static inline gboolean
+gst_vaapi_overlay_ensure_display (GstVaapiOverlay * overlay)
+{
+  return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (overlay));
+}
+
+static gboolean
+gst_vaapi_overlay_sink_query (GstAggregator * agg, GstAggregatorPad * bpad,
+    GstQuery * query)
+{
+  GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg);
+
+  if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) {
+    if (gst_vaapi_handle_context_query (GST_ELEMENT (overlay), query)) {
+      GST_DEBUG_OBJECT (overlay, "sharing display %" GST_PTR_FORMAT,
+          GST_VAAPI_PLUGIN_BASE_DISPLAY (overlay));
+      return TRUE;
+    }
+  } else if (GST_QUERY_TYPE (query) == GST_QUERY_ALLOCATION) {
+    GstCaps *caps;
+
+    gst_query_parse_allocation (query, &caps, NULL);
+
+    if (caps == NULL)
+      return FALSE;
+
+    if (!gst_vaapi_plugin_base_pad_set_caps
+        (GST_VAAPI_PLUGIN_BASE (overlay), GST_PAD (bpad), caps, NULL, NULL))
+      return FALSE;
+  }
+
+  return GST_AGGREGATOR_CLASS (gst_vaapi_overlay_parent_class)->sink_query
+      (agg, bpad, query);
+}
+
+static gboolean
+gst_vaapi_overlay_src_query (GstAggregator * agg, GstQuery * query)
+{
+  GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg);
+
+  if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) {
+    if (gst_vaapi_handle_context_query (GST_ELEMENT (overlay), query)) {
+      GST_DEBUG_OBJECT (overlay, "sharing display %" GST_PTR_FORMAT,
+          GST_VAAPI_PLUGIN_BASE_DISPLAY (overlay));
+      return TRUE;
+    }
+  }
+
+  return GST_AGGREGATOR_CLASS (gst_vaapi_overlay_parent_class)->src_query
+      (agg, query);
+}
+
+static gboolean
+gst_vaapi_overlay_start (GstAggregator * agg)
+{
+  GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg);
+
+  if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (overlay)))
+    return FALSE;
+
+  if (!gst_vaapi_overlay_ensure_display (overlay))
+    return FALSE;
+
+  overlay->blend =
+      gst_vaapi_blend_new (GST_VAAPI_PLUGIN_BASE_DISPLAY (overlay));
+  if (!overlay->blend)
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+_reset_sinkpad_private (GstElement * element, GstPad * pad, gpointer user_data)
+{
+  gst_vaapi_pad_private_reset (GST_VAAPI_OVERLAY_SINK_PAD (pad)->priv);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_overlay_stop (GstAggregator * agg)
+{
+  GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (agg);
+
+  gst_vaapi_video_pool_replace (&overlay->blend_pool, NULL);
+  gst_vaapi_blend_replace (&overlay->blend, NULL);
+
+  gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (overlay));
+
+  gst_element_foreach_sink_pad (GST_ELEMENT (overlay), _reset_sinkpad_private,
+      NULL);
+
+  return TRUE;
+}
+
+static void
+gst_vaapi_overlay_destroy (GstVaapiOverlay * const overlay)
+{
+  gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (overlay));
+  gst_element_foreach_sink_pad (GST_ELEMENT (overlay), _reset_sinkpad_private,
+      NULL);
+}
+
+static void
+gst_vaapi_overlay_finalize (GObject * object)
+{
+  GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (object);
+
+  gst_vaapi_overlay_destroy (overlay);
+  gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (overlay));
+
+  G_OBJECT_CLASS (gst_vaapi_overlay_parent_class)->finalize (object);
+}
+
+static gboolean
+gst_vaapi_overlay_propose_allocation (GstAggregator * agg,
+    GstAggregatorPad * pad, GstQuery * decide_query, GstQuery * query)
+{
+  return gst_vaapi_plugin_base_pad_propose_allocation
+      (GST_VAAPI_PLUGIN_BASE (agg), GST_PAD (pad), query);
+}
+
+static gboolean
+gst_vaapi_overlay_decide_allocation (GstAggregator * agg, GstQuery * query)
+{
+  return gst_vaapi_plugin_base_decide_allocation
+      (GST_VAAPI_PLUGIN_BASE (agg), query);
+}
+
+static GstVaapiBlendSurface *
+gst_vaapi_overlay_surface_next (gpointer data)
+{
+  GstVaapiOverlaySurfaceGenerator *generator;
+  GstVideoAggregatorPad *vagg_pad;
+  GstVaapiOverlaySinkPad *pad;
+  GstVideoFrame *inframe;
+  GstBuffer *inbuf;
+  GstBuffer *buf;
+  GstVaapiVideoMeta *inbuf_meta;
+  GstVaapiBlendSurface *blend_surface;
+
+  generator = (GstVaapiOverlaySurfaceGenerator *) data;
+
+  /* at the end of the generator? */
+  while (generator->current) {
+    /* get the current video aggregator sinkpad */
+    vagg_pad = GST_VIDEO_AGGREGATOR_PAD (generator->current->data);
+
+    /* increment list pointer */
+    generator->current = generator->current->next;
+
+    /* recycle the blend surface from the overlay surface generator */
+    blend_surface = &generator->blend_surface;
+    blend_surface->surface = NULL;
+
+    /* Current sinkpad may not be queueing buffers yet (e.g. timestamp-offset)
+     * or it may have reached EOS */
+    if (!gst_video_aggregator_pad_has_current_buffer (vagg_pad))
+      continue;
+
+    inframe = gst_video_aggregator_pad_get_prepared_frame (vagg_pad);
+    buf = gst_video_aggregator_pad_get_current_buffer (vagg_pad);
+    pad = GST_VAAPI_OVERLAY_SINK_PAD (vagg_pad);
+
+    if (gst_vaapi_plugin_base_pad_get_input_buffer (GST_VAAPI_PLUGIN_BASE
+            (generator->overlay), GST_PAD (pad), buf, &inbuf) != GST_FLOW_OK)
+      return blend_surface;
+
+    inbuf_meta = gst_buffer_get_vaapi_video_meta (inbuf);
+    if (inbuf_meta) {
+      blend_surface->surface = gst_vaapi_video_meta_get_surface (inbuf_meta);
+      blend_surface->crop = gst_vaapi_video_meta_get_render_rect (inbuf_meta);
+      blend_surface->target.x = pad->xpos;
+      blend_surface->target.y = pad->ypos;
+      blend_surface->target.width = (pad->width == DEFAULT_PAD_WIDTH)
+          ? GST_VIDEO_FRAME_WIDTH (inframe) : pad->width;
+      blend_surface->target.height = (pad->height == DEFAULT_PAD_HEIGHT)
+          ? GST_VIDEO_FRAME_HEIGHT (inframe) : pad->height;
+      blend_surface->alpha = pad->alpha;
+    }
+
+    gst_buffer_unref (inbuf);
+    return blend_surface;
+  }
+
+  return NULL;
+}
+
+static GstFlowReturn
+gst_vaapi_overlay_aggregate_frames (GstVideoAggregator * vagg,
+    GstBuffer * outbuf)
+{
+  GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (vagg);
+  GstVaapiVideoMeta *outbuf_meta;
+  GstVaapiSurface *outbuf_surface;
+  GstVaapiSurfaceProxy *proxy;
+  GstVaapiOverlaySurfaceGenerator generator;
+
+  if (!overlay->blend_pool) {
+    GstVaapiVideoPool *pool =
+        gst_vaapi_surface_pool_new_full (GST_VAAPI_PLUGIN_BASE_DISPLAY
+        (overlay),
+        GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO (overlay), 0);
+    if (!pool)
+      return GST_FLOW_ERROR;
+    gst_vaapi_video_pool_replace (&overlay->blend_pool, pool);
+    gst_vaapi_video_pool_unref (pool);
+  }
+
+  outbuf_meta = gst_buffer_get_vaapi_video_meta (outbuf);
+  if (!outbuf_meta)
+    return GST_FLOW_ERROR;
+
+  if (!gst_vaapi_video_meta_get_surface_proxy (outbuf_meta)) {
+    proxy = gst_vaapi_surface_proxy_new_from_pool
+        (GST_VAAPI_SURFACE_POOL (overlay->blend_pool));
+    if (!proxy)
+      return GST_FLOW_ERROR;
+    gst_vaapi_video_meta_set_surface_proxy (outbuf_meta, proxy);
+    gst_vaapi_surface_proxy_unref (proxy);
+  }
+
+  outbuf_surface = gst_vaapi_video_meta_get_surface (outbuf_meta);
+
+  /* initialize the surface generator */
+  generator.overlay = overlay;
+  generator.current = GST_ELEMENT (overlay)->sinkpads;
+
+  if (!gst_vaapi_blend_process (overlay->blend, outbuf_surface,
+          gst_vaapi_overlay_surface_next, &generator))
+    return GST_FLOW_ERROR;
+
+  return GST_FLOW_OK;
+}
+
+static GstFlowReturn
+gst_vaapi_overlay_create_output_buffer (GstVideoAggregator * vagg,
+    GstBuffer ** outbuf)
+{
+  GstVaapiOverlay *const overlay = GST_VAAPI_OVERLAY (vagg);
+  GstBufferPool *const pool =
+      GST_VAAPI_PLUGIN_BASE_SRC_PAD_BUFFER_POOL (overlay);
+
+  g_return_val_if_fail (pool != NULL, GST_FLOW_ERROR);
+
+  if (!gst_buffer_pool_is_active (pool) &&
+      !gst_buffer_pool_set_active (pool, TRUE)) {
+    GST_ERROR_OBJECT (overlay, "failed to activate output video buffer pool");
+    return GST_FLOW_ERROR;
+  }
+
+  *outbuf = NULL;
+  if ((gst_buffer_pool_acquire_buffer (pool, outbuf, NULL) != GST_FLOW_OK)
+      || !*outbuf) {
+    GST_ERROR_OBJECT (overlay, "failed to create output video buffer");
+    return GST_FLOW_ERROR;
+  }
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+gst_vaapi_overlay_negotiated_src_caps (GstAggregator * agg, GstCaps * caps)
+{
+  if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (agg), NULL, caps))
+    return FALSE;
+
+  return
+      GST_AGGREGATOR_CLASS (gst_vaapi_overlay_parent_class)->negotiated_src_caps
+      (agg, caps);
+}
+
+static GstCaps *
+gst_vaapi_overlay_fixate_src_caps (GstAggregator * agg, GstCaps * caps)
+{
+  GstVideoAggregator *vagg = GST_VIDEO_AGGREGATOR (agg);
+  GList *l;
+  gint best_width = -1, best_height = -1;
+  gint best_fps_n = -1, best_fps_d = -1;
+  gdouble best_fps = 0.;
+  GstCaps *ret = NULL;
+  GstStructure *s;
+
+  ret = gst_caps_make_writable (caps);
+
+  GST_OBJECT_LOCK (vagg);
+  for (l = GST_ELEMENT (vagg)->sinkpads; l; l = l->next) {
+    GstVideoAggregatorPad *vaggpad = l->data;
+    GstVaapiOverlaySinkPad *pad = GST_VAAPI_OVERLAY_SINK_PAD (vaggpad);
+    gint this_width, this_height;
+    gint fps_n, fps_d;
+    gdouble cur_fps;
+
+    fps_n = GST_VIDEO_INFO_FPS_N (&vaggpad->info);
+    fps_d = GST_VIDEO_INFO_FPS_D (&vaggpad->info);
+
+    this_width = (pad->width == DEFAULT_PAD_WIDTH)
+        ? GST_VIDEO_INFO_WIDTH (&vaggpad->info) : pad->width;
+    this_height = (pad->height == DEFAULT_PAD_HEIGHT)
+        ? GST_VIDEO_INFO_HEIGHT (&vaggpad->info) : pad->height;
+
+    this_width += MAX (pad->xpos, 0);
+    this_height += MAX (pad->ypos, 0);
+
+    if (best_width < this_width)
+      best_width = this_width;
+    if (best_height < this_height)
+      best_height = this_height;
+
+    if (fps_d == 0)
+      cur_fps = 0.0;
+    else
+      gst_util_fraction_to_double (fps_n, fps_d, &cur_fps);
+
+    if (best_fps < cur_fps) {
+      best_fps = cur_fps;
+      best_fps_n = fps_n;
+      best_fps_d = fps_d;
+    }
+  }
+  GST_OBJECT_UNLOCK (vagg);
+
+  if (best_fps_n <= 0 || best_fps_d <= 0 || best_fps == 0.0) {
+    best_fps_n = 25;
+    best_fps_d = 1;
+    best_fps = 25.0;
+  }
+
+  s = gst_caps_get_structure (ret, 0);
+  gst_structure_fixate_field_nearest_int (s, "width", best_width);
+  gst_structure_fixate_field_nearest_int (s, "height", best_height);
+  gst_structure_fixate_field_nearest_fraction (s, "framerate", best_fps_n,
+      best_fps_d);
+
+  return gst_caps_fixate (ret);
+}
+
+static GstVaapiPadPrivate *
+gst_vaapi_overlay_get_vaapi_pad_private (GstVaapiPluginBase * plugin,
+    GstPad * pad)
+{
+  if (GST_IS_VAAPI_OVERLAY_SINK_PAD (pad))
+    return GST_VAAPI_OVERLAY_SINK_PAD (pad)->priv;
+
+  g_assert (GST_VAAPI_PLUGIN_BASE_SRC_PAD (plugin) == pad);
+  return GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE (plugin);
+}
+
+static void
+gst_vaapi_overlay_class_init (GstVaapiOverlayClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstAggregatorClass *const agg_class = GST_AGGREGATOR_CLASS (klass);
+  GstVideoAggregatorClass *const vagg_class =
+      GST_VIDEO_AGGREGATOR_CLASS (klass);
+  GstVaapiPluginBaseClass *plugin_class = GST_VAAPI_PLUGIN_BASE_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_vaapi_overlay,
+      GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
+
+  gst_vaapi_plugin_base_class_init (plugin_class);
+  plugin_class->get_vaapi_pad_private =
+      GST_DEBUG_FUNCPTR (gst_vaapi_overlay_get_vaapi_pad_private);
+
+  object_class->finalize = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_finalize);
+
+  agg_class->sink_query = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_sink_query);
+  agg_class->src_query = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_src_query);
+  agg_class->start = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_start);
+  agg_class->propose_allocation =
+      GST_DEBUG_FUNCPTR (gst_vaapi_overlay_propose_allocation);
+  agg_class->fixate_src_caps =
+      GST_DEBUG_FUNCPTR (gst_vaapi_overlay_fixate_src_caps);
+  agg_class->negotiated_src_caps =
+      GST_DEBUG_FUNCPTR (gst_vaapi_overlay_negotiated_src_caps);
+  agg_class->decide_allocation =
+      GST_DEBUG_FUNCPTR (gst_vaapi_overlay_decide_allocation);
+  agg_class->stop = GST_DEBUG_FUNCPTR (gst_vaapi_overlay_stop);
+
+  vagg_class->aggregate_frames =
+      GST_DEBUG_FUNCPTR (gst_vaapi_overlay_aggregate_frames);
+  vagg_class->create_output_buffer =
+      GST_DEBUG_FUNCPTR (gst_vaapi_overlay_create_output_buffer);
+
+  element_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_vaapi_overlay_request_new_pad);
+  element_class->release_pad =
+      GST_DEBUG_FUNCPTR (gst_vaapi_overlay_release_pad);
+  element_class->set_context = GST_DEBUG_FUNCPTR (gst_vaapi_base_set_context);
+
+  gst_element_class_add_static_pad_template_with_gtype (element_class,
+      &gst_vaapi_overlay_sink_factory, GST_TYPE_VAAPI_OVERLAY_SINK_PAD);
+
+  gst_element_class_add_static_pad_template_with_gtype (element_class,
+      &gst_vaapi_overlay_src_factory, GST_TYPE_AGGREGATOR_PAD);
+
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API overlay",
+      "Filter/Editor/Video/Compositor/Hardware",
+      GST_PLUGIN_DESC, "U. Artie Eoff <ullysses.a.eoff@intel.com>");
+}
+
+static void
+gst_vaapi_overlay_init (GstVaapiOverlay * overlay)
+{
+  gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (overlay), GST_CAT_DEFAULT);
+}
+
+/* GstChildProxy implementation */
+static GObject *
+gst_vaapi_overlay_child_proxy_get_child_by_index (GstChildProxy * child_proxy,
+    guint index)
+{
+  GstVaapiOverlay *overlay = GST_VAAPI_OVERLAY (child_proxy);
+  GObject *obj = NULL;
+
+  GST_OBJECT_LOCK (overlay);
+  obj = g_list_nth_data (GST_ELEMENT_CAST (overlay)->sinkpads, index);
+  if (obj)
+    gst_object_ref (obj);
+  GST_OBJECT_UNLOCK (overlay);
+
+  return obj;
+}
+
+static guint
+gst_vaapi_overlay_child_proxy_get_children_count (GstChildProxy * child_proxy)
+{
+  guint count = 0;
+  GstVaapiOverlay *overlay = GST_VAAPI_OVERLAY (child_proxy);
+
+  GST_OBJECT_LOCK (overlay);
+  count = GST_ELEMENT_CAST (overlay)->numsinkpads;
+  GST_OBJECT_UNLOCK (overlay);
+
+  return count;
+}
+
+static void
+gst_vaapi_overlay_child_proxy_init (gpointer g_iface, gpointer iface_data)
+{
+  GstChildProxyInterface *iface = g_iface;
+
+  iface->get_child_by_index = gst_vaapi_overlay_child_proxy_get_child_by_index;
+  iface->get_children_count = gst_vaapi_overlay_child_proxy_get_children_count;
+}
+
+gboolean
+gst_vaapioverlay_register (GstPlugin * plugin, GstVaapiDisplay * display)
+{
+  GstVaapiBlend *blend = NULL;
+
+  blend = gst_vaapi_blend_new (display);
+  if (!blend)
+    return FALSE;
+  gst_vaapi_blend_replace (&blend, NULL);
+
+  return gst_element_register (plugin, "vaapioverlay", GST_RANK_NONE,
+      GST_TYPE_VAAPI_OVERLAY);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapioverlay.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapioverlay.h
new file mode 100644 (file)
index 0000000..dcb4ea2
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ *  gstvaapioverlay.h - VA-API vpp overlay
+ *
+ *  Copyright (C) 2019 Intel Corporation
+ *    Author: U. Artie Eoff <ullysses.a.eoff@intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+*/
+
+#ifndef GST_VAAPI_OVERLAY_H
+#define GST_VAAPI_OVERLAY_H
+
+#include "gstvaapipluginbase.h"
+#include <gst/vaapi/gstvaapisurfacepool.h>
+#include <gst/vaapi/gstvaapiblend.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPI_OVERLAY (gst_vaapi_overlay_get_type ())
+#define GST_VAAPI_OVERLAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_OVERLAY, GstVaapiOverlay))
+#define GST_VAAPI_OVERLAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_OVERLAY, \
+      GstVaapiOverlayClass))
+#define GST_IS_VAAPI_OVERLAY(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_OVERLAY))
+#define GST_IS_VAAPI_OVERLAY_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_OVERLAY))
+#define GST_VAAPI_OVERLAY_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPI_OVERLAY, \
+      GstVaapiOverlayClass))
+
+#define GST_TYPE_VAAPI_OVERLAY_SINK_PAD (gst_vaapi_overlay_sink_pad_get_type())
+#define GST_VAAPI_OVERLAY_SINK_PAD(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPI_OVERLAY_SINK_PAD, \
+      GstVaapiOverlaySinkPad))
+#define GST_VAAPI_OVERLAY_SINK_PAD_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPI_OVERLAY_SINK_PAD, \
+      GstVaapiOverlaySinkPadClass))
+#define GST_IS_VAAPI_OVERLAY_SINK_PAD(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPI_OVERLAY_SINK_PAD))
+#define GST_IS_VAAPI_OVERLAY_SINK_PAD_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPI_OVERLAY_SINK_PAD))
+
+typedef struct _GstVaapiOverlay GstVaapiOverlay;
+typedef struct _GstVaapiOverlayClass GstVaapiOverlayClass;
+
+typedef struct _GstVaapiOverlaySinkPad GstVaapiOverlaySinkPad;
+typedef struct _GstVaapiOverlaySinkPadClass GstVaapiOverlaySinkPadClass;
+
+struct _GstVaapiOverlay
+{
+  GstVaapiPluginBase parent_instance;
+
+  GstVaapiBlend *blend;
+  GstVaapiVideoPool *blend_pool;
+};
+
+struct _GstVaapiOverlayClass
+{
+  GstVaapiPluginBaseClass parent_class;
+};
+
+struct _GstVaapiOverlaySinkPad
+{
+  GstVideoAggregatorPad parent_instance;
+
+  gint xpos, ypos;
+  gint width, height;
+  gdouble alpha;
+
+  GstVaapiPadPrivate *priv;
+};
+
+struct _GstVaapiOverlaySinkPadClass
+{
+  GstVideoAggregatorPadClass parent_class;
+};
+
+GType
+gst_vaapi_overlay_get_type (void) G_GNUC_CONST;
+
+GType
+gst_vaapi_overlay_sink_pad_get_type (void) G_GNUC_CONST;
+
+gboolean
+gst_vaapioverlay_register (GstPlugin * plugin, GstVaapiDisplay * display);
+
+G_END_DECLS
+
+#endif
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginbase.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginbase.c
new file mode 100644 (file)
index 0000000..9b713b5
--- /dev/null
@@ -0,0 +1,1607 @@
+/*
+ *  gstvaapipluginbase.c - Base GStreamer VA-API Plugin element
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapisurface_drm.h>
+#include <gst/base/gstpushsrc.h>
+#include "gstvaapipluginbase.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideocontext.h"
+#include "gstvaapivideometa.h"
+#include "gstvaapivideobufferpool.h"
+#if USE_GST_GL_HELPERS
+# include <gst/gl/gl.h>
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
+/* Default debug category is from the subclass */
+#define GST_CAT_DEFAULT (plugin->debug_category)
+
+#define BUFFER_POOL_SINK_MIN_BUFFERS 2
+
+#define GST_VAAPI_PAD_PRIVATE(pad) \
+  (GST_VAAPI_PLUGIN_BASE_GET_CLASS(plugin)->get_vaapi_pad_private(plugin, pad))
+
+GstVaapiPadPrivate *
+gst_vaapi_pad_private_new (void)
+{
+  GstVaapiPadPrivate *priv = g_new0 (GstVaapiPadPrivate, 1);
+
+  gst_video_info_init (&priv->info);
+
+  return priv;
+}
+
+void
+gst_vaapi_pad_private_reset (GstVaapiPadPrivate * priv)
+{
+  g_assert (priv);
+
+  gst_caps_replace (&priv->caps, NULL);
+  gst_video_info_init (&priv->info);
+
+  gst_clear_object (&priv->buffer_pool);
+  gst_clear_object (&priv->allocator);
+
+  priv->buffer_size = 0;
+  priv->caps_is_raw = FALSE;
+
+  gst_clear_object (&priv->other_allocator);
+}
+
+void
+gst_vaapi_pad_private_finalize (GstVaapiPadPrivate * priv)
+{
+  gst_vaapi_pad_private_reset (priv);
+  g_free (priv);
+}
+
+/* GstVideoContext interface */
+static void
+plugin_set_display (GstVaapiPluginBase * plugin, GstVaapiDisplay * display)
+{
+  const gchar *const display_name =
+      gst_vaapi_display_get_display_name (display);
+
+  if (plugin->display_name && g_strcmp0 (plugin->display_name, display_name)) {
+    GST_DEBUG_OBJECT (plugin, "incompatible display name '%s', requested '%s'",
+        display_name, plugin->display_name);
+    gst_vaapi_display_replace (&plugin->display, NULL);
+  } else {
+    GST_INFO_OBJECT (plugin, "set display %" GST_PTR_FORMAT, display);
+    gst_vaapi_display_replace (&plugin->display, display);
+    plugin->display_type = gst_vaapi_display_get_display_type (display);
+    gst_vaapi_plugin_base_set_display_name (plugin, display_name);
+  }
+  gst_object_unref (display);
+}
+
+/**
+ * gst_vaapi_plugin_base_set_context:
+ * @plugin: a #GstVaapiPluginBase instance
+ * @context: a #GstContext to set
+ *
+ * This is a common set_context() element's vmethod for all the
+ * GStreamer VA-API elements.
+ *
+ * It normally should be used through the macro
+ * #GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT()
+ **/
+void
+gst_vaapi_plugin_base_set_context (GstVaapiPluginBase * plugin,
+    GstContext * context)
+{
+  GstVaapiDisplay *display = NULL;
+
+  /* gst.vaapi.app.Display is only attended _if_ the element is
+   * vaapisink and it doesn't have a display set yet */
+  if (gst_vaapi_video_context_get_display (context,
+          GST_IS_VIDEO_SINK (plugin) && !plugin->display, &display)) {
+    plugin_set_display (plugin, display);
+  }
+#if USE_GST_GL_HELPERS
+  gst_gl_handle_set_context (GST_ELEMENT_CAST (plugin), context,
+      (GstGLDisplay **) & plugin->gl_display,
+      (GstGLContext **) & plugin->gl_other_context);
+#endif
+}
+
+void
+gst_vaapi_plugin_base_init_interfaces (GType g_define_type_id)
+{
+}
+
+static gboolean
+default_has_interface (GstVaapiPluginBase * plugin, GType type)
+{
+  return FALSE;
+}
+
+static void
+default_display_changed (GstVaapiPluginBase * plugin)
+{
+}
+
+static GstVaapiSurface *
+_get_cached_surface (GstBuffer * buf)
+{
+  return gst_mini_object_get_qdata (GST_MINI_OBJECT (buf),
+      g_quark_from_static_string ("GstVaapiDMABufSurface"));
+}
+
+static void
+_set_cached_surface (GstBuffer * buf, GstVaapiSurface * surface)
+{
+  return gst_mini_object_set_qdata (GST_MINI_OBJECT (buf),
+      g_quark_from_static_string ("GstVaapiDMABufSurface"), surface,
+      (GDestroyNotify) gst_vaapi_surface_unref);
+}
+
+static gboolean
+plugin_update_sinkpad_info_from_buffer (GstVaapiPluginBase * plugin,
+    GstPad * sinkpad, GstBuffer * buf)
+{
+  GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad);
+  GstVideoInfo *const vip = &sinkpriv->info;
+  GstVideoMeta *vmeta;
+  guint i;
+
+  vmeta = gst_buffer_get_video_meta (buf);
+  if (!vmeta)
+    return TRUE;
+
+  if (GST_VIDEO_INFO_FORMAT (vip) != vmeta->format ||
+      GST_VIDEO_INFO_WIDTH (vip) != vmeta->width ||
+      GST_VIDEO_INFO_HEIGHT (vip) != vmeta->height ||
+      GST_VIDEO_INFO_N_PLANES (vip) != vmeta->n_planes)
+    return FALSE;
+
+  for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); ++i) {
+    GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = vmeta->offset[i];
+    GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = vmeta->stride[i];
+  }
+  GST_VIDEO_INFO_SIZE (vip) = gst_buffer_get_size (buf);
+  return TRUE;
+}
+
+static gboolean
+is_dma_buffer (GstBuffer * buf)
+{
+  GstMemory *mem;
+
+  if (gst_buffer_n_memory (buf) < 1)
+    return FALSE;
+
+  mem = gst_buffer_peek_memory (buf, 0);
+  if (!mem || !gst_is_dmabuf_memory (mem))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+plugin_bind_dma_to_vaapi_buffer (GstVaapiPluginBase * plugin, GstPad * sinkpad,
+    GstBuffer * inbuf, GstBuffer * outbuf)
+{
+  GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad);
+  GstVideoInfo *const vip = &sinkpriv->info;
+  GstVaapiVideoMeta *meta;
+  GstVaapiSurface *surface;
+  GstVaapiSurfaceProxy *proxy;
+  gint fd;
+
+  fd = gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (inbuf, 0));
+  if (fd < 0)
+    return FALSE;
+
+  if (!plugin_update_sinkpad_info_from_buffer (plugin, sinkpad, inbuf))
+    goto error_update_sinkpad_info;
+
+  meta = gst_buffer_get_vaapi_video_meta (outbuf);
+  g_return_val_if_fail (meta != NULL, FALSE);
+
+  /* Check for a VASurface cached in the buffer */
+  surface = _get_cached_surface (inbuf);
+  if (!surface) {
+    /* otherwise create one and cache it */
+    surface =
+        gst_vaapi_surface_new_with_dma_buf_handle (plugin->display, fd, vip);
+    if (!surface)
+      goto error_create_surface;
+    _set_cached_surface (inbuf, surface);
+  }
+
+  proxy = gst_vaapi_surface_proxy_new (surface);
+  if (!proxy)
+    goto error_create_proxy;
+  gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
+  gst_vaapi_surface_proxy_unref (proxy);
+  gst_buffer_add_parent_buffer_meta (outbuf, inbuf);
+  return TRUE;
+
+  /* ERRORS */
+error_update_sinkpad_info:
+  {
+    GST_ERROR_OBJECT (plugin,
+        "failed to update sink pad video info from video meta");
+    return FALSE;
+  }
+error_create_surface:
+  {
+    GST_ERROR_OBJECT (plugin,
+        "failed to create VA surface from dma_buf handle");
+    return FALSE;
+  }
+error_create_proxy:
+  {
+    GST_ERROR_OBJECT (plugin,
+        "failed to create VA surface proxy from wrapped VA surface");
+    return FALSE;
+  }
+}
+
+static void
+plugin_reset_texture_map (GstVaapiPluginBase * plugin)
+{
+  if (plugin->display)
+    gst_vaapi_display_reset_texture_map (plugin->display);
+}
+
+static GstVaapiPadPrivate *
+default_get_vaapi_pad_private (GstVaapiPluginBase * plugin, GstPad * pad)
+{
+  if (plugin->sinkpad == pad)
+    return plugin->sinkpriv;
+
+  g_assert (plugin->srcpad == pad);
+  return plugin->srcpriv;
+}
+
+void
+gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass)
+{
+  klass->has_interface = default_has_interface;
+  klass->display_changed = default_display_changed;
+  klass->get_vaapi_pad_private = default_get_vaapi_pad_private;
+}
+
+void
+gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin,
+    GstDebugCategory * debug_category)
+{
+  plugin->debug_category = debug_category;
+  plugin->display_type = GST_VAAPI_DISPLAY_TYPE_ANY;
+  plugin->display_type_req = GST_VAAPI_DISPLAY_TYPE_ANY;
+
+  /* sink pad */
+  plugin->sinkpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "sink");
+
+  if (plugin->sinkpad)
+    plugin->sinkpriv = gst_vaapi_pad_private_new ();
+
+  /* src pad */
+  if (!(GST_OBJECT_FLAGS (plugin) & GST_ELEMENT_FLAG_SINK))
+    plugin->srcpad = gst_element_get_static_pad (GST_ELEMENT (plugin), "src");
+
+  if (plugin->srcpad)
+    plugin->srcpriv = gst_vaapi_pad_private_new ();
+
+  plugin->enable_direct_rendering =
+      (g_getenv ("GST_VAAPI_ENABLE_DIRECT_RENDERING") != NULL);
+}
+
+void
+gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin)
+{
+  gst_vaapi_plugin_base_close (plugin);
+  gst_vaapi_display_replace (&plugin->display, NULL);
+  g_free (plugin->display_name);
+
+  if (plugin->sinkpriv)
+    gst_vaapi_pad_private_finalize (plugin->sinkpriv);
+  if (plugin->srcpriv)
+    gst_vaapi_pad_private_finalize (plugin->srcpriv);
+
+  if (plugin->sinkpad)
+    gst_object_unref (plugin->sinkpad);
+  if (plugin->srcpad)
+    gst_object_unref (plugin->srcpad);
+}
+
+/**
+ * gst_vaapi_plugin_base_open:
+ * @plugin: a #GstVaapiPluginBase
+ *
+ * Allocates any internal resources needed for correct operation from
+ * the subclass.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin)
+{
+  gst_caps_replace (&plugin->allowed_raw_caps, NULL);
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_plugin_base_close:
+ * @plugin: a #GstVaapiPluginBase
+ *
+ * Deallocates all internal resources that were allocated so
+ * far. i.e. put the base plugin object into a clean state.
+ */
+void
+gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin)
+{
+  /* Release vaapi textures first if exist, which refs display object */
+  plugin_reset_texture_map (plugin);
+
+  gst_object_replace (&plugin->gl_context, NULL);
+  gst_object_replace (&plugin->gl_display, NULL);
+  gst_object_replace (&plugin->gl_other_context, NULL);
+
+  gst_caps_replace (&plugin->allowed_raw_caps, NULL);
+
+  if (plugin->sinkpriv)
+    gst_vaapi_pad_private_reset (plugin->sinkpriv);
+  if (plugin->srcpriv)
+    gst_vaapi_pad_private_reset (plugin->srcpriv);
+}
+
+/**
+ * gst_vaapi_plugin_base_has_display_type:
+ * @plugin: a #GstVaapiPluginBase
+ * @display_type_req: the desired #GstVaapiDisplayType
+ *
+ * Checks whether the @plugin elements already has a #GstVaapiDisplay
+ * instance compatible with type @display_type_req.
+ *
+ * Return value: %TRUE if @plugin has a compatible display, %FALSE otherwise
+ */
+gboolean
+gst_vaapi_plugin_base_has_display_type (GstVaapiPluginBase * plugin,
+    GstVaapiDisplayType display_type_req)
+{
+  GstVaapiDisplayType display_type;
+
+  if (!plugin->display)
+    return FALSE;
+
+  display_type = plugin->display_type;
+  if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
+    return TRUE;
+
+  display_type = gst_vaapi_display_get_class_type (plugin->display);
+  if (gst_vaapi_display_type_is_compatible (display_type, display_type_req))
+    return TRUE;
+  return FALSE;
+}
+
+/**
+ * gst_vaapi_plugin_base_set_display_type:
+ * @plugin: a #GstVaapiPluginBase
+ * @display_type: the new request #GstVaapiDisplayType
+ *
+ * Requests a new display type. The change is effective at the next
+ * call to gst_vaapi_plugin_base_ensure_display().
+ */
+void
+gst_vaapi_plugin_base_set_display_type (GstVaapiPluginBase * plugin,
+    GstVaapiDisplayType display_type)
+{
+  plugin->display_type_req = display_type;
+}
+
+/**
+ * gst_vaapi_plugin_base_set_display_name:
+ * @plugin: a #GstVaapiPluginBase
+ * @display_name: the new display name to match
+ *
+ * Sets the name of the display to look for. The change is effective
+ * at the next call to gst_vaapi_plugin_base_ensure_display().
+ */
+void
+gst_vaapi_plugin_base_set_display_name (GstVaapiPluginBase * plugin,
+    const gchar * display_name)
+{
+  g_free (plugin->display_name);
+  plugin->display_name = g_strdup (display_name);
+}
+
+/**
+ * gst_vaapi_plugin_base_ensure_display:
+ * @plugin: a #GstVaapiPluginBase
+ *
+ * Ensures the display stored in @plugin complies with the requested
+ * display type constraints.
+ *
+ * Returns: %TRUE if the display was created to match the requested
+ *   type, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin)
+{
+  if (gst_vaapi_plugin_base_has_display_type (plugin, plugin->display_type_req))
+    return TRUE;
+  gst_vaapi_display_replace (&plugin->display, NULL);
+
+  if (!gst_vaapi_ensure_display (GST_ELEMENT (plugin),
+          plugin->display_type_req))
+    return FALSE;
+  plugin->display_type = gst_vaapi_display_get_display_type (plugin->display);
+
+  GST_VAAPI_PLUGIN_BASE_GET_CLASS (plugin)->display_changed (plugin);
+  return TRUE;
+}
+
+static gboolean
+gst_vaapi_buffer_pool_caps_is_equal (GstBufferPool * pool, GstCaps * newcaps)
+{
+  GstStructure *config;
+  GstCaps *caps;
+  gboolean ret;
+
+  caps = NULL;
+  ret = FALSE;
+  config = gst_buffer_pool_get_config (pool);
+  if (gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
+    ret = gst_caps_is_equal (newcaps, caps);
+  gst_structure_free (config);
+
+  return ret;
+}
+
+static inline gboolean
+reset_allocator (GstAllocator * allocator, GstVideoInfo * vinfo)
+{
+  const GstVideoInfo *orig_vi;
+
+  if (!allocator)
+    return TRUE;
+
+  orig_vi = gst_allocator_get_vaapi_video_info (allocator, NULL);
+  if (!gst_video_info_changed (orig_vi, vinfo))
+    return FALSE;
+
+  gst_object_unref (allocator);
+  return TRUE;
+}
+
+static gboolean
+ensure_sinkpad_allocator (GstVaapiPluginBase * plugin, GstPad * sinkpad,
+    GstCaps * caps, guint * size)
+{
+  GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad);
+  GstVideoInfo vinfo;
+  const GstVideoInfo *image_info;
+  GstVaapiImageUsageFlags usage_flag =
+      GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
+
+  if (!gst_video_info_from_caps (&vinfo, caps))
+    goto error_invalid_caps;
+
+  if (!reset_allocator (sinkpriv->allocator, &vinfo))
+    goto bail;
+
+  /* enable direct upload if upstream requests raw video */
+  if (gst_caps_is_video_raw (caps)) {
+    usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD;
+    GST_INFO_OBJECT (plugin, "enabling direct upload in sink allocator");
+  }
+  sinkpriv->allocator =
+      gst_vaapi_video_allocator_new (plugin->display, &vinfo, 0, usage_flag);
+
+bail:
+  if (!sinkpriv->allocator)
+    goto error_create_allocator;
+
+  image_info = gst_allocator_get_vaapi_video_info (sinkpriv->allocator, NULL);
+  g_assert (image_info);        /* allocator ought set its image info */
+
+  /* update the size with the one generated by the allocator */
+  *size = GST_VIDEO_INFO_SIZE (image_info);
+
+  return TRUE;
+
+  /* ERRORS */
+error_invalid_caps:
+  {
+    GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+error_create_allocator:
+  {
+    GST_ERROR_OBJECT (plugin, "failed to create sink pad's allocator");
+    return FALSE;
+  }
+}
+
+static inline guint
+get_dmabuf_surface_allocation_flags (void)
+{
+  /* @FIXME: fetch the real devices ids */
+  /* Pair vendor/device identifies an unique physical device. */
+  guint va_vendor_id = 0x00;
+  guint va_device_id = 0x00;
+  guint gl_vendor_id = 0x00;
+  guint gl_device_id = 0x00;
+
+  /* Requires linear memory only if fd export is done on a different
+   * device than the device where the fd is imported. */
+  gboolean same_physical_device = va_vendor_id == gl_vendor_id
+      && va_device_id == gl_device_id;
+
+  if (same_physical_device)
+    return 0;
+  return GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE;
+}
+
+static inline GstAllocator *
+create_dmabuf_srcpad_allocator (GstVaapiPluginBase * plugin,
+    GstVideoInfo * vinfo, gboolean check_for_map)
+{
+  GstAllocator *allocator;
+
+  if (!GST_IS_VIDEO_DECODER (plugin) && !GST_IS_BASE_TRANSFORM (plugin))
+    return NULL;
+
+  allocator = gst_vaapi_dmabuf_allocator_new (plugin->display, vinfo,
+      get_dmabuf_surface_allocation_flags (), GST_PAD_SRC);
+  if (!allocator || !check_for_map)
+    return allocator;
+
+  /* the dmabuf allocator *must* be capable to map a buffer with raw
+   * caps and the there's no evidence of downstream dmabuf
+   * importation */
+  if (!gst_vaapi_dmabuf_can_map (plugin->display, allocator)) {
+    GST_INFO_OBJECT (plugin, "dmabuf allocator generates unmappable buffers");
+    gst_object_replace ((GstObject **) & allocator, NULL);
+  }
+
+  return allocator;
+}
+
+static gboolean
+ensure_srcpad_allocator (GstVaapiPluginBase * plugin, GstPad * srcpad,
+    GstVideoInfo * vinfo, GstCaps * caps)
+{
+  GstVaapiPadPrivate *srcpriv = GST_VAAPI_PAD_PRIVATE (srcpad);
+  const GstVideoInfo *image_info;
+
+  if (!reset_allocator (srcpriv->allocator, vinfo))
+    goto valid_allocator;
+
+  srcpriv->allocator = NULL;
+  if (caps && gst_vaapi_caps_feature_contains (caps,
+          GST_VAAPI_CAPS_FEATURE_DMABUF)) {
+    srcpriv->allocator = create_dmabuf_srcpad_allocator (plugin, vinfo, FALSE);
+    if (!srcpriv->allocator)
+      goto error_create_allocator;
+  }
+
+  if (!srcpriv->allocator) {
+    GstVaapiImageUsageFlags usage_flag =
+        GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
+
+    if (plugin->enable_direct_rendering) {
+      usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER;
+      GST_INFO_OBJECT (plugin, "enabling direct rendering in source allocator");
+    }
+
+    srcpriv->allocator =
+        gst_vaapi_video_allocator_new (plugin->display, vinfo, 0, usage_flag);
+  }
+
+  if (!srcpriv->allocator)
+    goto error_create_allocator;
+
+valid_allocator:
+  image_info = gst_allocator_get_vaapi_video_info (srcpriv->allocator, NULL);
+  g_assert (image_info);        /* both allocators ought set its image
+                                 * info */
+
+  /* update the size with the one generated by the allocator */
+  GST_VIDEO_INFO_SIZE (vinfo) = GST_VIDEO_INFO_SIZE (image_info);
+
+  if (GST_IS_VIDEO_DECODER (plugin)) {
+    /* the received caps are the "allocation caps" which may be
+     * different from the "negotiation caps". In this case, we should
+     * indicate the allocator to store the negotiation caps since they
+     * are the one should be used for frame mapping with GstVideoMeta */
+    gboolean different_caps = srcpriv->caps &&
+        !gst_caps_is_strictly_equal (srcpriv->caps, caps);
+    const GstVideoInfo *previous_negotiated =
+        gst_allocator_get_vaapi_negotiated_video_info (srcpriv->allocator);
+
+    if (different_caps) {
+      guint i;
+      GstVideoInfo vi = srcpriv->info;
+
+      /* update the planes and the size with the allocator image/surface
+       * info, but not the resolution */
+      for (i = 0; i < GST_VIDEO_INFO_N_PLANES (image_info); i++) {
+        GST_VIDEO_INFO_PLANE_OFFSET (&vi, i) =
+            GST_VIDEO_INFO_PLANE_OFFSET (image_info, i);
+        GST_VIDEO_INFO_PLANE_STRIDE (&vi, i) =
+            GST_VIDEO_INFO_PLANE_STRIDE (image_info, i);
+      }
+      GST_VIDEO_INFO_SIZE (&vi) = GST_VIDEO_INFO_SIZE (image_info);
+      gst_allocator_set_vaapi_negotiated_video_info (srcpriv->allocator, &vi);
+    } else if (previous_negotiated) {
+      gst_allocator_set_vaapi_negotiated_video_info (srcpriv->allocator, NULL);
+    }
+  }
+  return TRUE;
+
+  /* ERRORS */
+error_create_allocator:
+  {
+    GST_ERROR_OBJECT (plugin, "failed to create src pad's allocator");
+    return FALSE;
+  }
+}
+
+/**
+ * gst_vaapi_plugin_base_create_pool:
+ * @plugin: a #GstVaapiPluginBase
+ * @caps: the initial #GstCaps for the resulting buffer pool
+ * @size: the size of each buffer, not including prefix and padding
+ * @options: a set of #GstVaapiVideoBufferPoolOption encoded as bit-wise
+ * @allocator: (allow-none): the #GstAllocator to use or %NULL
+ *
+ * Create an instance of #GstVaapiVideoBufferPool
+ *
+ * Returns: (transfer full): a new allocated #GstBufferPool
+ **/
+static GstBufferPool *
+gst_vaapi_plugin_base_create_pool (GstVaapiPluginBase * plugin, GstCaps * caps,
+    gsize size, guint min_buffers, guint max_buffers, guint options,
+    GstAllocator * allocator)
+{
+  GstBufferPool *pool;
+  GstStructure *config;
+
+  if (!(pool = gst_vaapi_video_buffer_pool_new (plugin->display)))
+    goto error_create_pool;
+
+  config = gst_buffer_pool_get_config (pool);
+  gst_buffer_pool_config_set_params (config, caps, size, min_buffers,
+      max_buffers);
+  gst_buffer_pool_config_add_option (config,
+      GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META);
+  if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) {
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_META);
+  }
+  if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT) {
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT);
+  }
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+  if (options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) {
+    gst_buffer_pool_config_add_option (config,
+        GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META);
+  }
+#endif
+  if (allocator)
+    gst_buffer_pool_config_set_allocator (config, allocator, NULL);
+  if (!gst_buffer_pool_set_config (pool, config)) {
+    config = gst_buffer_pool_get_config (pool);
+
+    if (!gst_buffer_pool_config_validate_params (config, caps, size,
+            min_buffers, max_buffers)) {
+      gst_structure_free (config);
+      goto error_pool_config;
+    }
+
+    if (!gst_buffer_pool_set_config (pool, config))
+      goto error_pool_config;
+  }
+  return pool;
+
+  /* ERRORS */
+error_create_pool:
+  {
+    GST_ERROR_OBJECT (plugin, "failed to create buffer pool");
+    return NULL;
+  }
+error_pool_config:
+  {
+    gst_object_unref (pool);
+    GST_ELEMENT_ERROR (plugin, RESOURCE, SETTINGS,
+        ("Failed to configure the buffer pool"),
+        ("Configuration is most likely invalid, please report this issue."));
+    return NULL;
+  }
+}
+
+/**
+ * ensure_sinkpad_buffer_pool:
+ * @plugin: a #GstVaapiPluginBase
+ * @sinkpad: the #GstPad to use for the resulting buffer pool
+ *
+ * Makes sure the sink pad video buffer pool is created with the
+ * appropriate caps defined in the @sinkpad.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+static gboolean
+ensure_sinkpad_buffer_pool (GstVaapiPluginBase * plugin, GstPad * sinkpad)
+{
+  GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad);
+  GstCaps *caps = sinkpriv->caps;
+  GstBufferPool *pool;
+  guint size;
+
+  /* video decoders don't use a buffer pool in the sink pad */
+  if (GST_IS_VIDEO_DECODER (plugin))
+    return TRUE;
+
+  if (!gst_vaapi_plugin_base_ensure_display (plugin))
+    return FALSE;
+
+  if (sinkpriv->buffer_pool) {
+    if (gst_vaapi_buffer_pool_caps_is_equal (sinkpriv->buffer_pool, caps))
+      return TRUE;
+    gst_buffer_pool_set_active (sinkpriv->buffer_pool, FALSE);
+    gst_clear_object (&sinkpriv->buffer_pool);
+    gst_clear_object (&sinkpriv->allocator);
+    sinkpriv->buffer_size = 0;
+  }
+
+  if (!ensure_sinkpad_allocator (plugin, sinkpad, caps, &size))
+    return FALSE;
+
+  pool =
+      gst_vaapi_plugin_base_create_pool (plugin, caps, size,
+      BUFFER_POOL_SINK_MIN_BUFFERS, 0,
+      GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META, sinkpriv->allocator);
+  if (!pool)
+    return FALSE;
+
+  sinkpriv->buffer_pool = pool;
+  sinkpriv->buffer_size = size;
+  return TRUE;
+}
+
+static gboolean
+_set_srcpad_caps (GstVaapiPluginBase * plugin, GstPad * srcpad, GstCaps * caps)
+{
+  GstVaapiPadPrivate *srcpriv = NULL;
+
+  if (caps) {
+    g_assert (srcpad);
+    srcpriv = GST_VAAPI_PAD_PRIVATE (srcpad);
+    g_assert (srcpriv);
+
+    if (caps != srcpriv->caps) {
+      if (!gst_video_info_from_caps (&srcpriv->info, caps))
+        return FALSE;
+      if (srcpriv->buffer_pool
+          && !gst_vaapi_buffer_pool_caps_is_equal (srcpriv->buffer_pool,
+              caps)) {
+        gst_buffer_pool_set_active (srcpriv->buffer_pool, FALSE);
+        gst_clear_object (&srcpriv->buffer_pool);
+        gst_clear_object (&srcpriv->allocator);
+        plugin_reset_texture_map (plugin);
+      }
+      gst_caps_replace (&srcpriv->caps, caps);
+    }
+  }
+
+  return TRUE;
+}
+
+static gboolean
+_set_sinkpad_caps (GstVaapiPluginBase * plugin, GstPad * sinkpad,
+    GstCaps * caps)
+{
+  GstVaapiPadPrivate *sinkpriv = NULL;
+
+  if (caps) {
+    g_assert (sinkpad);
+    sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad);
+    g_assert (sinkpriv);
+
+    if (caps != sinkpriv->caps) {
+      if (!gst_video_info_from_caps (&sinkpriv->info, caps))
+        return FALSE;
+      gst_caps_replace (&sinkpriv->caps, caps);
+      sinkpriv->caps_is_raw = !gst_caps_has_vaapi_surface (caps);
+    }
+
+    if (!ensure_sinkpad_buffer_pool (plugin, sinkpad))
+      return FALSE;
+  }
+
+  return TRUE;
+}
+
+/**
+ * gst_vaapi_plugin_base_pad_set_caps:
+ * @plugin: a #GstVaapiPluginBase
+ * @sinkpad: the sink pad to set @incaps on
+ * @incaps: the sink pad (input) caps
+ * @srcpad: the src pad to set @outcaps on
+ * @outcaps: the src pad (output) caps
+ *
+ * Notifies the base plugin object of the new input and output caps,
+ * obtained from the subclass on the requested pads.
+ *
+ * Returns: %TRUE if the update of caps was successful, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_plugin_base_pad_set_caps (GstVaapiPluginBase * plugin,
+    GstPad * sinkpad, GstCaps * incaps, GstPad * srcpad, GstCaps * outcaps)
+{
+  return _set_sinkpad_caps (plugin, sinkpad, incaps)
+      && _set_srcpad_caps (plugin, srcpad, outcaps);
+}
+
+/**
+ * gst_vaapi_plugin_base_set_caps:
+ * @plugin: a #GstVaapiPluginBase
+ * @incaps: the sink pad (input) caps
+ * @outcaps: the src pad (output) caps
+ *
+ * Notifies the base plugin object of the new input and output caps,
+ * obtained from the subclass, on the base plugin static pads.
+ *
+ * Returns: %TRUE if the update of caps was successful, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
+    GstCaps * outcaps)
+{
+  return gst_vaapi_plugin_base_pad_set_caps (plugin, plugin->sinkpad, incaps,
+      plugin->srcpad, outcaps);
+}
+
+/**
+ * gst_vaapi_plugin_base_pad_propose_allocation:
+ * @plugin: a #GstVaapiPluginBase
+ * @sinkpad: the sinkpad to configure the allocation query on
+ * @query: the allocation query to configure
+ *
+ * Proposes allocation parameters to the upstream elements on the requested
+ * sinkpad.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_plugin_base_pad_propose_allocation (GstVaapiPluginBase * plugin,
+    GstPad * sinkpad, GstQuery * query)
+{
+  GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad);
+  GstCaps *caps = NULL;
+  GstBufferPool *pool = NULL;
+  gboolean need_pool;
+  guint size = 0, n_allocators;
+
+  gst_query_parse_allocation (query, &caps, &need_pool);
+  if (!caps)
+    goto error_no_caps;
+
+  if (!ensure_sinkpad_allocator (plugin, sinkpad, caps, &size))
+    return FALSE;
+
+  if (need_pool) {
+    pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size,
+        BUFFER_POOL_SINK_MIN_BUFFERS, 0,
+        GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META, sinkpriv->allocator);
+    if (!pool)
+      return FALSE;
+  }
+
+  /* Set sinkpad allocator as the last allocation param.
+   *
+   * If there's none, set system's allocator first and VAAPI allocator
+   * second
+   */
+  n_allocators = gst_query_get_n_allocation_params (query);
+  if (n_allocators == 0) {
+    GstAllocator *allocator;
+
+    allocator = gst_allocator_find (GST_ALLOCATOR_SYSMEM);
+    gst_query_add_allocation_param (query, allocator, NULL);
+    gst_object_unref (allocator);
+  }
+  gst_query_add_allocation_param (query, sinkpriv->allocator, NULL);
+
+  gst_query_add_allocation_pool (query, pool, size,
+      BUFFER_POOL_SINK_MIN_BUFFERS, 0);
+  if (pool)
+    gst_object_unref (pool);
+
+  gst_query_add_allocation_meta (query, GST_VAAPI_VIDEO_META_API_TYPE, NULL);
+  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL);
+  return TRUE;
+
+  /* ERRORS */
+error_no_caps:
+  {
+    GST_INFO_OBJECT (plugin, "no caps specified");
+    return FALSE;
+  }
+}
+
+/**
+ * gst_vaapi_plugin_base_propose_allocation:
+ * @plugin: a #GstVaapiPluginBase
+ * @query: the allocation query to configure
+ *
+ * Proposes allocation parameters to the upstream elements on the base plugin
+ * static sinkpad.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin,
+    GstQuery * query)
+{
+  return gst_vaapi_plugin_base_pad_propose_allocation (plugin, plugin->sinkpad,
+      query);
+}
+
+/**
+ * gst_vaapi_plugin_base_decide_allocation:
+ * @plugin: a #GstVaapiPluginBase
+ * @query: the allocation query to parse
+ * @feature: the desired #GstVaapiCapsFeature, or zero to find the
+ *   preferred one
+ *
+ * Decides allocation parameters for the downstream elements on the base
+ * plugin static srcpad.
+ *
+ * Returns: %TRUE if successful, %FALSE otherwise.
+ */
+gboolean
+gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin,
+    GstQuery * query)
+{
+  GstVaapiPadPrivate *srcpriv = GST_VAAPI_PAD_PRIVATE (plugin->srcpad);
+  GstCaps *caps = NULL;
+  GstBufferPool *pool;
+  GstVideoInfo vi;
+  guint i, size, min, max, pool_options, num_allocators;
+  gint index_allocator;
+  gboolean update_pool = FALSE;
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+  guint idx;
+#endif
+
+  gst_query_parse_allocation (query, &caps, NULL);
+  if (!caps)
+    goto error_no_caps;
+
+  pool_options = 0;
+  if (gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL))
+    pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META;
+
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+  if (gst_query_find_allocation_meta (query,
+          GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx) &&
+      gst_vaapi_caps_feature_contains (caps,
+          GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META))
+    pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD;
+
+#if USE_GST_GL_HELPERS
+  if (!plugin->gl_context &&
+      (pool_options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD)) {
+    const GstStructure *params;
+    GstObject *gl_context;
+
+    gst_query_parse_nth_allocation_meta (query, idx, &params);
+    if (params) {
+      if (gst_structure_get (params, "gst.gl.GstGLContext", GST_TYPE_GL_CONTEXT,
+              &gl_context, NULL) && gl_context) {
+        gst_vaapi_plugin_base_set_gl_context (plugin, gl_context);
+        gst_vaapi_plugin_base_set_srcpad_can_dmabuf (plugin, gl_context);
+        gst_object_unref (gl_context);
+      }
+    }
+  }
+#endif
+#endif
+
+  /* Make sure the display we pass down to the buffer pool is actually
+     the expected one, especially when the downstream element requires
+     a GLX or EGL display */
+  if (!gst_vaapi_plugin_base_ensure_display (plugin))
+    goto error_ensure_display;
+
+  if (!gst_video_info_from_caps (&vi, caps))
+    goto error_invalid_caps;
+  gst_video_info_force_nv12_if_encoded (&vi);
+
+  index_allocator = -1;
+  num_allocators = gst_query_get_n_allocation_params (query);
+  for (i = 0; i < num_allocators; i++) {
+    GstAllocator *allocator = NULL;
+    GstAllocationParams params;
+
+    gst_query_parse_nth_allocation_param (query, i, &allocator, &params);
+    if (!allocator)
+      continue;
+
+    /* Let's keep the the first allocator if it is not VA-API. It
+     * might be used if it is required to copy the output frame to a
+     * new buffer */
+    if (i == 0
+        && g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0) {
+      if (srcpriv->other_allocator)
+        gst_object_unref (srcpriv->other_allocator);
+      srcpriv->other_allocator = allocator;
+      srcpriv->other_allocator_params = params;
+      continue;
+    }
+
+    if (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) == 0) {
+      GST_DEBUG_OBJECT (plugin, "found vaapi allocator in query %"
+          GST_PTR_FORMAT, allocator);
+      index_allocator = i;
+      if (srcpriv->allocator)
+        gst_object_unref (srcpriv->allocator);
+      srcpriv->allocator = allocator;
+      break;
+    }
+    gst_object_unref (allocator);
+  }
+
+  if (gst_query_get_n_allocation_pools (query) > 0) {
+    gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max);
+    update_pool = TRUE;
+    size = MAX (size, GST_VIDEO_INFO_SIZE (&vi));
+    if (pool) {
+      /* Check whether downstream element proposed a bufferpool but did
+         not provide a correct propose_allocation() implementation */
+      if (gst_buffer_pool_has_option (pool,
+              GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT))
+        pool_options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT;
+
+      /* GstVaapiVideoMeta is mandatory, and this implies VA surface memory */
+      if (!gst_buffer_pool_has_option (pool,
+              GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) {
+        GST_INFO_OBJECT (plugin, "ignoring non-VAAPI pool: %" GST_PTR_FORMAT,
+            pool);
+        gst_clear_object (&pool);
+      }
+    }
+  } else {
+    pool = NULL;
+    size = GST_VIDEO_INFO_SIZE (&vi);
+    min = max = 0;
+  }
+
+  if (!pool) {
+    if (!ensure_srcpad_allocator (plugin, plugin->srcpad, &vi, caps))
+      goto error;
+    size = GST_VIDEO_INFO_SIZE (&vi);   /* size might be updated by
+                                         * allocator */
+    pool = gst_vaapi_plugin_base_create_pool (plugin, caps, size, min, max,
+        pool_options, srcpriv->allocator);
+    if (!pool)
+      goto error;
+  }
+
+  if (update_pool)
+    gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max);
+  else
+    gst_query_add_allocation_pool (query, pool, size, min, max);
+
+  /* allocator might be updated by ensure_srcpad_allocator() */
+  if (srcpriv->allocator) {
+    if (index_allocator > 0) {
+      gst_query_set_nth_allocation_param (query, index_allocator,
+          srcpriv->allocator, NULL);
+    } else {
+      GST_DEBUG_OBJECT (plugin, "adding allocator in query %" GST_PTR_FORMAT,
+          srcpriv->allocator);
+      gst_query_add_allocation_param (query, srcpriv->allocator, NULL);
+    }
+  }
+
+  gst_clear_object (&srcpriv->buffer_pool);
+  srcpriv->buffer_pool = pool;
+
+  /* if downstream doesn't support GstVideoMeta, and the negotiated
+   * caps are raw video, and the used allocator is the VA-API one, we
+   * should copy the VA-API frame into a dumb buffer */
+  plugin->copy_output_frame = gst_vaapi_video_buffer_pool_copy_buffer (pool);
+
+  return TRUE;
+
+  /* ERRORS */
+error_no_caps:
+  {
+    GST_ERROR_OBJECT (plugin, "no caps specified");
+    return FALSE;
+  }
+error_invalid_caps:
+  {
+    GST_ERROR_OBJECT (plugin, "invalid caps %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+error_ensure_display:
+  {
+    GST_ERROR_OBJECT (plugin, "failed to ensure display of type %d",
+        plugin->display_type_req);
+    return FALSE;
+  }
+error:
+  {
+    /* error message already sent */
+    return FALSE;
+  }
+}
+
+/**
+ * gst_vaapi_plugin_base_pad_get_input_buffer:
+ * @plugin: a #GstVaapiPluginBase
+ * @sinkpad: the sink pad to obtain input buffer on
+ * @inbuf: the sink pad (input) buffer
+ * @outbuf_ptr: the pointer to location to the VA surface backed buffer
+ *
+ * Acquires the static sink pad (input) buffer as a VA surface backed
+ * buffer. This is mostly useful for raw YUV buffers, as source
+ * buffers that are already backed as a VA surface are passed
+ * verbatim.
+ *
+ * Returns: #GST_FLOW_OK if the buffer could be acquired
+ */
+GstFlowReturn
+gst_vaapi_plugin_base_pad_get_input_buffer (GstVaapiPluginBase * plugin,
+    GstPad * sinkpad, GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
+{
+  GstVaapiPadPrivate *sinkpriv = GST_VAAPI_PAD_PRIVATE (sinkpad);
+  GstVaapiVideoMeta *meta;
+  GstBuffer *outbuf;
+  GstVideoFrame src_frame, out_frame;
+  gboolean success;
+
+  g_return_val_if_fail (inbuf != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (outbuf_ptr != NULL, GST_FLOW_ERROR);
+
+  meta = gst_buffer_get_vaapi_video_meta (inbuf);
+  if (meta) {
+    *outbuf_ptr = gst_buffer_ref (inbuf);
+    return GST_FLOW_OK;
+  }
+
+  if (!sinkpriv->caps_is_raw)
+    goto error_invalid_buffer;
+
+  if (!sinkpriv->buffer_pool)
+    goto error_no_pool;
+
+  if (!gst_buffer_pool_is_active (sinkpriv->buffer_pool) &&
+      !gst_buffer_pool_set_active (sinkpriv->buffer_pool, TRUE))
+    goto error_active_pool;
+
+  outbuf = NULL;
+  if (gst_buffer_pool_acquire_buffer (sinkpriv->buffer_pool,
+          &outbuf, NULL) != GST_FLOW_OK)
+    goto error_create_buffer;
+
+  if (is_dma_buffer (inbuf)) {
+    if (!plugin_bind_dma_to_vaapi_buffer (plugin, sinkpad, inbuf, outbuf))
+      goto error_bind_dma_buffer;
+    goto done;
+  }
+
+  if (!gst_video_frame_map (&src_frame, &sinkpriv->info, inbuf, GST_MAP_READ))
+    goto error_map_src_buffer;
+
+  if (!gst_video_frame_map (&out_frame, &sinkpriv->info, outbuf, GST_MAP_WRITE))
+    goto error_map_dst_buffer;
+
+  success = gst_video_frame_copy (&out_frame, &src_frame);
+  gst_video_frame_unmap (&out_frame);
+  gst_video_frame_unmap (&src_frame);
+  if (!success)
+    goto error_copy_buffer;
+
+done:
+  if (!gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_FLAGS |
+          GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META, 0, -1))
+    return GST_FLOW_ERROR;
+  *outbuf_ptr = outbuf;
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_no_pool:
+  {
+    GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
+        ("no buffer pool was negotiated"), ("no buffer pool was negotiated"));
+    return GST_FLOW_ERROR;
+  }
+error_active_pool:
+  {
+    GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
+        ("failed to activate buffer pool"), ("failed to activate buffer pool"));
+    return GST_FLOW_ERROR;
+  }
+error_map_dst_buffer:
+  {
+    gst_video_frame_unmap (&src_frame);
+    // fall-through
+  }
+error_map_src_buffer:
+  {
+    GST_WARNING ("failed to map buffer");
+    gst_buffer_unref (outbuf);
+    return GST_FLOW_NOT_SUPPORTED;
+  }
+
+  /* ERRORS */
+error_invalid_buffer:
+  {
+    GST_ELEMENT_ERROR (plugin, STREAM, FAILED,
+        ("failed to validate source buffer"),
+        ("failed to validate source buffer"));
+    return GST_FLOW_ERROR;
+  }
+error_create_buffer:
+  {
+    GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
+        ("failed to create buffer"));
+    return GST_FLOW_ERROR;
+  }
+error_bind_dma_buffer:
+  {
+    GST_ELEMENT_ERROR (plugin, STREAM, FAILED, ("Allocation failed"),
+        ("failed to bind dma_buf to VA surface buffer"));
+    gst_buffer_unref (outbuf);
+    return GST_FLOW_ERROR;
+  }
+error_copy_buffer:
+  {
+    GST_WARNING_OBJECT (plugin, "failed to upload buffer to VA surface");
+    gst_buffer_unref (outbuf);
+    return GST_FLOW_NOT_SUPPORTED;
+  }
+}
+
+/**
+ * gst_vaapi_plugin_base_get_input_buffer:
+ * @plugin: a #GstVaapiPluginBase
+ * @inbuf: the sink pad (input) buffer
+ * @outbuf_ptr: the pointer to location to the VA surface backed buffer
+ *
+ * Acquires the static sink pad (input) buffer as a VA surface backed
+ * buffer. This is mostly useful for raw YUV buffers, as source
+ * buffers that are already backed as a VA surface are passed
+ * verbatim.
+ *
+ * Returns: #GST_FLOW_OK if the buffer could be acquired
+ */
+GstFlowReturn
+gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin,
+    GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
+{
+  return gst_vaapi_plugin_base_pad_get_input_buffer (plugin, plugin->sinkpad,
+      inbuf, outbuf_ptr);
+}
+
+/**
+ * gst_vaapi_plugin_base_set_gl_context:
+ * @plugin: a #GstVaapiPluginBase
+ * @object: the new GL context from downstream
+ *
+ * Registers the new GL context. The change is effective at the next
+ * call to gst_vaapi_plugin_base_ensure_display(), where the
+ * underlying display object could be re-allocated to fit the GL
+ * context needs
+ */
+void
+gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin,
+    GstObject * object)
+{
+#if USE_GST_GL_HELPERS
+  GstGLContext *const gl_context = GST_GL_CONTEXT (object);
+  GstVaapiDisplayType display_type;
+
+  if (plugin->gl_context == object)
+    return;
+
+  gst_object_replace (&plugin->gl_context, object);
+
+  switch (gst_gl_context_get_gl_platform (gl_context)) {
+#if GST_VAAPI_USE_GLX
+    case GST_GL_PLATFORM_GLX:
+      display_type = GST_VAAPI_DISPLAY_TYPE_GLX;
+      break;
+#endif
+    case GST_GL_PLATFORM_EGL:
+#if GST_VAAPI_USE_EGL
+      display_type = GST_VAAPI_DISPLAY_TYPE_EGL;
+      break;
+#endif
+    default:
+      display_type = plugin->display_type;
+      break;
+  }
+  GST_INFO_OBJECT (plugin, "GL context: %" GST_PTR_FORMAT, plugin->gl_context);
+  gst_vaapi_plugin_base_set_display_type (plugin, display_type);
+#endif
+}
+
+/**
+ * gst_vaapi_plugin_base_create_gl_context:
+ * @plugin: a #GstVaapiPluginBase
+ *
+ * It queries downstream and upstream for a #GstGLDisplay and a other
+ * #GstGLContext. If not found, a new #GstGLDisplay and #GstGLContext
+ * are created, if it is possible.
+ *
+ * Returns: (transfer full) a new created #GstGLContext or %NULL
+ **/
+GstObject *
+gst_vaapi_plugin_base_create_gl_context (GstVaapiPluginBase * plugin)
+{
+#if USE_GST_GL_HELPERS
+  GstGLContext *gl_other_context = NULL, *gl_context = NULL;
+  GstGLDisplay *gl_display = NULL;
+
+  if (!plugin->gl_display)
+    return NULL;
+
+  gl_display = (GstGLDisplay *) plugin->gl_display;
+  if (gst_gl_display_get_handle_type (gl_display) == GST_GL_DISPLAY_TYPE_ANY)
+    goto no_valid_gl_display;
+  gl_other_context = (GstGLContext *) plugin->gl_other_context;
+
+  GST_INFO_OBJECT (plugin, "creating a new GstGL context");
+
+  GST_OBJECT_LOCK (gl_display);
+  do {
+    if (gl_context)
+      gst_object_unref (gl_context);
+    gl_context = gst_gl_display_get_gl_context_for_thread (gl_display, NULL);
+    if (!gl_context) {
+      if (!gst_gl_display_create_context (gl_display, gl_other_context,
+              &gl_context, NULL))
+        break;
+    }
+  } while (!gst_gl_display_add_context (gl_display, gl_context));
+  GST_OBJECT_UNLOCK (gl_display);
+
+  return GST_OBJECT_CAST (gl_context);
+
+  /* ERRORS */
+no_valid_gl_display:
+  {
+    GST_INFO_OBJECT (plugin, "No valid GL display found");
+    gst_object_replace (&plugin->gl_display, NULL);
+    gst_object_replace (&plugin->gl_other_context, NULL);
+    return NULL;
+  }
+#else
+  return NULL;
+#endif
+}
+
+static GArray *
+extract_allowed_surface_formats (GstVaapiDisplay * display,
+    GArray * img_formats)
+{
+  guint i;
+  GArray *out_formats;
+  guint surface_chroma = 0;
+  GstVaapiSurface *surface = NULL;
+
+  /* let's assume all the formats are possible to download */
+  if (gst_vaapi_display_has_driver_quirks (display,
+          GST_VAAPI_DRIVER_QUIRK_NO_CHECK_SURFACE_PUT_IMAGE)) {
+    out_formats = g_array_ref (img_formats);
+    goto bail;
+  }
+
+  out_formats =
+      g_array_sized_new (FALSE, FALSE, sizeof (GstVideoFormat),
+      img_formats->len);
+  if (!out_formats)
+    return NULL;
+
+  for (i = 0; i < img_formats->len; i++) {
+    const GstVideoFormat img_format =
+        g_array_index (img_formats, GstVideoFormat, i);
+    GstVaapiImage *image;
+    GstVideoInfo vi;
+    guint img_chroma;
+
+    if (img_format == GST_VIDEO_FORMAT_UNKNOWN)
+      continue;
+
+    img_chroma = gst_vaapi_video_format_get_chroma_type (img_format);
+    if (img_chroma != surface_chroma) {
+      if (surface)
+        gst_vaapi_surface_unref (surface);
+      gst_video_info_set_format (&vi, img_format, 64, 64);
+      surface = gst_vaapi_surface_new_full (display, &vi, 0);
+      if (!surface)
+        continue;
+      surface_chroma = img_chroma;
+    }
+
+    image = gst_vaapi_image_new (display, img_format, 64, 64);
+    if (!image)
+      continue;
+    if (gst_vaapi_surface_put_image (surface, image))
+      g_array_append_val (out_formats, img_format);
+    gst_vaapi_image_unref (image);
+  }
+
+  if (surface)
+    gst_vaapi_surface_unref (surface);
+
+bail:
+  if (out_formats->len == 0) {
+    g_array_unref (out_formats);
+    return NULL;
+  }
+  return out_formats;
+}
+
+static gboolean
+ensure_allowed_raw_caps (GstVaapiPluginBase * plugin)
+{
+  GArray *formats, *out_formats;
+  GstVaapiDisplay *display;
+  GstCaps *out_caps;
+  gboolean ret = FALSE;
+
+  if (plugin->allowed_raw_caps)
+    return TRUE;
+
+  out_formats = NULL;
+  display = gst_object_ref (plugin->display);
+  formats = gst_vaapi_display_get_image_formats (display);
+  if (!formats)
+    goto bail;
+  out_formats = extract_allowed_surface_formats (display, formats);
+  if (!out_formats)
+    goto bail;
+  out_caps = gst_vaapi_video_format_new_template_caps_from_list (out_formats);
+  if (!out_caps)
+    goto bail;
+
+  gst_caps_replace (&plugin->allowed_raw_caps, out_caps);
+  gst_caps_unref (out_caps);
+  ret = TRUE;
+
+bail:
+  if (formats)
+    g_array_unref (formats);
+  if (out_formats)
+    g_array_unref (out_formats);
+  gst_object_unref (display);
+
+  return ret;
+}
+
+/**
+ * gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps:
+ * @plugin: a #GstVaapiPluginBase
+ *
+ * Returns the raw #GstCaps allowed by the element.
+ *
+ * Returns: the allowed raw #GstCaps or %NULL
+ **/
+GstCaps *
+gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (GstVaapiPluginBase * plugin)
+{
+  if (!ensure_allowed_raw_caps (plugin))
+    return NULL;
+  return plugin->allowed_raw_caps;
+}
+
+/**
+ * gst_vaapi_plugin_base_set_srcpad_can_dmabuf:
+ * @plugin: a #GstVaapiPluginBase
+ * @object: the GL context from gst-gl
+ *
+ * This function will determine if @object supports dmabuf
+ * importing on the base plugin static srcpad.
+ *
+ * Please note that the context @object should come from downstream.
+ **/
+void
+gst_vaapi_plugin_base_set_srcpad_can_dmabuf (GstVaapiPluginBase * plugin,
+    GstObject * object)
+{
+#if GST_VAAPI_USE_EGL && USE_GST_GL_HELPERS
+  GstVaapiPadPrivate *srcpriv = GST_VAAPI_PAD_PRIVATE (plugin->srcpad);
+  GstGLContext *const gl_context = GST_GL_CONTEXT (object);
+
+  srcpriv->can_dmabuf =
+      (!(gst_gl_context_get_gl_api (gl_context) & GST_GL_API_GLES1)
+      && gst_gl_context_check_feature (gl_context,
+          "EGL_EXT_image_dma_buf_import"));
+#endif
+}
+
+static void
+_init_performance_debug (void)
+{
+#ifndef GST_DISABLE_GST_DEBUG
+  static gsize _init = 0;
+
+  if (g_once_init_enter (&_init)) {
+    GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
+    g_once_init_leave (&_init, 1);
+  }
+#endif
+}
+
+/**
+ * gst_vaapi_plugin_copy_va_buffer:
+ * @plugin: a #GstVaapiPluginBase
+ * @inbuf: a #GstBuffer with VA memory type
+ * @outbuf: a #GstBuffer with system allocated memory
+ *
+ * Copy @inbuf to @outbuf. This if required when downstream doesn't
+ * support GstVideoMeta, and since VA memory may have custom strides a
+ * frame copy is required.
+ *
+ * Returns: %FALSE if the copy failed, otherwise %TRUE. Also returns
+ *          %TRUE if it is not required to do the copy
+ **/
+gboolean
+gst_vaapi_plugin_copy_va_buffer (GstVaapiPluginBase * plugin,
+    GstBuffer * inbuf, GstBuffer * outbuf)
+{
+  GstVaapiPadPrivate *srcpriv = GST_VAAPI_PAD_PRIVATE (plugin->srcpad);
+  GstVideoMeta *vmeta;
+  GstVideoFrame src_frame, dst_frame;
+  gboolean success;
+
+  if (!plugin->copy_output_frame)
+    return TRUE;
+
+  /* inbuf shall have video meta */
+  vmeta = gst_buffer_get_video_meta (inbuf);
+  if (!vmeta)
+    return FALSE;
+
+  _init_performance_debug ();
+  GST_CAT_INFO (CAT_PERFORMANCE, "copying VA buffer to system memory buffer");
+
+  if (!gst_video_frame_map (&src_frame, &srcpriv->info, inbuf, GST_MAP_READ))
+    return FALSE;
+  if (!gst_video_frame_map (&dst_frame, &srcpriv->info, outbuf, GST_MAP_WRITE)) {
+    gst_video_frame_unmap (&src_frame);
+    return FALSE;
+  }
+  success = gst_video_frame_copy (&dst_frame, &src_frame);
+  gst_video_frame_unmap (&dst_frame);
+  gst_video_frame_unmap (&src_frame);
+
+  if (success) {
+    gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS
+        | GST_BUFFER_COPY_FLAGS, 0, -1);
+  }
+
+  return success;
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginbase.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginbase.h
new file mode 100644 (file)
index 0000000..94aa296
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ *  gstvaapipluginbase.h - Base GStreamer VA-API Plugin element
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_PLUGIN_BASE_H
+#define GST_VAAPI_PLUGIN_BASE_H
+
+#include <gst/base/gstbasetransform.h>
+#include <gst/video/gstvideodecoder.h>
+#include <gst/video/gstvideoencoder.h>
+#include <gst/video/gstvideosink.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiPluginBase GstVaapiPluginBase;
+typedef struct _GstVaapiPluginBaseClass GstVaapiPluginBaseClass;
+typedef struct _GstVaapiPadPrivate GstVaapiPadPrivate;
+
+#define GST_VAAPI_PLUGIN_BASE(plugin) \
+  ((GstVaapiPluginBase *)(plugin))
+#define GST_VAAPI_PLUGIN_BASE_CLASS(plugin) \
+  ((GstVaapiPluginBaseClass *)(plugin))
+#define GST_VAAPI_PLUGIN_BASE_GET_CLASS(plugin) \
+  GST_VAAPI_PLUGIN_BASE_CLASS(GST_ELEMENT_GET_CLASS( \
+      GST_VAAPI_PLUGIN_BASE_ELEMENT(plugin)))
+#define GST_VAAPI_PLUGIN_BASE_PARENT(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE(plugin)->parent_instance)
+#define GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_CLASS(plugin)->parent_class)
+#define GST_VAAPI_PLUGIN_BASE_ELEMENT(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->element)
+#define GST_VAAPI_PLUGIN_BASE_ELEMENT_CLASS(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->element)
+#define GST_VAAPI_PLUGIN_BASE_DECODER(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->decoder)
+#define GST_VAAPI_PLUGIN_BASE_DECODER_CLASS(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->decoder)
+#define GST_VAAPI_PLUGIN_BASE_ENCODER(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->encoder)
+#define GST_VAAPI_PLUGIN_BASE_ENCODER_CLASS(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->encoder)
+#define GST_VAAPI_PLUGIN_BASE_TRANSFORM(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->transform)
+#define GST_VAAPI_PLUGIN_BASE_TRANSFORM_CLASS(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->transform)
+#define GST_VAAPI_PLUGIN_BASE_SINK(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT(plugin)->sink)
+#define GST_VAAPI_PLUGIN_BASE_SINK_CLASS(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_PARENT_CLASS(plugin)->sink)
+
+#define GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES \
+  gst_vaapi_plugin_base_init_interfaces(g_define_type_id);
+
+#define GST_VAAPI_PLUGIN_BASE_SINK_PAD(plugin) \
+  (GST_VAAPI_PLUGIN_BASE(plugin)->sinkpad)
+#define GST_VAAPI_PLUGIN_BASE_SINK_PAD_PRIVATE(plugin) \
+  (GST_VAAPI_PLUGIN_BASE(plugin)->sinkpriv)
+#define GST_VAAPI_PLUGIN_BASE_SINK_PAD_CAPS(plugin) \
+  (GST_VAAPI_PLUGIN_BASE_SINK_PAD_PRIVATE(plugin)->caps)
+#define GST_VAAPI_PLUGIN_BASE_SINK_PAD_INFO(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_SINK_PAD_PRIVATE(plugin)->info)
+
+#define GST_VAAPI_PLUGIN_BASE_SRC_PAD(plugin) \
+  (GST_VAAPI_PLUGIN_BASE(plugin)->srcpad)
+#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin) \
+  (GST_VAAPI_PLUGIN_BASE(plugin)->srcpriv)
+#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAPS(plugin) \
+  (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->caps)
+#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO(plugin) \
+  (&GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->info)
+#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF(plugin) \
+  (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->can_dmabuf)
+#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_BUFFER_POOL(plugin) \
+  (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->buffer_pool)
+#define GST_VAAPI_PLUGIN_BASE_SRC_PAD_ALLOCATOR(plugin) \
+  (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->allocator)
+#define GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR(plugin) \
+  (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->other_allocator)
+#define GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR_PARAMS(plugin) \
+  (GST_VAAPI_PLUGIN_BASE_SRC_PAD_PRIVATE(plugin)->other_allocator_params)
+
+#define GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME(plugin) \
+  (GST_VAAPI_PLUGIN_BASE(plugin)->copy_output_frame)
+
+#define GST_VAAPI_PLUGIN_BASE_DISPLAY(plugin) \
+  (GST_VAAPI_PLUGIN_BASE(plugin)->display)
+#define GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE(plugin) \
+  (GST_VAAPI_PLUGIN_BASE(plugin)->display_type)
+#define GST_VAAPI_PLUGIN_BASE_DISPLAY_NAME(plugin) \
+  (GST_VAAPI_PLUGIN_BASE(plugin)->display_name)
+#define GST_VAAPI_PLUGIN_BASE_DISPLAY_REPLACE(plugin, new_display) \
+  (gst_vaapi_display_replace(&GST_VAAPI_PLUGIN_BASE_DISPLAY(plugin), \
+       (new_display)))
+
+#define GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT(parent_class) \
+  static void \
+  gst_vaapi_base_set_context (GstElement * element, GstContext * context) \
+  { \
+    GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element); \
+    \
+    gst_vaapi_plugin_base_set_context (plugin, context); \
+    GST_ELEMENT_CLASS (parent_class)->set_context (element, context); \
+  }
+
+struct _GstVaapiPadPrivate
+{
+  GstCaps *caps;
+  GstVideoInfo info;
+  GstBufferPool *buffer_pool;
+  GstAllocator *allocator;
+  guint buffer_size;
+  gboolean caps_is_raw;
+
+  gboolean can_dmabuf;
+
+  GstAllocator *other_allocator;
+  GstAllocationParams other_allocator_params;
+};
+
+G_GNUC_INTERNAL
+GstVaapiPadPrivate *
+gst_vaapi_pad_private_new (void);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_pad_private_reset (GstVaapiPadPrivate * priv);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_pad_private_finalize (GstVaapiPadPrivate * priv);
+
+struct _GstVaapiPluginBase
+{
+  /*< private >*/
+  union
+  {
+    GstElement element;
+    GstVideoDecoder decoder;
+    GstVideoEncoder encoder;
+    GstBaseTransform transform;
+    GstVideoSink sink;
+    GstVideoAggregator aggregator;
+  } parent_instance;
+
+  GstDebugCategory *debug_category;
+
+  GstPad *sinkpad;
+  GstPad *srcpad;
+
+  GstVaapiPadPrivate *sinkpriv;
+  GstVaapiPadPrivate *srcpriv;
+
+  GstVaapiDisplay *display;
+  GstVaapiDisplayType display_type;
+  GstVaapiDisplayType display_type_req;
+  gchar *display_name;
+
+  GstObject *gl_context;
+  GstObject *gl_display;
+  GstObject *gl_other_context;
+
+  GstCaps *allowed_raw_caps;
+
+  gboolean enable_direct_rendering;
+  gboolean copy_output_frame;
+};
+
+struct _GstVaapiPluginBaseClass
+{
+  /*< private >*/
+  union
+  {
+    GstElementClass element;
+    GstVideoDecoderClass decoder;
+    GstVideoEncoderClass encoder;
+    GstBaseTransformClass transform;
+    GstVideoSinkClass sink;
+    GstVideoAggregatorClass aggregator;
+  } parent_class;
+
+  gboolean  (*has_interface) (GstVaapiPluginBase * plugin, GType type);
+  void (*display_changed) (GstVaapiPluginBase * plugin);
+  GstVaapiPadPrivate * (*get_vaapi_pad_private) (GstVaapiPluginBase * plugin, GstPad * pad);
+};
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_init_interfaces (GType type);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_class_init (GstVaapiPluginBaseClass * klass);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_init (GstVaapiPluginBase * plugin,
+    GstDebugCategory * debug_category);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_finalize (GstVaapiPluginBase * plugin);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_plugin_base_open (GstVaapiPluginBase * plugin);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_close (GstVaapiPluginBase * plugin);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_plugin_base_has_display_type (GstVaapiPluginBase * plugin,
+    GstVaapiDisplayType display_type_req);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_set_display_type (GstVaapiPluginBase * plugin,
+    GstVaapiDisplayType display_type);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_set_display_name (GstVaapiPluginBase * plugin,
+    const gchar * display_name);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_plugin_base_ensure_display (GstVaapiPluginBase * plugin);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_plugin_base_set_caps (GstVaapiPluginBase * plugin, GstCaps * incaps,
+    GstCaps * outcaps);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_plugin_base_pad_set_caps (GstVaapiPluginBase *plugin,
+    GstPad * sinkpad, GstCaps * incaps, GstPad * srcpad, GstCaps * outcaps);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_plugin_base_propose_allocation (GstVaapiPluginBase * plugin,
+    GstQuery * query);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_plugin_base_pad_propose_allocation (GstVaapiPluginBase * plugin,
+    GstPad * sinkpad, GstQuery * query);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_plugin_base_decide_allocation (GstVaapiPluginBase * plugin,
+    GstQuery * query);
+
+G_GNUC_INTERNAL
+GstFlowReturn
+gst_vaapi_plugin_base_get_input_buffer (GstVaapiPluginBase * plugin,
+    GstBuffer * inbuf, GstBuffer ** outbuf_ptr);
+
+G_GNUC_INTERNAL
+GstFlowReturn
+gst_vaapi_plugin_base_pad_get_input_buffer (GstVaapiPluginBase * plugin,
+    GstPad * sinkpad, GstBuffer * inbuf, GstBuffer ** outbuf_ptr);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_set_context (GstVaapiPluginBase * plugin,
+    GstContext * context);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_set_gl_context (GstVaapiPluginBase * plugin,
+    GstObject * object);
+
+G_GNUC_INTERNAL
+GstObject *
+gst_vaapi_plugin_base_create_gl_context (GstVaapiPluginBase * plugin);
+
+G_GNUC_INTERNAL
+GstCaps *
+gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (GstVaapiPluginBase * plugin);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_plugin_base_set_srcpad_can_dmabuf (GstVaapiPluginBase * plugin,
+    GstObject * object);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_plugin_copy_va_buffer (GstVaapiPluginBase * plugin,
+    GstBuffer * inbuf, GstBuffer * outbuf);
+
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_PLUGIN_BASE_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginutil.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginutil.c
new file mode 100644 (file)
index 0000000..6fa18f6
--- /dev/null
@@ -0,0 +1,1347 @@
+/*
+ *  gstvaapipluginutil.h - VA-API plugin helpers
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *  Copyright (C) 2011 Collabora
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstcompat.h"
+#include "gstvaapivideocontext.h"
+#include <gst/vaapi/gstvaapiprofilecaps.h>
+#include <gst/vaapi/gstvaapiutils.h>
+#if GST_VAAPI_USE_DRM
+# include <gst/vaapi/gstvaapidisplay_drm.h>
+#endif
+#if GST_VAAPI_USE_X11
+# include <gst/vaapi/gstvaapidisplay_x11.h>
+#endif
+#if GST_VAAPI_USE_GLX
+# include <gst/vaapi/gstvaapidisplay_glx.h>
+#endif
+#if GST_VAAPI_USE_EGL
+# include <gst/vaapi/gstvaapidisplay_egl.h>
+#endif
+#if GST_VAAPI_USE_WAYLAND
+# include <gst/vaapi/gstvaapidisplay_wayland.h>
+#endif
+#if USE_GST_GL_HELPERS
+# include <gst/gl/gl.h>
+#if GST_VAAPI_USE_EGL && GST_GL_HAVE_PLATFORM_EGL
+# include <gst/gl/egl/gstgldisplay_egl.h>
+#endif
+#endif
+#include "gstvaapipluginutil.h"
+#include "gstvaapipluginbase.h"
+
+/* Environment variable for disable driver white-list */
+#define GST_VAAPI_ALL_DRIVERS_ENV "GST_VAAPI_ALL_DRIVERS"
+
+typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFunc) (const gchar *);
+typedef GstVaapiDisplay *(*GstVaapiDisplayCreateFromHandleFunc) (gpointer);
+
+typedef struct
+{
+  const gchar *type_str;
+  GstVaapiDisplayType type;
+  GstVaapiDisplayCreateFunc create_display;
+  GstVaapiDisplayCreateFromHandleFunc create_display_from_handle;
+} DisplayMap;
+
+/* *INDENT-OFF* */
+static const DisplayMap g_display_map[] = {
+#if GST_VAAPI_USE_WAYLAND
+  {"wayland",
+   GST_VAAPI_DISPLAY_TYPE_WAYLAND,
+   gst_vaapi_display_wayland_new,
+   (GstVaapiDisplayCreateFromHandleFunc)
+   gst_vaapi_display_wayland_new_with_display},
+#endif
+#if GST_VAAPI_USE_GLX
+  {"glx",
+   GST_VAAPI_DISPLAY_TYPE_GLX,
+   gst_vaapi_display_glx_new,
+   (GstVaapiDisplayCreateFromHandleFunc)
+   gst_vaapi_display_glx_new_with_display},
+#endif
+#if GST_VAAPI_USE_X11
+  {"x11",
+   GST_VAAPI_DISPLAY_TYPE_X11,
+   gst_vaapi_display_x11_new,
+   (GstVaapiDisplayCreateFromHandleFunc)
+   gst_vaapi_display_x11_new_with_display},
+#endif
+#if GST_VAAPI_USE_DRM
+  {"drm",
+   GST_VAAPI_DISPLAY_TYPE_DRM,
+   gst_vaapi_display_drm_new},
+#endif
+  {NULL,}
+};
+/* *INDENT-ON* */
+
+static GstVaapiDisplay *
+gst_vaapi_create_display (GstVaapiDisplayType display_type,
+    const gchar * display_name)
+{
+  GstVaapiDisplay *display = NULL;
+  const DisplayMap *m;
+
+  for (m = g_display_map; m->type_str != NULL; m++) {
+    if (display_type != GST_VAAPI_DISPLAY_TYPE_ANY && display_type != m->type)
+      continue;
+
+    display = m->create_display (display_name);
+    if (display || display_type != GST_VAAPI_DISPLAY_TYPE_ANY)
+      break;
+  }
+  return display;
+}
+
+#if USE_GST_GL_HELPERS
+static GstVaapiDisplay *
+gst_vaapi_create_display_from_handle (GstVaapiDisplayType display_type,
+    gpointer handle)
+{
+  GstVaapiDisplay *display;
+  const DisplayMap *m;
+
+  if (display_type == GST_VAAPI_DISPLAY_TYPE_ANY)
+    return NULL;
+
+  for (m = g_display_map; m->type_str != NULL; m++) {
+    if (m->type == display_type) {
+      display = m->create_display_from_handle ?
+          m->create_display_from_handle (handle) : NULL;
+      return display;
+    }
+  }
+  return NULL;
+}
+
+static GstVaapiDisplayType
+gst_vaapi_get_display_type_from_gl (GstGLDisplayType gl_display_type,
+    GstGLPlatform gl_platform)
+{
+  switch (gl_display_type) {
+#if GST_VAAPI_USE_X11
+    case GST_GL_DISPLAY_TYPE_X11:{
+#if GST_VAAPI_USE_GLX
+      if (gl_platform == GST_GL_PLATFORM_GLX)
+        return GST_VAAPI_DISPLAY_TYPE_GLX;
+#endif
+      return GST_VAAPI_DISPLAY_TYPE_X11;
+    }
+#endif
+#if GST_VAAPI_USE_WAYLAND
+    case GST_GL_DISPLAY_TYPE_WAYLAND:{
+      return GST_VAAPI_DISPLAY_TYPE_WAYLAND;
+    }
+#endif
+#if GST_VAAPI_USE_EGL
+    case GST_GL_DISPLAY_TYPE_EGL:{
+      return GST_VAAPI_DISPLAY_TYPE_EGL;
+    }
+#endif
+#if GST_VAAPI_USE_DRM
+    case GST_GL_DISPLAY_TYPE_GBM:{
+      return GST_VAAPI_DISPLAY_TYPE_DRM;
+    }
+#endif
+    default:
+      /* unsupported display. Still DRM may work. */
+      break;
+  }
+
+  return GST_VAAPI_DISPLAY_TYPE_ANY;
+}
+
+static GstVaapiDisplayType
+gst_vaapi_get_display_type_from_gl_env (void)
+{
+  const gchar *const gl_window_type = g_getenv ("GST_GL_WINDOW");
+
+  if (!gl_window_type) {
+#if GST_VAAPI_USE_X11 && GST_GL_HAVE_WINDOW_X11
+    return GST_VAAPI_DISPLAY_TYPE_X11;
+#elif GST_VAAPI_USE_WAYLAND && GST_GL_HAVE_WINDOW_WAYLAND
+    return GST_VAAPI_DISPLAY_TYPE_WAYLAND;
+#elif GST_VAAPI_USE_EGL && GST_GL_HAVE_PLATFORM_EGL
+    return GST_VAAPI_DISPLAY_TYPE_EGL;
+#endif
+  }
+#if GST_VAAPI_USE_X11
+  if (g_strcmp0 (gl_window_type, "x11") == 0)
+    return GST_VAAPI_DISPLAY_TYPE_X11;
+#endif
+#if GST_VAAPI_USE_WAYLAND
+  if (g_strcmp0 (gl_window_type, "wayland") == 0)
+    return GST_VAAPI_DISPLAY_TYPE_WAYLAND;
+#endif
+#if GST_VAAPI_USE_EGL
+  {
+    const gchar *const gl_platform_type = g_getenv ("GST_GL_PLATFORM");
+    if (g_strcmp0 (gl_platform_type, "egl") == 0)
+      return GST_VAAPI_DISPLAY_TYPE_EGL;
+  }
+#endif
+
+  return GST_VAAPI_DISPLAY_TYPE_ANY;
+}
+
+#if GST_VAAPI_USE_EGL
+static gint
+gst_vaapi_get_gles_version_from_gl_api (GstGLAPI gl_api)
+{
+  switch (gl_api) {
+    case GST_GL_API_GLES1:
+      return 1;
+    case GST_GL_API_GLES2:
+      return 2;
+    case GST_GL_API_OPENGL:
+    case GST_GL_API_OPENGL3:
+      return 0;
+    default:
+      break;
+  }
+  return -1;
+}
+
+static guintptr
+gst_vaapi_get_egl_handle_from_gl_display (GstGLDisplay * gl_display)
+{
+  guintptr egl_handle = 0;
+  GstGLDisplayEGL *egl_display;
+
+  egl_display = gst_gl_display_egl_from_gl_display (gl_display);
+  if (egl_display) {
+    egl_handle = gst_gl_display_get_handle (GST_GL_DISPLAY (egl_display));
+    gst_object_unref (egl_display);
+  }
+  return egl_handle;
+}
+#endif /* GST_VAAPI_USE_EGL */
+
+static GstVaapiDisplay *
+gst_vaapi_create_display_from_egl (GstGLDisplay * gl_display,
+    GstGLContext * gl_context, GstVaapiDisplayType display_type,
+    gpointer native_display)
+{
+  GstVaapiDisplay *display = NULL;
+#if GST_VAAPI_USE_EGL
+  GstGLAPI gl_api;
+  gint gles_version;
+  guintptr egl_handler;
+
+  gl_api = gst_gl_context_get_gl_api (gl_context);
+  gles_version = gst_vaapi_get_gles_version_from_gl_api (gl_api);
+  if (gles_version == -1)
+    return NULL;
+
+  egl_handler = gst_vaapi_get_egl_handle_from_gl_display (gl_display);
+  if (egl_handler != 0) {
+    gpointer native_display_egl = GSIZE_TO_POINTER (egl_handler);
+    display = gst_vaapi_display_egl_new_with_native_display (native_display_egl,
+        display_type, gles_version);
+  }
+
+  if (!display) {
+    GstVaapiDisplay *wrapped_display;
+
+    wrapped_display =
+        gst_vaapi_create_display_from_handle (display_type, native_display);
+    if (wrapped_display) {
+      display = gst_vaapi_display_egl_new (wrapped_display, gles_version);
+      gst_object_unref (wrapped_display);
+    }
+  }
+
+  if (display) {
+    gst_vaapi_display_egl_set_gl_context (GST_VAAPI_DISPLAY_EGL (display),
+        GSIZE_TO_POINTER (gst_gl_context_get_gl_context (gl_context)));
+  }
+#endif
+  return display;
+}
+#endif /* USE_GST_GL_HELPERS */
+
+static GstVaapiDisplay *
+gst_vaapi_create_display_from_gl_context (GstObject * gl_context_object)
+{
+#if USE_GST_GL_HELPERS
+  GstGLContext *const gl_context = GST_GL_CONTEXT (gl_context_object);
+  GstGLDisplay *const gl_display = gst_gl_context_get_display (gl_context);
+  GstGLDisplayType gl_display_type;
+  GstGLPlatform gl_platform;
+  gpointer native_display;
+  GstVaapiDisplay *display = NULL;
+  GstVaapiDisplayType display_type;
+
+  /* Get display type and the native hanler */
+  gl_display_type = gst_gl_display_get_handle_type (gl_display);
+  gl_platform = gst_gl_context_get_gl_platform (gl_context);
+  display_type =
+      gst_vaapi_get_display_type_from_gl (gl_display_type, gl_platform);
+
+  native_display = GSIZE_TO_POINTER (gst_gl_display_get_handle (gl_display));
+
+  if (display_type == GST_VAAPI_DISPLAY_TYPE_ANY) {
+    /* derive type and native_display from the active window */
+    GstGLWindow *const gl_window = gst_gl_context_get_window (gl_context);
+    if (gl_window)
+      native_display = GSIZE_TO_POINTER (gst_gl_window_get_display (gl_window));
+    display_type = gst_vaapi_get_display_type_from_gl_env ();
+  }
+
+  if (gl_platform == GST_GL_PLATFORM_EGL) {
+    display = gst_vaapi_create_display_from_egl (gl_display, gl_context,
+        display_type, native_display);
+  }
+
+  /* Non-EGL and fallback */
+  if (!display) {
+    display =
+        gst_vaapi_create_display_from_handle (display_type, native_display);
+  }
+
+  gst_object_unref (gl_display);
+
+  return display;
+#endif
+  GST_ERROR ("No GstGL support");
+  return NULL;
+}
+
+static void
+gst_vaapi_find_gl_context (GstElement * element)
+{
+#if USE_GST_GL_HELPERS
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
+
+  /* if the element is vaapisink or any vaapi encoder it doesn't need
+   * to know a GstGLContext in order to create an appropriate
+   * GstVaapiDisplay. Let's them to choose their own
+   * GstVaapiDisplay */
+  if (GST_IS_VIDEO_SINK (element) || GST_IS_VIDEO_ENCODER (element))
+    return;
+
+  if (!gst_gl_ensure_element_data (plugin,
+          (GstGLDisplay **) & plugin->gl_display,
+          (GstGLContext **) & plugin->gl_other_context))
+    goto no_valid_gl_display;
+
+  gst_vaapi_find_gl_local_context (element, &plugin->gl_context);
+
+  if (plugin->gl_context) {
+    gst_vaapi_plugin_base_set_srcpad_can_dmabuf (plugin, plugin->gl_context);
+  } else {
+    GstObject *gl_context;
+
+    gl_context = gst_vaapi_plugin_base_create_gl_context (plugin);
+    if (gl_context) {
+      gst_vaapi_plugin_base_set_gl_context (plugin, gl_context);
+      gst_object_unref (gl_context);
+    }
+  }
+
+  /* ERRORS */
+no_valid_gl_display:
+  {
+    GST_INFO_OBJECT (plugin, "No valid GL display found");
+    gst_object_replace (&plugin->gl_display, NULL);
+    gst_object_replace (&plugin->gl_other_context, NULL);
+    return;
+  }
+#endif
+}
+
+gboolean
+gst_vaapi_ensure_display (GstElement * element, GstVaapiDisplayType type)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
+  GstVaapiDisplay *display = NULL;
+
+  g_return_val_if_fail (GST_IS_ELEMENT (element), FALSE);
+
+  if (gst_vaapi_video_context_prepare (element, &plugin->display)) {
+    /* Neighbour found and it updated the display */
+    if (gst_vaapi_plugin_base_has_display_type (plugin, type))
+      return TRUE;
+  }
+
+  /* Query for a local GstGL context. If it's found, it will be used
+   * to create the VA display */
+  if (!plugin->gl_context)
+    gst_vaapi_find_gl_context (element);
+
+  /* If no neighboor, or application not interested, use system default */
+  if (plugin->gl_context) {
+    display = gst_vaapi_create_display_from_gl_context (plugin->gl_context);
+    /* Cannot instantiate VA display based on GL context. Reset the
+     *  requested display type to ANY to try again */
+    if (!display)
+      gst_vaapi_plugin_base_set_display_type (plugin,
+          GST_VAAPI_DISPLAY_TYPE_ANY);
+  }
+  if (!display)
+    display = gst_vaapi_create_display (type, plugin->display_name);
+  if (!display)
+    return FALSE;
+
+  gst_vaapi_video_context_propagate (element, display);
+  gst_object_unref (display);
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_handle_context_query (GstElement * element, GstQuery * query)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (element);
+  const gchar *type = NULL;
+  GstContext *context, *old_context;
+
+  g_return_val_if_fail (query != NULL, FALSE);
+
+#if USE_GST_GL_HELPERS
+  if (plugin->gl_display && plugin->gl_context && plugin->gl_other_context) {
+    if (gst_gl_handle_context_query (element, query,
+            (GstGLDisplay *) plugin->gl_display,
+            (GstGLContext *) plugin->gl_context,
+            (GstGLContext *) plugin->gl_other_context))
+      return TRUE;
+  }
+#endif
+
+  if (!plugin->display)
+    return FALSE;
+
+  if (!gst_query_parse_context_type (query, &type))
+    return FALSE;
+
+  if (g_strcmp0 (type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME))
+    return FALSE;
+
+  gst_query_parse_context (query, &old_context);
+  if (old_context) {
+    context = gst_context_copy (old_context);
+    gst_vaapi_video_context_set_display (context, plugin->display);
+  } else {
+    context = gst_vaapi_video_context_new_with_display (plugin->display, FALSE);
+  }
+
+  gst_query_set_context (query, context);
+  gst_context_unref (context);
+
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_append_surface_caps (GstCaps * out_caps, GstCaps * in_caps)
+{
+  GstStructure *structure;
+  const GValue *v_width, *v_height, *v_framerate, *v_par;
+  guint i, n_structures;
+
+  structure = gst_caps_get_structure (in_caps, 0);
+  v_width = gst_structure_get_value (structure, "width");
+  v_height = gst_structure_get_value (structure, "height");
+  v_framerate = gst_structure_get_value (structure, "framerate");
+  v_par = gst_structure_get_value (structure, "pixel-aspect-ratio");
+  if (!v_width || !v_height)
+    return FALSE;
+
+  n_structures = gst_caps_get_size (out_caps);
+  for (i = 0; i < n_structures; i++) {
+    structure = gst_caps_get_structure (out_caps, i);
+    gst_structure_set_value (structure, "width", v_width);
+    gst_structure_set_value (structure, "height", v_height);
+    if (v_framerate)
+      gst_structure_set_value (structure, "framerate", v_framerate);
+    if (v_par)
+      gst_structure_set_value (structure, "pixel-aspect-ratio", v_par);
+  }
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_apply_composition (GstVaapiSurface * surface, GstBuffer * buffer)
+{
+  GstVideoOverlayCompositionMeta *const cmeta =
+      gst_buffer_get_video_overlay_composition_meta (buffer);
+  GstVideoOverlayComposition *composition = NULL;
+
+  if (cmeta)
+    composition = cmeta->overlay;
+  return gst_vaapi_surface_set_subpictures_from_composition (surface,
+      composition);
+}
+
+gboolean
+gst_vaapi_value_set_format (GValue * value, GstVideoFormat format)
+{
+  const gchar *str;
+
+  str = gst_video_format_to_string (format);
+  if (!str)
+    return FALSE;
+
+  g_value_init (value, G_TYPE_STRING);
+  g_value_set_string (value, str);
+  return TRUE;
+}
+
+gboolean
+gst_vaapi_value_set_format_list (GValue * value, GArray * formats)
+{
+  GValue v_format = G_VALUE_INIT;
+  guint i;
+
+  g_value_init (value, GST_TYPE_LIST);
+  for (i = 0; i < formats->len; i++) {
+    GstVideoFormat const format = g_array_index (formats, GstVideoFormat, i);
+
+    if (!gst_vaapi_value_set_format (&v_format, format))
+      continue;
+    gst_value_list_append_value (value, &v_format);
+    g_value_unset (&v_format);
+  }
+  return TRUE;
+}
+
+static void
+set_video_template_caps (GstCaps * caps)
+{
+  GstStructure *const structure = gst_caps_get_structure (caps, 0);
+
+  gst_structure_set (structure,
+      "width", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+      "height", GST_TYPE_INT_RANGE, 1, G_MAXINT,
+      "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+}
+
+GstCaps *
+gst_vaapi_video_format_new_template_caps (GstVideoFormat format)
+{
+  GstCaps *caps;
+
+  g_return_val_if_fail (format != GST_VIDEO_FORMAT_UNKNOWN, NULL);
+
+  caps = gst_caps_new_empty_simple ("video/x-raw");
+  if (!caps)
+    return NULL;
+
+  gst_caps_set_simple (caps,
+      "format", G_TYPE_STRING, gst_video_format_to_string (format), NULL);
+  set_video_template_caps (caps);
+  return caps;
+}
+
+GstCaps *
+gst_vaapi_video_format_new_template_caps_from_list (GArray * formats)
+{
+  GValue v_formats = G_VALUE_INIT;
+  GstCaps *caps;
+
+  caps = gst_caps_new_empty_simple ("video/x-raw");
+  if (!caps)
+    return NULL;
+
+  if (!gst_vaapi_value_set_format_list (&v_formats, formats)) {
+    gst_caps_unref (caps);
+    return NULL;
+  }
+
+  gst_caps_set_value (caps, "format", &v_formats);
+  set_video_template_caps (caps);
+  g_value_unset (&v_formats);
+  return caps;
+}
+
+GstCaps *
+gst_vaapi_video_format_new_template_caps_with_features (GstVideoFormat format,
+    const gchar * features_string)
+{
+  GstCapsFeatures *features;
+  GstCaps *caps;
+
+  caps = gst_vaapi_video_format_new_template_caps (format);
+  if (!caps)
+    return NULL;
+
+  features = gst_caps_features_new (features_string, NULL);
+  if (!features) {
+    gst_caps_unref (caps);
+    return NULL;
+  }
+  gst_caps_set_features (caps, 0, features);
+  return caps;
+}
+
+static GstVideoFormat
+gst_vaapi_find_preferred_format (const GValue * format_list,
+    GstVideoFormat native_format)
+{
+  const GValue *frmt;
+  GstVideoFormat out_format;
+  guint i;
+
+  /* if one format, that is the one */
+  if (G_VALUE_HOLDS_STRING (format_list))
+    return gst_video_format_from_string (g_value_get_string (format_list));
+
+  if (!GST_VALUE_HOLDS_LIST (format_list)) {
+    GST_ERROR ("negotiated caps do not have a valid format");
+    return GST_VIDEO_FORMAT_UNKNOWN;
+  }
+
+  if (native_format == GST_VIDEO_FORMAT_UNKNOWN
+      || native_format == GST_VIDEO_FORMAT_ENCODED) {
+    native_format = GST_VIDEO_FORMAT_NV12;      /* default VA format */
+  }
+
+  /* search our native format in the list */
+  for (i = 0; i < gst_value_list_get_size (format_list); i++) {
+    frmt = gst_value_list_get_value (format_list, i);
+    out_format = gst_video_format_from_string (g_value_get_string (frmt));
+
+    /* GStreamer do not handle encoded formats nicely. Try the next
+     * one. */
+    if (out_format == GST_VIDEO_FORMAT_ENCODED)
+      continue;
+
+    if (native_format == out_format)
+      return out_format;
+  }
+
+  /* just pick the first valid format in the list */
+  i = 0;
+  do {
+    frmt = gst_value_list_get_value (format_list, i++);
+    out_format = gst_video_format_from_string (g_value_get_string (frmt));
+  } while (out_format == GST_VIDEO_FORMAT_ENCODED);
+
+  return out_format;
+}
+
+GstVaapiCapsFeature
+gst_vaapi_find_preferred_caps_feature (GstPad * pad, GstCaps * allowed_caps,
+    GstVideoFormat * out_format_ptr)
+{
+  GstVaapiCapsFeature feature = GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED;
+  guint i, j, num_structures;
+  GstCaps *peer_caps, *out_caps = NULL, *caps = NULL;
+  static const guint feature_list[] = { GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE,
+    GST_VAAPI_CAPS_FEATURE_DMABUF,
+    GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META,
+    GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY,
+  };
+
+  /* query with no filter */
+  peer_caps = gst_pad_peer_query_caps (pad, NULL);
+  if (!peer_caps)
+    goto cleanup;
+  if (gst_caps_is_empty (peer_caps))
+    goto cleanup;
+
+  /* filter against our allowed caps */
+  out_caps = gst_caps_intersect_full (allowed_caps, peer_caps,
+      GST_CAPS_INTERSECT_FIRST);
+
+  /* default feature */
+  feature = GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY;
+
+  /* if downstream requests caps ANY, system memory is preferred */
+  if (gst_caps_is_any (peer_caps))
+    goto find_format;
+
+  num_structures = gst_caps_get_size (out_caps);
+  for (i = 0; i < num_structures; i++) {
+    GstCapsFeatures *const features = gst_caps_get_features (out_caps, i);
+    GstStructure *const structure = gst_caps_get_structure (out_caps, i);
+
+    /* Skip ANY features, we need an exact match for correct evaluation */
+    if (gst_caps_features_is_any (features))
+      continue;
+
+    gst_caps_replace (&caps, NULL);
+    caps = gst_caps_new_full (gst_structure_copy (structure), NULL);
+    if (!caps)
+      continue;
+    gst_caps_set_features_simple (caps, gst_caps_features_copy (features));
+
+    for (j = 0; j < G_N_ELEMENTS (feature_list); j++) {
+      if (gst_vaapi_caps_feature_contains (caps, feature_list[j])
+          && feature < feature_list[j]) {
+        feature = feature_list[j];
+        break;
+      }
+    }
+
+    /* Stop at the first match, the caps should already be sorted out
+       by preference order from downstream elements */
+    if (feature != GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY)
+      break;
+  }
+
+find_format:
+  if (!caps)
+    caps = gst_caps_ref (out_caps);
+
+  if (out_format_ptr) {
+    GstVideoFormat out_format;
+    GstStructure *structure = NULL;
+    const GValue *format_list;
+
+    num_structures = gst_caps_get_size (caps);
+    for (i = 0; i < num_structures; i++) {
+      GstCapsFeatures *const features = gst_caps_get_features (caps, i);
+      if (gst_caps_features_contains (features,
+              gst_vaapi_caps_feature_to_string (feature))) {
+        structure = gst_caps_get_structure (caps, i);
+        break;
+      }
+    }
+    if (!structure)
+      goto cleanup;
+    format_list = gst_structure_get_value (structure, "format");
+    if (!format_list)
+      goto cleanup;
+    out_format = gst_vaapi_find_preferred_format (format_list, *out_format_ptr);
+    if (out_format == GST_VIDEO_FORMAT_UNKNOWN)
+      goto cleanup;
+
+    *out_format_ptr = out_format;
+  }
+
+cleanup:
+  gst_caps_replace (&caps, NULL);
+  gst_caps_replace (&out_caps, NULL);
+  gst_caps_replace (&peer_caps, NULL);
+  return feature;
+}
+
+const gchar *
+gst_vaapi_caps_feature_to_string (GstVaapiCapsFeature feature)
+{
+  const gchar *str;
+
+  switch (feature) {
+    case GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY:
+      str = GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY;
+      break;
+    case GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META:
+      str = GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META;
+      break;
+    case GST_VAAPI_CAPS_FEATURE_DMABUF:
+      str = GST_CAPS_FEATURE_MEMORY_DMABUF;
+      break;
+    case GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE:
+      str = GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE;
+      break;
+    default:
+      str = NULL;
+      break;
+  }
+  return str;
+}
+
+gboolean
+gst_caps_set_interlaced (GstCaps * caps, GstVideoInfo * vip)
+{
+  GstVideoInterlaceMode mode;
+  const gchar *mode_str;
+
+  mode = vip ? GST_VIDEO_INFO_INTERLACE_MODE (vip) :
+      GST_VIDEO_INTERLACE_MODE_PROGRESSIVE;
+  switch (mode) {
+    case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
+      mode_str = "progressive";
+      break;
+    case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
+      mode_str = "interleaved";
+      break;
+    case GST_VIDEO_INTERLACE_MODE_MIXED:
+      mode_str = "mixed";
+      break;
+    default:
+      GST_ERROR ("unsupported `interlace-mode' %d", mode);
+      return FALSE;
+  }
+
+  gst_caps_set_simple (caps, "interlace-mode", G_TYPE_STRING, mode_str, NULL);
+  return TRUE;
+}
+
+static gboolean
+_gst_caps_has_feature (const GstCaps * caps, const gchar * feature)
+{
+  guint i;
+
+  for (i = 0; i < gst_caps_get_size (caps); i++) {
+    GstCapsFeatures *const features = gst_caps_get_features (caps, i);
+    /* Skip ANY features, we need an exact match for correct evaluation */
+    if (gst_caps_features_is_any (features))
+      continue;
+    if (gst_caps_features_contains (features, feature))
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+gboolean
+gst_vaapi_caps_feature_contains (const GstCaps * caps,
+    GstVaapiCapsFeature feature)
+{
+  const gchar *feature_str;
+
+  g_return_val_if_fail (caps != NULL, FALSE);
+
+  feature_str = gst_vaapi_caps_feature_to_string (feature);
+  if (!feature_str)
+    return FALSE;
+
+  return _gst_caps_has_feature (caps, feature_str);
+}
+
+/* Checks whether the supplied caps contain VA surfaces */
+gboolean
+gst_caps_has_vaapi_surface (GstCaps * caps)
+{
+  g_return_val_if_fail (caps != NULL, FALSE);
+
+  return _gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE);
+}
+
+gboolean
+gst_caps_is_video_raw (GstCaps * caps)
+{
+  GstStructure *structure;
+
+  g_return_val_if_fail (caps != NULL, FALSE);
+
+  if (!gst_caps_is_fixed (caps))
+    return FALSE;
+  if (!_gst_caps_has_feature (caps, GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY))
+    return FALSE;
+  structure = gst_caps_get_structure (caps, 0);
+  return gst_structure_has_name (structure, "video/x-raw");
+}
+
+void
+gst_video_info_change_format (GstVideoInfo * vip, GstVideoFormat format,
+    guint width, guint height)
+{
+  GstVideoInfo vi = *vip;
+
+  gst_video_info_set_format (vip, format, width, height);
+
+  GST_VIDEO_INFO_INTERLACE_MODE (vip) = GST_VIDEO_INFO_INTERLACE_MODE (&vi);
+  GST_VIDEO_FORMAT_INFO_FLAGS (vip) = GST_VIDEO_FORMAT_INFO_FLAGS (&vi);
+  GST_VIDEO_INFO_VIEWS (vip) = GST_VIDEO_INFO_VIEWS (&vi);
+  GST_VIDEO_INFO_PAR_N (vip) = GST_VIDEO_INFO_PAR_N (&vi);
+  GST_VIDEO_INFO_PAR_D (vip) = GST_VIDEO_INFO_PAR_D (&vi);
+  GST_VIDEO_INFO_FPS_N (vip) = GST_VIDEO_INFO_FPS_N (&vi);
+  GST_VIDEO_INFO_FPS_D (vip) = GST_VIDEO_INFO_FPS_D (&vi);
+  GST_VIDEO_INFO_MULTIVIEW_MODE (vip) = GST_VIDEO_INFO_MULTIVIEW_MODE (&vi);
+  GST_VIDEO_INFO_MULTIVIEW_FLAGS (vip) = GST_VIDEO_INFO_MULTIVIEW_FLAGS (&vi);
+}
+
+/**
+ * gst_video_info_changed:
+ * @old: old #GstVideoInfo
+ * @new: new #GstVideoInfo
+ *
+ * Compares @old and @new
+ *
+ * Returns: %TRUE if @old has different format/width/height than
+ * @new. Otherwise, %FALSE.
+ **/
+gboolean
+gst_video_info_changed (const GstVideoInfo * old, const GstVideoInfo * new)
+{
+  if (GST_VIDEO_INFO_FORMAT (old) != GST_VIDEO_INFO_FORMAT (new))
+    return TRUE;
+  if (GST_VIDEO_INFO_WIDTH (old) != GST_VIDEO_INFO_WIDTH (new))
+    return TRUE;
+  if (GST_VIDEO_INFO_HEIGHT (old) != GST_VIDEO_INFO_HEIGHT (new))
+    return TRUE;
+  return FALSE;
+}
+
+/**
+ * gst_video_info_force_nv12_if_encoded:
+ * @vinfo: a #GstVideoInfo
+ *
+ * If the format of @vinfo is %GST_VIDEO_FORMAT_ENCODED it is changed
+ * to %GST_VIDEO_FORMAT_NV12.
+ **/
+void
+gst_video_info_force_nv12_if_encoded (GstVideoInfo * vinfo)
+{
+  if (GST_VIDEO_INFO_FORMAT (vinfo) != GST_VIDEO_FORMAT_ENCODED)
+    return;
+  gst_video_info_set_format (vinfo, GST_VIDEO_FORMAT_NV12,
+      GST_VIDEO_INFO_WIDTH (vinfo), GST_VIDEO_INFO_HEIGHT (vinfo));
+}
+
+/**
+ * gst_vaapi_create_test_display:
+ *
+ * Creates a temporal #GstVaapiDisplay instance, just for testing the
+ * supported features.
+ *
+ * Returns: a new #GstVaapiDisplay instances. Free with
+ * gst_object_unref () after use. Or %NULL if no VA display is
+ * available.
+ **/
+GstVaapiDisplay *
+gst_vaapi_create_test_display (void)
+{
+  guint i;
+  GstVaapiDisplay *display = NULL;
+  const GstVaapiDisplayType test_display_map[] = {
+#if GST_VAAPI_USE_DRM
+    GST_VAAPI_DISPLAY_TYPE_DRM,
+#endif
+#if GST_VAAPI_USE_X11
+    GST_VAAPI_DISPLAY_TYPE_X11,
+#endif
+  };
+
+  for (i = 0; i < G_N_ELEMENTS (test_display_map); i++) {
+    display = gst_vaapi_create_display (test_display_map[i], NULL);
+    if (display)
+      break;
+  }
+  return display;
+}
+
+/**
+ * gst_vaapi_driver_is_whitelisted:
+ * @display: a #GstVaapiDisplay
+ *
+ * Looks the VA-API driver vendors in an internal white-list.
+ *
+ * Returns: %TRUE if driver is in the white-list, otherwise %FALSE
+ **/
+gboolean
+gst_vaapi_driver_is_whitelisted (GstVaapiDisplay * display)
+{
+  const gchar *vendor;
+  guint i;
+  static const gchar *whitelist[] = {
+    "Intel i965 driver",
+    "Intel iHD driver",
+    "Mesa Gallium driver",
+    NULL
+  };
+
+  g_return_val_if_fail (display, FALSE);
+
+  if (g_getenv (GST_VAAPI_ALL_DRIVERS_ENV))
+    return TRUE;
+
+  vendor = gst_vaapi_display_get_vendor_string (display);
+  if (!vendor)
+    goto no_vendor;
+
+  for (i = 0; whitelist[i]; i++) {
+    if (g_ascii_strncasecmp (vendor, whitelist[i], strlen (whitelist[i])) == 0)
+      return TRUE;
+  }
+
+  GST_WARNING ("Unsupported VA driver: %s. Export environment variable "
+      GST_VAAPI_ALL_DRIVERS_ENV " to bypass", vendor);
+  return FALSE;
+
+  /* ERRORS */
+no_vendor:
+  {
+    GST_WARNING ("no VA-API driver vendor description");
+    return FALSE;
+  }
+}
+
+/**
+ * gst_vaapi_codecs_has_codec:
+ * @codecs: a #GArray of #GstVaapiCodec
+ * @codec: a #GstVaapiCodec to find in @codec
+ *
+ * Search in the available @codecs for the specific @codec.
+ *
+ * Returns: %TRUE if @codec is in @codecs
+ **/
+gboolean
+gst_vaapi_codecs_has_codec (GArray * codecs, GstVaapiCodec codec)
+{
+  guint i;
+  GstVaapiCodec c;
+
+  g_return_val_if_fail (codec, FALSE);
+
+  for (i = 0; i < codecs->len; i++) {
+    c = g_array_index (codecs, GstVaapiCodec, i);
+    if (c == codec)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+/**
+ * gst_vaapi_encoder_get_profiles_from_caps:
+ * @caps: a #GstCaps to detect
+ * @func: a #GstVaapiStrToProfileFunc
+ *
+ * This function will detect all profile strings in @caps and
+ * return the according GstVaapiProfile in array.
+ *
+ * Return: A #GArray of @GstVaapiProfile if succeed, %NULL if fail.
+ **/
+GArray *
+gst_vaapi_encoder_get_profiles_from_caps (GstCaps * caps,
+    GstVaapiStrToProfileFunc func)
+{
+  guint i, j;
+  GstVaapiProfile profile;
+  GArray *profiles = NULL;
+
+  if (!caps)
+    return NULL;
+
+  profiles = g_array_new (FALSE, FALSE, sizeof (GstVaapiProfile));
+  if (!profiles)
+    return NULL;
+
+  for (i = 0; i < gst_caps_get_size (caps); i++) {
+    GstStructure *const structure = gst_caps_get_structure (caps, i);
+    const GValue *const value = gst_structure_get_value (structure, "profile");
+
+    if (value && G_VALUE_HOLDS_STRING (value)) {
+      const gchar *str = g_value_get_string (value);
+      if (str) {
+        profile = func (str);
+        if (profile == GST_VAAPI_PROFILE_H264_BASELINE)
+          profile = GST_VAAPI_PROFILE_H264_CONSTRAINED_BASELINE;
+        if (profile != GST_VAAPI_PROFILE_UNKNOWN)
+          g_array_append_val (profiles, profile);
+      }
+    } else if (value && GST_VALUE_HOLDS_LIST (value)) {
+      const GValue *v;
+      const gchar *str;
+      for (j = 0; j < gst_value_list_get_size (value); j++) {
+        v = gst_value_list_get_value (value, j);
+        if (!v || !G_VALUE_HOLDS_STRING (v))
+          continue;
+
+        str = g_value_get_string (v);
+        if (str) {
+          profile = func (str);
+          if (profile != GST_VAAPI_PROFILE_UNKNOWN)
+            g_array_append_val (profiles, profile);
+        }
+      }
+    }
+  }
+
+  if (profiles->len == 0) {
+    g_array_unref (profiles);
+    profiles = NULL;
+  }
+
+  return profiles;
+}
+
+void
+gst_vaapi_caps_set_width_and_height_range (GstCaps * caps, gint min_width,
+    gint min_height, gint max_width, gint max_height)
+{
+  guint size, i;
+  GstStructure *structure;
+
+  /* Set the width/height info to caps */
+  size = gst_caps_get_size (caps);
+  for (i = 0; i < size; i++) {
+    structure = gst_caps_get_structure (caps, i);
+    if (!structure)
+      continue;
+    gst_structure_set (structure, "width", GST_TYPE_INT_RANGE, min_width,
+        max_width, "height", GST_TYPE_INT_RANGE, min_height, max_height,
+        "framerate", GST_TYPE_FRACTION_RANGE, 0, 1, G_MAXINT, 1, NULL);
+  }
+}
+
+/**
+ * gst_vaapi_build_caps_from_formats:
+ * @formats: an array of supported #GstVideoFormat
+ * @min_width: the min supported width
+ * @min_height: the min supported height
+ * @max_width: the max supported width
+ * @max_height: the max supported height
+ * @mem_types: the supported VA mem types
+ *
+ * This function generates a #GstCaps based on the information such as
+ * formats, width and height.
+ *
+ * Return: A #GstCaps.
+ **/
+GstCaps *
+gst_vaapi_build_caps_from_formats (GArray * formats, gint min_width,
+    gint min_height, gint max_width, gint max_height, guint mem_types)
+{
+  GstCaps *out_caps, *raw_caps, *va_caps, *dma_caps;
+
+  dma_caps = NULL;
+
+  raw_caps = gst_vaapi_video_format_new_template_caps_from_list (formats);
+  if (!raw_caps)
+    return NULL;
+  gst_vaapi_caps_set_width_and_height_range (raw_caps, min_width, min_height,
+      max_width, max_height);
+
+  va_caps = gst_caps_copy (raw_caps);
+  gst_caps_set_features_simple (va_caps,
+      gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE));
+
+  if (gst_vaapi_mem_type_supports (mem_types,
+          GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF) ||
+      gst_vaapi_mem_type_supports (mem_types,
+          GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF2)) {
+    dma_caps = gst_caps_copy (raw_caps);
+    gst_caps_set_features_simple (dma_caps,
+        gst_caps_features_from_string (GST_CAPS_FEATURE_MEMORY_DMABUF));
+  }
+
+  out_caps = va_caps;
+  if (dma_caps)
+    gst_caps_append (out_caps, dma_caps);
+  gst_caps_append (out_caps, raw_caps);
+
+  return out_caps;
+}
+
+/**
+ * gst_vaapi_build_template_raw_caps_by_codec:
+ * @display: a #GstVaapiDisplay
+ * @usage: used for encode, decode or postproc
+ * @codec: a #GstVaapiCodec specify the codec to detect
+ * @extra_fmts: a #GArray of extra #GstVideoFormat
+ *
+ * Called by vaapi elements to detect the all possible video formats belong to
+ * the specified codec and build the caps. Only YUV kinds of formats are detected
+ * because so far almost all codecs use YUV kinds of formats as input/output.
+ * extra_fmts can specified more formats to be included.
+ *
+ * Returns: a built #GstCaps if succeeds, or %NULL if error.
+ **/
+GstCaps *
+gst_vaapi_build_template_raw_caps_by_codec (GstVaapiDisplay * display,
+    GstVaapiContextUsage usage, GstVaapiCodec codec, GArray * extra_fmts)
+{
+  GArray *profiles = NULL;
+  GArray *supported_fmts = NULL;
+  GstCaps *out_caps = NULL;
+  guint i, e;
+  GstVaapiProfile profile;
+  guint value;
+  guint chroma;
+  GstVaapiChromaType gst_chroma;
+  GstVaapiEntrypoint entrypoint_start, entrypoint_end;
+
+  if (usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) {
+    profiles = gst_vaapi_display_get_encode_profiles (display);
+    entrypoint_start = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE;
+    entrypoint_end = GST_VAAPI_ENTRYPOINT_SLICE_ENCODE_LP;
+  } else if (usage == GST_VAAPI_CONTEXT_USAGE_DECODE) {
+    profiles = gst_vaapi_display_get_decode_profiles (display);
+    entrypoint_start = GST_VAAPI_ENTRYPOINT_VLD;
+    entrypoint_end = GST_VAAPI_ENTRYPOINT_MOCO;
+  }
+  /* TODO: VPP */
+
+  if (!profiles)
+    goto out;
+
+  chroma = 0;
+  for (i = 0; i < profiles->len; i++) {
+    profile = g_array_index (profiles, GstVaapiProfile, i);
+    if (gst_vaapi_profile_get_codec (profile) != codec)
+      continue;
+
+    for (e = entrypoint_start; e <= entrypoint_end; e++) {
+      if (!gst_vaapi_get_config_attribute (display,
+              gst_vaapi_profile_get_va_profile (profile),
+              gst_vaapi_entrypoint_get_va_entrypoint (e),
+              VAConfigAttribRTFormat, &value))
+        continue;
+
+      chroma |= value;
+    }
+  }
+
+  if (!chroma)
+    goto out;
+
+  for (gst_chroma = GST_VAAPI_CHROMA_TYPE_YUV420;
+      gst_chroma <= GST_VAAPI_CHROMA_TYPE_YUV444_12BPP; gst_chroma++) {
+    GArray *fmts;
+    if (!(chroma & from_GstVaapiChromaType (gst_chroma)))
+      continue;
+
+    fmts = gst_vaapi_video_format_get_formats_by_chroma (gst_chroma);
+    if (!fmts)
+      continue;
+
+    /* One format can not belong to different chroma, no need to merge */
+    if (supported_fmts == NULL) {
+      supported_fmts = fmts;
+    } else {
+      for (i = 0; i < fmts->len; i++)
+        g_array_append_val (supported_fmts,
+            g_array_index (fmts, GstVideoFormat, i));
+      g_array_unref (fmts);
+    }
+  }
+
+  if (!supported_fmts)
+    goto out;
+
+  if (extra_fmts) {
+    for (i = 0; i < extra_fmts->len; i++)
+      g_array_append_val (supported_fmts,
+          g_array_index (extra_fmts, GstVideoFormat, i));
+  }
+
+  out_caps = gst_vaapi_build_caps_from_formats (supported_fmts, 1, 1,
+      G_MAXINT, G_MAXINT,
+      from_GstVaapiBufferMemoryType (GST_VAAPI_BUFFER_MEMORY_TYPE_DMA_BUF));
+
+out:
+  if (profiles)
+    g_array_unref (profiles);
+  if (supported_fmts)
+    g_array_unref (supported_fmts);
+
+  return out_caps;
+}
+
+/**
+ * gst_vaapi_structure_set_profiles:
+ * @st: a #GstStructure
+ * @list: a %NULL-terminated array of strings
+ *
+ * The @list of profiles are set in @st
+ **/
+void
+gst_vaapi_structure_set_profiles (GstStructure * st, gchar ** list)
+{
+  guint i;
+  GValue vlist = G_VALUE_INIT;
+  GValue value = G_VALUE_INIT;
+
+  g_value_init (&vlist, GST_TYPE_LIST);
+  g_value_init (&value, G_TYPE_STRING);
+
+  for (i = 0; list[i]; i++) {
+    g_value_set_string (&value, list[i]);
+    gst_value_list_append_value (&vlist, &value);
+  }
+
+  if (i == 1)
+    gst_structure_set_value (st, "profile", &value);
+  else if (i > 1)
+    gst_structure_set_value (st, "profile", &vlist);
+
+  g_value_unset (&value);
+  g_value_unset (&vlist);
+}
+
+/**
+ * gst_vaapi_build_template_coded_caps_by_codec:
+ * @display: a #GstVaapiDisplay
+ * @usage: used for encode or decode
+ * @codec: a #GstVaapiCodec specify the codec to detect
+ * @caps_str: a string of basic caps
+ *
+ * Called by vaapi elements to detect the all possible profiles belong to the
+ * specified codec and build the caps based on the basic caps description.
+ *
+ * Returns: a built #GstCaps if succeeds, or %NULL if error.
+ **/
+GstCaps *
+gst_vaapi_build_template_coded_caps_by_codec (GstVaapiDisplay * display,
+    GstVaapiContextUsage usage, GstVaapiCodec codec, const char *caps_str,
+    GstVaapiProfileToStrFunc func)
+{
+  GValue v_profiles = G_VALUE_INIT;
+  GValue v_profile = G_VALUE_INIT;
+  GstCaps *caps = NULL;
+  guint i, num;
+  GArray *profiles = NULL;
+  GstVaapiProfile profile;
+  const gchar *str;
+
+  caps = gst_caps_from_string (caps_str);
+  if (!caps)
+    goto out;
+
+  if (!func)
+    goto out;
+
+  /* If no profiles, just ignore the profile field. */
+  if (usage == GST_VAAPI_CONTEXT_USAGE_ENCODE) {
+    profiles = gst_vaapi_display_get_encode_profiles (display);
+  } else if (usage == GST_VAAPI_CONTEXT_USAGE_DECODE) {
+    profiles = gst_vaapi_display_get_decode_profiles (display);
+  }
+  if (!profiles || profiles->len == 0)
+    goto out;
+
+  num = 0;
+  g_value_init (&v_profiles, GST_TYPE_LIST);
+  g_value_init (&v_profile, G_TYPE_STRING);
+
+  for (i = 0; i < profiles->len; i++) {
+    profile = g_array_index (profiles, GstVaapiProfile, i);
+    if (gst_vaapi_profile_get_codec (profile) != codec)
+      continue;
+
+    str = func (profile);
+    if (!str)
+      continue;
+
+    g_value_set_string (&v_profile, str);
+    num++;
+    gst_value_list_append_value (&v_profiles, &v_profile);
+  }
+
+  if (num == 1) {
+    gst_caps_set_value (caps, "profile", &v_profile);
+  } else if (num > 1) {
+    gst_caps_set_value (caps, "profile", &v_profiles);
+  }
+
+out:
+  g_value_unset (&v_profile);
+  g_value_unset (&v_profiles);
+  if (profiles)
+    g_array_unref (profiles);
+
+  return caps;
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginutil.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipluginutil.h
new file mode 100644 (file)
index 0000000..236ccd3
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *  gstvaapipluginutil.h - VA-API plugins private helper
+ *
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *  Copyright (C) 2011 Collabora
+ *    Author: Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_PLUGIN_UTIL_H
+#define GST_VAAPI_PLUGIN_UTIL_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapicontext.h>
+#include "gstvaapivideomemory.h"
+
+typedef GstVaapiProfile (*GstVaapiStrToProfileFunc) (const gchar * str);
+typedef const gchar * (*GstVaapiProfileToStrFunc) (GstVaapiProfile profile);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_ensure_display (GstElement * element, GstVaapiDisplayType type);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_handle_context_query (GstElement * element, GstQuery * query);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_append_surface_caps (GstCaps * out_caps, GstCaps * in_caps);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_apply_composition (GstVaapiSurface * surface, GstBuffer * buffer);
+
+#ifndef G_PRIMITIVE_SWAP
+#define G_PRIMITIVE_SWAP(type, a, b) do {       \
+        const type t = a; a = b; b = t;         \
+    } while (0)
+#endif
+
+/* Helpers for GValue construction for video formats */
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_value_set_format (GValue * value, GstVideoFormat format);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_value_set_format_list (GValue * value, GArray * formats);
+
+/* Helpers to build video caps */
+typedef enum
+{
+  GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED,
+  GST_VAAPI_CAPS_FEATURE_SYSTEM_MEMORY,
+  GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META,
+  GST_VAAPI_CAPS_FEATURE_DMABUF,
+  GST_VAAPI_CAPS_FEATURE_VAAPI_SURFACE,
+} GstVaapiCapsFeature;
+
+G_GNUC_INTERNAL
+GstCaps *
+gst_vaapi_video_format_new_template_caps (GstVideoFormat format);
+
+G_GNUC_INTERNAL
+GstCaps *
+gst_vaapi_video_format_new_template_caps_from_list (GArray * formats);
+
+G_GNUC_INTERNAL
+GstCaps *
+gst_vaapi_video_format_new_template_caps_with_features (GstVideoFormat format,
+    const gchar * features_string);
+
+G_GNUC_INTERNAL
+GstVaapiCapsFeature
+gst_vaapi_find_preferred_caps_feature (GstPad * pad, GstCaps * allowed_caps,
+    GstVideoFormat * out_format_ptr);
+
+G_GNUC_INTERNAL
+const gchar *
+gst_vaapi_caps_feature_to_string (GstVaapiCapsFeature feature);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_caps_feature_contains (const GstCaps * caps,
+    GstVaapiCapsFeature feature);
+
+/* Helpers to handle interlaced contents */
+# define GST_CAPS_INTERLACED_MODES \
+    "interlace-mode = (string){ progressive, interleaved, mixed }"
+# define GST_CAPS_INTERLACED_FALSE \
+    "interlace-mode = (string)progressive"
+
+#define GST_VAAPI_MAKE_SURFACE_CAPS                                     \
+    GST_VIDEO_CAPS_MAKE_WITH_FEATURES(                                  \
+        GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, GST_VAAPI_FORMATS_ALL)
+
+#define GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS                                 \
+    GST_VIDEO_CAPS_MAKE_WITH_FEATURES(                                  \
+        GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META, "{ RGBA, BGRA }")
+
+#define GST_VAAPI_MAKE_DMABUF_CAPS                                      \
+    GST_VIDEO_CAPS_MAKE_WITH_FEATURES(                                  \
+        GST_CAPS_FEATURE_MEMORY_DMABUF, "{ I420, YV12, RGBA }")
+
+G_GNUC_INTERNAL
+gboolean
+gst_caps_set_interlaced (GstCaps * caps, GstVideoInfo * vip);
+
+G_GNUC_INTERNAL
+gboolean
+gst_caps_has_vaapi_surface (GstCaps * caps);
+
+G_GNUC_INTERNAL
+gboolean
+gst_caps_is_video_raw (GstCaps * caps);
+
+G_GNUC_INTERNAL
+void
+gst_video_info_change_format (GstVideoInfo * vip, GstVideoFormat format,
+    guint width, guint height);
+
+G_GNUC_INTERNAL
+gboolean
+gst_video_info_changed (const GstVideoInfo * old, const GstVideoInfo * new);
+
+G_GNUC_INTERNAL
+void
+gst_video_info_force_nv12_if_encoded (GstVideoInfo * vinfo);
+
+G_GNUC_INTERNAL
+GstVaapiDisplay *
+gst_vaapi_create_test_display (void);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_driver_is_whitelisted (GstVaapiDisplay * display);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_codecs_has_codec (GArray * codecs, GstVaapiCodec codec);
+
+G_GNUC_INTERNAL
+GArray *
+gst_vaapi_encoder_get_profiles_from_caps (GstCaps * caps,
+    GstVaapiStrToProfileFunc func);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_caps_set_width_and_height_range (GstCaps * caps, gint min_width,
+    gint min_height, gint max_width, gint max_height);
+
+G_GNUC_INTERNAL
+GstCaps *
+gst_vaapi_build_caps_from_formats (GArray * formats, gint min_width,
+    gint min_height, gint max_width, gint max_height, guint mem_type);
+
+G_GNUC_INTERNAL
+GstCaps *
+gst_vaapi_build_template_raw_caps_by_codec (GstVaapiDisplay * display,
+    GstVaapiContextUsage usage, GstVaapiCodec codec, GArray * extra_fmts);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_structure_set_profiles (GstStructure * st, gchar ** list);
+
+G_GNUC_INTERNAL
+GstCaps *
+gst_vaapi_build_template_coded_caps_by_codec (GstVaapiDisplay * display,
+    GstVaapiContextUsage usage, GstVaapiCodec codec, const char *caps_str,
+    GstVaapiProfileToStrFunc func);
+
+#endif /* GST_VAAPI_PLUGIN_UTIL_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostproc.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostproc.c
new file mode 100644 (file)
index 0000000..0b1debc
--- /dev/null
@@ -0,0 +1,2803 @@
+/*
+ *  gstvaapipostproc.c - VA-API video postprocessing
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapipostproc
+ * @short_description: A VA-API base video postprocessing filter
+ *
+ * vaapipostproc consists in various postprocessing algorithms to be
+ * applied to VA surfaces.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 videotestsrc ! vaapipostproc ! video/x-raw, width=1920, height=1080 ! vaapisink
+ * ]|
+ */
+
+#include "gstcompat.h"
+#include <gst/video/video.h>
+
+#include <gst/vaapi/gstvaapivalue.h>
+
+#include "gstvaapipostproc.h"
+#include "gstvaapipostprocutil.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideobuffer.h"
+#include "gstvaapivideobufferpool.h"
+#include "gstvaapivideomemory.h"
+
+#define GST_PLUGIN_NAME "vaapipostproc"
+#define GST_PLUGIN_DESC "A VA-API video postprocessing filter"
+
+GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapipostproc);
+#ifndef GST_DISABLE_GST_DEBUG
+#define GST_CAT_DEFAULT gst_debug_vaapipostproc
+#else
+#define GST_CAT_DEFAULT NULL
+#endif
+
+/* Default templates */
+/* *INDENT-OFF* */
+static const char gst_vaapipostproc_sink_caps_str[] =
+  GST_VAAPI_MAKE_SURFACE_CAPS ", "
+  GST_CAPS_INTERLACED_MODES "; "
+  GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL) ", "
+  GST_CAPS_INTERLACED_MODES "; "
+  GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_DMABUF,
+      GST_VAAPI_FORMATS_ALL) ", "
+  GST_CAPS_INTERLACED_MODES;
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+static const char gst_vaapipostproc_src_caps_str[] =
+  GST_VAAPI_MAKE_SURFACE_CAPS ", "
+  GST_CAPS_INTERLACED_FALSE "; "
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+  GST_VAAPI_MAKE_GLTEXUPLOAD_CAPS "; "
+#endif
+  GST_VIDEO_CAPS_MAKE (GST_VAAPI_FORMATS_ALL) ", "
+  GST_CAPS_INTERLACED_MODES;
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+static GstStaticPadTemplate gst_vaapipostproc_sink_factory =
+  GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (gst_vaapipostproc_sink_caps_str));
+/* *INDENT-ON* */
+
+/* *INDENT-OFF* */
+static GstStaticPadTemplate gst_vaapipostproc_src_factory =
+  GST_STATIC_PAD_TEMPLATE ("src",
+    GST_PAD_SRC,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (gst_vaapipostproc_src_caps_str));
+/* *INDENT-ON* */
+
+static void gst_vaapipostproc_colorbalance_init (gpointer iface, gpointer data);
+
+G_DEFINE_TYPE_WITH_CODE (GstVaapiPostproc, gst_vaapipostproc,
+    GST_TYPE_BASE_TRANSFORM, GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES
+    G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
+        gst_vaapipostproc_colorbalance_init));
+
+GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (gst_vaapipostproc_parent_class);
+
+static GstVideoFormat native_formats[] =
+    { GST_VIDEO_FORMAT_NV12, GST_VIDEO_FORMAT_YV12, GST_VIDEO_FORMAT_I420 };
+
+enum
+{
+  PROP_0,
+
+#ifndef GST_REMOVE_DEPRECATED
+  PROP_FORMAT,
+  PROP_WIDTH,
+  PROP_HEIGHT,
+#endif
+  PROP_FORCE_ASPECT_RATIO,
+  PROP_DEINTERLACE_MODE,
+  PROP_DEINTERLACE_METHOD,
+  PROP_DENOISE,
+  PROP_SHARPEN,
+  PROP_HUE,
+  PROP_SATURATION,
+  PROP_BRIGHTNESS,
+  PROP_CONTRAST,
+  PROP_SCALE_METHOD,
+  PROP_VIDEO_DIRECTION,
+  PROP_CROP_LEFT,
+  PROP_CROP_RIGHT,
+  PROP_CROP_TOP,
+  PROP_CROP_BOTTOM,
+  PROP_HDR_TONE_MAP,
+#ifndef GST_REMOVE_DEPRECATED
+  PROP_SKIN_TONE_ENHANCEMENT,
+#endif
+  PROP_SKIN_TONE_ENHANCEMENT_LEVEL,
+};
+
+#define GST_VAAPI_TYPE_HDR_TONE_MAP \
+    gst_vaapi_hdr_tone_map_get_type()
+
+static GType
+gst_vaapi_hdr_tone_map_get_type (void)
+{
+  static gsize g_type = 0;
+
+  static const GEnumValue enum_values[] = {
+    {GST_VAAPI_HDR_TONE_MAP_AUTO,
+        "Auto detection", "auto"},
+    {GST_VAAPI_HDR_TONE_MAP_DISABLED,
+        "Disable HDR tone mapping", "disabled"},
+    {0, NULL, NULL},
+  };
+
+  if (g_once_init_enter (&g_type)) {
+    const GType type =
+        g_enum_register_static ("GstVaapiHDRToneMap", enum_values);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+#define GST_VAAPI_TYPE_DEINTERLACE_MODE \
+    gst_vaapi_deinterlace_mode_get_type()
+
+static GType
+gst_vaapi_deinterlace_mode_get_type (void)
+{
+  static GType deinterlace_mode_type = 0;
+
+  static const GEnumValue mode_types[] = {
+    {GST_VAAPI_DEINTERLACE_MODE_AUTO,
+        "Auto detection", "auto"},
+    {GST_VAAPI_DEINTERLACE_MODE_INTERLACED,
+        "Force deinterlacing", "interlaced"},
+    {GST_VAAPI_DEINTERLACE_MODE_DISABLED,
+        "Never deinterlace", "disabled"},
+    {0, NULL, NULL},
+  };
+
+  if (!deinterlace_mode_type) {
+    deinterlace_mode_type =
+        g_enum_register_static ("GstVaapiDeinterlaceMode", mode_types);
+  }
+  return deinterlace_mode_type;
+}
+
+static void
+ds_reset (GstVaapiDeinterlaceState * ds)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (ds->buffers); i++)
+    gst_buffer_replace (&ds->buffers[i], NULL);
+  ds->buffers_index = 0;
+  ds->num_surfaces = 0;
+  ds->deint = FALSE;
+  ds->tff = FALSE;
+}
+
+static void
+ds_add_buffer (GstVaapiDeinterlaceState * ds, GstBuffer * buf)
+{
+  gst_buffer_replace (&ds->buffers[ds->buffers_index], buf);
+  ds->buffers_index = (ds->buffers_index + 1) % G_N_ELEMENTS (ds->buffers);
+}
+
+static inline GstBuffer *
+ds_get_buffer (GstVaapiDeinterlaceState * ds, guint index)
+{
+  /* Note: the index increases towards older buffers.
+     i.e. buffer at index 0 means the immediately preceding buffer
+     in the history, buffer at index 1 means the one preceding the
+     surface at index 0, etc. */
+  const guint n = ds->buffers_index + G_N_ELEMENTS (ds->buffers) - index - 1;
+  return ds->buffers[n % G_N_ELEMENTS (ds->buffers)];
+}
+
+static void
+ds_set_surfaces (GstVaapiDeinterlaceState * ds)
+{
+  GstVaapiVideoMeta *meta;
+  guint i;
+
+  ds->num_surfaces = 0;
+  for (i = 0; i < G_N_ELEMENTS (ds->buffers); i++) {
+    GstBuffer *const buf = ds_get_buffer (ds, i);
+    if (!buf)
+      break;
+
+    meta = gst_buffer_get_vaapi_video_meta (buf);
+    ds->surfaces[ds->num_surfaces++] = gst_vaapi_video_meta_get_surface (meta);
+  }
+}
+
+static GstVaapiFilterOpInfo *
+find_filter_op (GPtrArray * filter_ops, GstVaapiFilterOp op)
+{
+  guint i;
+
+  if (filter_ops) {
+    for (i = 0; i < filter_ops->len; i++) {
+      GstVaapiFilterOpInfo *const filter_op = g_ptr_array_index (filter_ops, i);
+      if (filter_op->op == op)
+        return filter_op;
+    }
+  }
+  return NULL;
+}
+
+static inline gboolean
+gst_vaapipostproc_ensure_display (GstVaapiPostproc * postproc)
+{
+  return
+      gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (postproc));
+}
+
+static gboolean
+gst_vaapipostproc_ensure_filter (GstVaapiPostproc * postproc)
+{
+  if (postproc->filter)
+    return TRUE;
+
+  if (!gst_vaapipostproc_ensure_display (postproc))
+    return FALSE;
+
+  gst_caps_replace (&postproc->allowed_srcpad_caps, NULL);
+  gst_caps_replace (&postproc->allowed_sinkpad_caps, NULL);
+
+  postproc->filter =
+      gst_vaapi_filter_new (GST_VAAPI_PLUGIN_BASE_DISPLAY (postproc));
+  if (!postproc->filter)
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapipostproc_ensure_filter_caps (GstVaapiPostproc * postproc)
+{
+  if (!gst_vaapipostproc_ensure_filter (postproc))
+    return FALSE;
+
+  if (!postproc->filter_ops) {
+    postproc->filter_ops = gst_vaapi_filter_get_operations (postproc->filter);
+    if (!postproc->filter_ops)
+      return FALSE;
+  }
+
+  if (!postproc->filter_formats) {
+    postproc->filter_formats = gst_vaapi_filter_get_formats
+        (postproc->filter, NULL, NULL, NULL, NULL);
+    if (!postproc->filter_formats)
+      return FALSE;
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_vaapipostproc_create (GstVaapiPostproc * postproc)
+{
+  if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (postproc)))
+    return FALSE;
+  if (!gst_vaapipostproc_ensure_display (postproc))
+    return FALSE;
+
+  postproc->use_vpp = FALSE;
+  postproc->has_vpp = gst_vaapipostproc_ensure_filter (postproc);
+  return TRUE;
+}
+
+static void
+gst_vaapipostproc_destroy_filter (GstVaapiPostproc * postproc)
+{
+  if (postproc->filter_formats) {
+    g_array_unref (postproc->filter_formats);
+    postproc->filter_formats = NULL;
+  }
+
+  if (postproc->filter_ops) {
+    g_ptr_array_unref (postproc->filter_ops);
+    postproc->filter_ops = NULL;
+  }
+  if (postproc->cb_channels) {
+    g_list_free_full (postproc->cb_channels, g_object_unref);
+    postproc->cb_channels = NULL;
+  }
+  gst_vaapi_filter_replace (&postproc->filter, NULL);
+  gst_vaapi_video_pool_replace (&postproc->filter_pool, NULL);
+}
+
+static void
+gst_vaapipostproc_destroy (GstVaapiPostproc * postproc)
+{
+  ds_reset (&postproc->deinterlace_state);
+  gst_vaapipostproc_destroy_filter (postproc);
+
+  gst_caps_replace (&postproc->allowed_sinkpad_caps, NULL);
+  gst_caps_replace (&postproc->allowed_srcpad_caps, NULL);
+  gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (postproc));
+}
+
+static gboolean
+gst_vaapipostproc_start (GstBaseTransform * trans)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+
+  ds_reset (&postproc->deinterlace_state);
+  if (!gst_vaapi_plugin_base_open (GST_VAAPI_PLUGIN_BASE (postproc)))
+    return FALSE;
+  g_mutex_lock (&postproc->postproc_lock);
+  gst_vaapipostproc_ensure_filter (postproc);
+  g_mutex_unlock (&postproc->postproc_lock);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapipostproc_stop (GstBaseTransform * trans)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+
+  g_mutex_lock (&postproc->postproc_lock);
+  ds_reset (&postproc->deinterlace_state);
+  gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (postproc));
+
+  postproc->field_duration = GST_CLOCK_TIME_NONE;
+  gst_video_info_init (&postproc->sinkpad_info);
+  gst_video_info_init (&postproc->srcpad_info);
+  gst_video_info_init (&postproc->filter_pool_info);
+  g_mutex_unlock (&postproc->postproc_lock);
+
+  return TRUE;
+}
+
+static gboolean
+should_deinterlace_buffer (GstVaapiPostproc * postproc, GstBuffer * buf)
+{
+  if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) ||
+      postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_DISABLED)
+    return FALSE;
+
+  if (postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_INTERLACED)
+    return TRUE;
+
+  g_assert (postproc->deinterlace_mode == GST_VAAPI_DEINTERLACE_MODE_AUTO);
+
+  switch (GST_VIDEO_INFO_INTERLACE_MODE (&postproc->sinkpad_info)) {
+    case GST_VIDEO_INTERLACE_MODE_INTERLEAVED:
+      return TRUE;
+    case GST_VIDEO_INTERLACE_MODE_PROGRESSIVE:
+      return FALSE;
+    case GST_VIDEO_INTERLACE_MODE_MIXED:
+      if (GST_BUFFER_FLAG_IS_SET (buf, GST_VIDEO_BUFFER_FLAG_INTERLACED))
+        return TRUE;
+      break;
+    default:
+      GST_ERROR_OBJECT (postproc,
+          "unhandled \"interlace-mode\", disabling deinterlacing");
+      break;
+  }
+  return FALSE;
+}
+
+static GstBuffer *
+create_output_buffer (GstVaapiPostproc * postproc)
+{
+  GstBuffer *outbuf;
+
+  GstBufferPool *const pool =
+      GST_VAAPI_PLUGIN_BASE_SRC_PAD_BUFFER_POOL (postproc);
+  GstFlowReturn ret;
+
+  g_return_val_if_fail (pool != NULL, NULL);
+
+  if (!gst_buffer_pool_is_active (pool) &&
+      !gst_buffer_pool_set_active (pool, TRUE))
+    goto error_activate_pool;
+
+  outbuf = NULL;
+  ret = gst_buffer_pool_acquire_buffer (pool, &outbuf, NULL);
+  if (ret != GST_FLOW_OK || !outbuf)
+    goto error_create_buffer;
+  return outbuf;
+
+  /* ERRORS */
+error_activate_pool:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to activate output video buffer pool");
+    return NULL;
+  }
+error_create_buffer:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to create output video buffer");
+    return NULL;
+  }
+}
+
+static inline GstBuffer *
+create_output_dump_buffer (GstVaapiPostproc * postproc)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (postproc);
+
+  return
+      gst_buffer_new_allocate (GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR (plugin),
+      GST_VIDEO_INFO_SIZE (GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO (plugin)),
+      &GST_VAAPI_PLUGIN_BASE_OTHER_ALLOCATOR_PARAMS (plugin));
+}
+
+static void
+copy_metadata (GstVaapiPostproc * postproc, GstBuffer * outbuf,
+    GstBuffer * inbuf)
+{
+  GstBaseTransformClass *bclass = GST_BASE_TRANSFORM_GET_CLASS (postproc);
+  GstBaseTransform *trans = GST_BASE_TRANSFORM (postproc);
+
+  if (inbuf == outbuf)
+    return;
+  if (!bclass->copy_metadata)
+    return;
+  if (!bclass->copy_metadata (trans, inbuf, outbuf)) {
+    /* something failed, post a warning */
+    GST_ELEMENT_WARNING (trans, STREAM, NOT_IMPLEMENTED,
+        ("could not copy metadata"), (NULL));
+  }
+}
+
+static gboolean
+append_output_buffer_metadata (GstVaapiPostproc * postproc, GstBuffer * outbuf,
+    GstBuffer * inbuf, guint flags)
+{
+  GstVaapiVideoMeta *inbuf_meta, *outbuf_meta;
+  GstVaapiSurfaceProxy *proxy;
+
+  gst_buffer_copy_into (outbuf, inbuf, flags | GST_BUFFER_COPY_FLAGS, 0, -1);
+
+  copy_metadata (postproc, outbuf, inbuf);
+
+  /* GstVaapiVideoMeta */
+  inbuf_meta = gst_buffer_get_vaapi_video_meta (inbuf);
+  g_return_val_if_fail (inbuf_meta != NULL, FALSE);
+  proxy = gst_vaapi_video_meta_get_surface_proxy (inbuf_meta);
+
+  outbuf_meta = gst_buffer_get_vaapi_video_meta (outbuf);
+  g_return_val_if_fail (outbuf_meta != NULL, FALSE);
+  proxy = gst_vaapi_surface_proxy_copy (proxy);
+  if (!proxy)
+    return FALSE;
+
+  gst_vaapi_video_meta_set_surface_proxy (outbuf_meta, proxy);
+  gst_vaapi_surface_proxy_unref (proxy);
+  return TRUE;
+}
+
+static gboolean
+deint_method_is_advanced (GstVaapiDeinterlaceMethod deint_method)
+{
+  gboolean is_advanced;
+
+  switch (deint_method) {
+    case GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE:
+    case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
+      is_advanced = TRUE;
+      break;
+    default:
+      is_advanced = FALSE;
+      break;
+  }
+  return is_advanced;
+}
+
+static GstVaapiDeinterlaceMethod
+get_next_deint_method (GstVaapiDeinterlaceMethod deint_method)
+{
+  switch (deint_method) {
+    case GST_VAAPI_DEINTERLACE_METHOD_MOTION_COMPENSATED:
+      deint_method = GST_VAAPI_DEINTERLACE_METHOD_MOTION_ADAPTIVE;
+      break;
+    default:
+      /* Default to basic "bob" for all others */
+      deint_method = GST_VAAPI_DEINTERLACE_METHOD_BOB;
+      break;
+  }
+  return deint_method;
+}
+
+static gboolean
+set_best_deint_method (GstVaapiPostproc * postproc, guint flags,
+    GstVaapiDeinterlaceMethod * deint_method_ptr)
+{
+  GstVaapiDeinterlaceMethod deint_method = postproc->deinterlace_method;
+  gboolean success;
+
+  for (;;) {
+    success = gst_vaapi_filter_set_deinterlacing (postproc->filter,
+        deint_method, flags);
+    if (success || deint_method == GST_VAAPI_DEINTERLACE_METHOD_BOB)
+      break;
+    deint_method = get_next_deint_method (deint_method);
+  }
+  *deint_method_ptr = deint_method;
+  return success;
+}
+
+static gboolean
+should_hdr_tone_map (GstVaapiPostproc * const postproc, const GstCaps * caps)
+{
+  switch (postproc->hdr_tone_map) {
+    case GST_VAAPI_HDR_TONE_MAP_AUTO:
+    {
+      GstVideoMasteringDisplayInfo minfo;
+      return gst_video_mastering_display_info_from_caps (&minfo, caps);
+    }
+    case GST_VAAPI_HDR_TONE_MAP_DISABLED:
+      return FALSE;
+    default:
+      GST_ERROR_OBJECT (postproc, "unhandled \"hdr-tone-map\" option");
+      break;
+  }
+  return FALSE;
+}
+
+static gboolean
+configure_hdr_tone_map (GstVaapiPostproc * const postproc, const GstCaps * caps)
+{
+  gboolean enable;
+
+  g_return_val_if_fail (postproc->has_vpp, FALSE);
+
+  enable = should_hdr_tone_map (postproc, caps);
+
+  if (!gst_vaapi_filter_set_hdr_tone_map (postproc->filter, enable))
+    goto fail_configure_hdr_tone_map;
+
+  if (enable) {
+    GstVideoMasteringDisplayInfo minfo;
+    GstVideoContentLightLevel linfo;
+
+    gst_video_mastering_display_info_from_caps (&minfo, caps);
+    gst_video_content_light_level_from_caps (&linfo, caps);
+
+    if (!gst_vaapi_filter_set_hdr_tone_map_meta (postproc->filter, &minfo,
+            &linfo))
+      goto fail_configure_hdr_tone_map;
+
+    postproc->flags |= GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP;
+  } else {
+    postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP);
+  }
+
+  return TRUE;
+
+fail_configure_hdr_tone_map:
+  {
+    postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP);
+    return FALSE;
+  }
+}
+
+static gboolean
+check_filter_update (GstVaapiPostproc * postproc)
+{
+  guint filter_flag = postproc->flags;
+  guint op_flag;
+  gint i;
+
+  if (!postproc->has_vpp)
+    return FALSE;
+
+  for (i = GST_VAAPI_FILTER_OP_DENOISE;
+      i <= GST_VAAPI_FILTER_OP_SKINTONE_LEVEL; i++) {
+    op_flag = (filter_flag >> i) & 1;
+    if (op_flag)
+      return TRUE;
+  }
+
+  return FALSE;
+}
+
+static gboolean
+update_filter (GstVaapiPostproc * postproc)
+{
+  /* Validate filters */
+  if ((postproc->flags & GST_VAAPI_POSTPROC_FLAG_FORMAT) &&
+      !gst_vaapi_filter_set_format (postproc->filter, postproc->format))
+    return FALSE;
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DENOISE) {
+    if (!gst_vaapi_filter_set_denoising_level (postproc->filter,
+            postproc->denoise_level))
+      return FALSE;
+
+    if (gst_vaapi_filter_get_denoising_level_default (postproc->filter) ==
+        postproc->denoise_level)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_DENOISE);
+  }
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SHARPEN) {
+    if (!gst_vaapi_filter_set_sharpening_level (postproc->filter,
+            postproc->sharpen_level))
+      return FALSE;
+
+    if (gst_vaapi_filter_get_sharpening_level_default (postproc->filter) ==
+        postproc->sharpen_level)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SHARPEN);
+  }
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_HUE) {
+    if (!gst_vaapi_filter_set_hue (postproc->filter, postproc->hue))
+      return FALSE;
+
+    if (gst_vaapi_filter_get_hue_default (postproc->filter) == postproc->hue)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_HUE);
+  }
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SATURATION) {
+    if (!gst_vaapi_filter_set_saturation (postproc->filter,
+            postproc->saturation))
+      return FALSE;
+
+    if (gst_vaapi_filter_get_saturation_default (postproc->filter) ==
+        postproc->saturation)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SATURATION);
+  }
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS) {
+    if (!gst_vaapi_filter_set_brightness (postproc->filter,
+            postproc->brightness))
+      return FALSE;
+
+    if (gst_vaapi_filter_get_brightness_default (postproc->filter) ==
+        postproc->brightness)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS);
+  }
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_CONTRAST) {
+    if (!gst_vaapi_filter_set_contrast (postproc->filter, postproc->contrast))
+      return FALSE;
+
+    if (gst_vaapi_filter_get_contrast_default (postproc->filter) ==
+        postproc->contrast)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_CONTRAST);
+  }
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SCALE) {
+    if (!gst_vaapi_filter_set_scaling (postproc->filter,
+            postproc->scale_method))
+      return FALSE;
+
+    if (gst_vaapi_filter_get_scaling_default (postproc->filter) ==
+        postproc->scale_method)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SCALE);
+  }
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION) {
+    GstVideoOrientationMethod method = postproc->video_direction;
+    if (method == GST_VIDEO_ORIENTATION_AUTO)
+      method = postproc->tag_video_direction;
+
+    if (!gst_vaapi_filter_set_video_direction (postproc->filter, method)) {
+      GST_ELEMENT_WARNING (postproc, LIBRARY, SETTINGS,
+          ("Unsupported video direction '%s' by driver.",
+              gst_vaapi_enum_type_get_nick
+              (GST_TYPE_VIDEO_ORIENTATION_METHOD, method)),
+          ("video direction transformation ignored"));
+
+      /* Don't return FALSE because other filters might be set */
+    }
+
+    if (gst_vaapi_filter_get_video_direction_default (postproc->filter) ==
+        method)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION);
+  }
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_CROP)
+    if ((postproc->crop_left | postproc->crop_right | postproc->crop_top
+            | postproc->crop_bottom) == 0)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_CROP);
+
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL) {
+    if (!gst_vaapi_filter_set_skintone_level (postproc->filter,
+            postproc->skintone_value))
+      return FALSE;
+
+    if (gst_vaapi_filter_get_skintone_level_default (postproc->filter) ==
+        postproc->skintone_value)
+      postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL);
+
+#ifndef GST_REMOVE_DEPRECATED
+    /*
+     * When use skin tone level property, disable old skin tone property always
+     */
+    postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SKINTONE);
+#endif
+  } else {
+#ifndef GST_REMOVE_DEPRECATED
+    if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_SKINTONE) {
+      if (!gst_vaapi_filter_set_skintone (postproc->filter,
+              postproc->skintone_enhance))
+        return FALSE;
+
+      if (gst_vaapi_filter_get_skintone_default (postproc->filter) ==
+          postproc->skintone_enhance)
+        postproc->flags &= ~(GST_VAAPI_POSTPROC_FLAG_SKINTONE);
+    }
+#endif
+  }
+
+  return TRUE;
+}
+
+static void
+gst_vaapipostproc_set_passthrough (GstBaseTransform * trans)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  gboolean filter_updated = FALSE;
+
+  if (check_filter_update (postproc) && update_filter (postproc)) {
+    /* check again if changed value is default */
+    filter_updated = check_filter_update (postproc);
+  }
+
+  gst_base_transform_set_passthrough (trans, postproc->same_caps
+      && !filter_updated);
+}
+
+static gboolean
+replace_to_dumb_buffer_if_required (GstVaapiPostproc * postproc,
+    GstBuffer ** fieldbuf)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (postproc);
+  GstBuffer *newbuf;
+
+  if (!GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (postproc))
+    return TRUE;
+
+  newbuf = create_output_dump_buffer (postproc);
+  if (!newbuf)
+    return FALSE;
+
+  if (!gst_vaapi_plugin_copy_va_buffer (plugin, *fieldbuf, newbuf)) {
+    gst_buffer_unref (newbuf);
+    return FALSE;
+  }
+
+  gst_buffer_replace (fieldbuf, newbuf);
+  gst_buffer_unref (newbuf);
+
+  return TRUE;
+}
+
+static gboolean
+use_vpp_crop (GstVaapiPostproc * postproc)
+{
+  return !(postproc->forward_crop
+      && !(postproc->flags & GST_VAAPI_POSTPROC_FLAG_CROP));
+}
+
+static void
+rotate_crop_meta (GstVaapiPostproc * const postproc, const GstVideoMeta * vmeta,
+    GstVideoCropMeta * crop)
+{
+  guint tmp;
+
+  g_return_if_fail (postproc->has_vpp);
+
+  /* The video meta is required since the caps width/height are smaller,
+   * which would not result in a usable GstVideoInfo for mapping the
+   * buffer. */
+  if (!vmeta || !crop)
+    return;
+
+  switch (gst_vaapi_filter_get_video_direction (postproc->filter)) {
+    case GST_VIDEO_ORIENTATION_HORIZ:
+      crop->x = vmeta->width - crop->width - crop->x;
+      break;
+    case GST_VIDEO_ORIENTATION_VERT:
+      crop->y = vmeta->height - crop->height - crop->y;
+      break;
+    case GST_VIDEO_ORIENTATION_90R:
+      tmp = crop->x;
+      crop->x = vmeta->height - crop->height - crop->y;
+      crop->y = tmp;
+      G_PRIMITIVE_SWAP (guint, crop->width, crop->height);
+      break;
+    case GST_VIDEO_ORIENTATION_180:
+      crop->x = vmeta->width - crop->width - crop->x;
+      crop->y = vmeta->height - crop->height - crop->y;
+      break;
+    case GST_VIDEO_ORIENTATION_90L:
+      tmp = crop->x;
+      crop->x = crop->y;
+      crop->y = vmeta->width - crop->width - tmp;
+      G_PRIMITIVE_SWAP (guint, crop->width, crop->height);
+      break;
+    case GST_VIDEO_ORIENTATION_UR_LL:
+      tmp = crop->x;
+      crop->x = vmeta->height - crop->height - crop->y;
+      crop->y = vmeta->width - crop->width - tmp;
+      G_PRIMITIVE_SWAP (guint, crop->width, crop->height);
+      break;
+    case GST_VIDEO_ORIENTATION_UL_LR:
+      G_PRIMITIVE_SWAP (guint, crop->x, crop->y);
+      G_PRIMITIVE_SWAP (guint, crop->width, crop->height);
+      break;
+    default:
+      break;
+  }
+}
+
+static GstFlowReturn
+gst_vaapipostproc_process_vpp (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer * outbuf)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  GstVaapiDeinterlaceState *const ds = &postproc->deinterlace_state;
+  GstVaapiVideoMeta *inbuf_meta, *outbuf_meta;
+  GstVaapiSurface *inbuf_surface, *outbuf_surface;
+  GstVaapiSurfaceProxy *proxy;
+  GstVaapiFilterStatus status;
+  GstClockTime timestamp;
+  GstFlowReturn ret;
+  GstBuffer *fieldbuf;
+  GstVaapiDeinterlaceMethod deint_method;
+  guint flags, deint_flags;
+  gboolean tff, deint, deint_refs, deint_changed, discont;
+  const GstVideoCropMeta *crop_meta;
+  GstVaapiRectangle *crop_rect = NULL;
+  GstVaapiRectangle tmp_rect;
+
+  inbuf_meta = gst_buffer_get_vaapi_video_meta (inbuf);
+  if (!inbuf_meta)
+    goto error_invalid_buffer;
+  inbuf_surface = gst_vaapi_video_meta_get_surface (inbuf_meta);
+
+  if (use_vpp_crop (postproc)) {
+    crop_rect = &tmp_rect;
+    crop_rect->x = postproc->crop_left;
+    crop_rect->y = postproc->crop_top;
+    crop_rect->width = GST_VIDEO_INFO_WIDTH (&postproc->sinkpad_info)
+        - (postproc->crop_left + postproc->crop_right);
+    crop_rect->height = GST_VIDEO_INFO_HEIGHT (&postproc->sinkpad_info)
+        - (postproc->crop_top + postproc->crop_bottom);
+
+    crop_meta = gst_buffer_get_video_crop_meta (inbuf);
+    if (crop_meta) {
+      crop_rect->x += crop_meta->x;
+      crop_rect->y += crop_meta->y;
+    }
+  }
+
+  if (!crop_rect)
+    crop_rect = (GstVaapiRectangle *)
+        gst_vaapi_video_meta_get_render_rect (inbuf_meta);
+
+  timestamp = GST_BUFFER_TIMESTAMP (inbuf);
+  tff = GST_BUFFER_FLAG_IS_SET (inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+  discont = GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_DISCONT);
+  deint = should_deinterlace_buffer (postproc, inbuf);
+
+  /* Drop references if deinterlacing conditions changed */
+  deint_changed = deint != ds->deint;
+  if (deint_changed || (ds->num_surfaces > 0 && tff != ds->tff))
+    ds_reset (ds);
+
+  deint_method = postproc->deinterlace_method;
+  deint_refs = deint_method_is_advanced (deint_method);
+  if (deint_refs && 0) {
+    GstBuffer *const prev_buf = ds_get_buffer (ds, 0);
+    GstClockTime prev_pts, pts = GST_BUFFER_TIMESTAMP (inbuf);
+    /* Reset deinterlacing state when there is a discontinuity */
+    if (prev_buf && (prev_pts = GST_BUFFER_TIMESTAMP (prev_buf)) != pts) {
+      const GstClockTimeDiff pts_diff = GST_CLOCK_DIFF (prev_pts, pts);
+      if (pts_diff < 0 || (postproc->field_duration > 0 &&
+              pts_diff >= postproc->field_duration * 3 - 1))
+        ds_reset (ds);
+    }
+  }
+
+  ds->deint = deint;
+  ds->tff = tff;
+
+  flags = gst_vaapi_video_meta_get_render_flags (inbuf_meta) &
+      ~GST_VAAPI_PICTURE_STRUCTURE_MASK;
+
+  /* First field */
+  if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
+    fieldbuf = create_output_buffer (postproc);
+    if (!fieldbuf)
+      goto error_create_buffer;
+
+    outbuf_meta = gst_buffer_get_vaapi_video_meta (fieldbuf);
+    if (!outbuf_meta)
+      goto error_create_meta;
+
+    if (!gst_vaapi_video_meta_get_surface_proxy (outbuf_meta)) {
+      proxy =
+          gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
+          (postproc->filter_pool));
+      if (!proxy)
+        goto error_create_proxy;
+      gst_vaapi_video_meta_set_surface_proxy (outbuf_meta, proxy);
+      gst_vaapi_surface_proxy_unref (proxy);
+    }
+
+    if (deint) {
+      deint_flags = (tff ? GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD : 0);
+      if (tff)
+        deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
+      if (!set_best_deint_method (postproc, deint_flags, &deint_method))
+        goto error_op_deinterlace;
+
+      if (deint_method != postproc->deinterlace_method) {
+        GST_DEBUG ("unsupported deinterlace-method %u. Using %u instead",
+            postproc->deinterlace_method, deint_method);
+        postproc->deinterlace_method = deint_method;
+        deint_refs = deint_method_is_advanced (deint_method);
+      }
+
+      if (deint_refs) {
+        ds_set_surfaces (ds);
+        if (!gst_vaapi_filter_set_deinterlacing_references (postproc->filter,
+                ds->surfaces, ds->num_surfaces, NULL, 0))
+          goto error_op_deinterlace;
+      }
+    } else if (deint_changed) {
+      // Reset internal filter to non-deinterlacing mode
+      deint_method = GST_VAAPI_DEINTERLACE_METHOD_NONE;
+      if (!gst_vaapi_filter_set_deinterlacing (postproc->filter,
+              deint_method, 0))
+        goto error_op_deinterlace;
+    }
+
+    outbuf_surface = gst_vaapi_video_meta_get_surface (outbuf_meta);
+    gst_vaapi_filter_set_cropping_rectangle (postproc->filter, crop_rect);
+    status = gst_vaapi_filter_process (postproc->filter, inbuf_surface,
+        outbuf_surface, flags);
+    if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
+      goto error_process_vpp;
+
+    copy_metadata (postproc, fieldbuf, inbuf);
+    GST_BUFFER_TIMESTAMP (fieldbuf) = timestamp;
+    GST_BUFFER_DURATION (fieldbuf) = postproc->field_duration;
+    if (discont) {
+      GST_BUFFER_FLAG_SET (fieldbuf, GST_BUFFER_FLAG_DISCONT);
+      discont = FALSE;
+    }
+
+    if (!replace_to_dumb_buffer_if_required (postproc, &fieldbuf))
+      goto error_copy_buffer;
+
+    ret = gst_pad_push (trans->srcpad, fieldbuf);
+    if (ret != GST_FLOW_OK)
+      goto error_push_buffer;
+  }
+  fieldbuf = NULL;
+
+  /* Second field */
+  outbuf_meta = gst_buffer_get_vaapi_video_meta (outbuf);
+  if (!outbuf_meta)
+    goto error_create_meta;
+
+  if (!gst_vaapi_video_meta_get_surface_proxy (outbuf_meta)) {
+    proxy =
+        gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
+        (postproc->filter_pool));
+    if (!proxy)
+      goto error_create_proxy;
+    gst_vaapi_video_meta_set_surface_proxy (outbuf_meta, proxy);
+    gst_vaapi_surface_proxy_unref (proxy);
+  }
+
+  if (deint) {
+    deint_flags = (tff ? 0 : GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD);
+    if (tff)
+      deint_flags |= GST_VAAPI_DEINTERLACE_FLAG_TFF;
+    if (!gst_vaapi_filter_set_deinterlacing (postproc->filter,
+            deint_method, deint_flags))
+      goto error_op_deinterlace;
+
+    if (deint_refs
+        && !gst_vaapi_filter_set_deinterlacing_references (postproc->filter,
+            ds->surfaces, ds->num_surfaces, NULL, 0))
+      goto error_op_deinterlace;
+  } else if (deint_changed
+      && !gst_vaapi_filter_set_deinterlacing (postproc->filter, deint_method,
+          0))
+    goto error_op_deinterlace;
+
+  outbuf_surface = gst_vaapi_video_meta_get_surface (outbuf_meta);
+  gst_vaapi_filter_set_cropping_rectangle (postproc->filter, crop_rect);
+  status = gst_vaapi_filter_process (postproc->filter, inbuf_surface,
+      outbuf_surface, flags);
+  if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
+    goto error_process_vpp;
+
+  if (!(postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE))
+    gst_buffer_copy_into (outbuf, inbuf, GST_BUFFER_COPY_TIMESTAMPS, 0, -1);
+  else {
+    GST_BUFFER_TIMESTAMP (outbuf) = timestamp + postproc->field_duration;
+    GST_BUFFER_DURATION (outbuf) = postproc->field_duration;
+    if (discont) {
+      GST_BUFFER_FLAG_SET (fieldbuf, GST_BUFFER_FLAG_DISCONT);
+      discont = FALSE;
+    }
+  }
+
+  copy_metadata (postproc, outbuf, inbuf);
+
+  rotate_crop_meta (postproc, gst_buffer_get_video_meta (inbuf),
+      gst_buffer_get_video_crop_meta (outbuf));
+
+  if (deint && deint_refs)
+    ds_add_buffer (ds, inbuf);
+  postproc->use_vpp = TRUE;
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_invalid_buffer:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to validate source buffer");
+    return GST_FLOW_ERROR;
+  }
+error_create_buffer:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to create output buffer");
+    return GST_FLOW_ERROR;
+  }
+error_create_meta:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to create new output buffer meta");
+    gst_buffer_replace (&fieldbuf, NULL);
+    return GST_FLOW_ERROR;
+  }
+error_create_proxy:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to create surface proxy from pool");
+    gst_buffer_replace (&fieldbuf, NULL);
+    return GST_FLOW_ERROR;
+  }
+error_op_deinterlace:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to apply deinterlacing filter");
+    gst_buffer_replace (&fieldbuf, NULL);
+    return GST_FLOW_NOT_SUPPORTED;
+  }
+error_process_vpp:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to apply VPP filters (error %d)",
+        status);
+    gst_buffer_replace (&fieldbuf, NULL);
+    return GST_FLOW_ERROR;
+  }
+error_copy_buffer:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to copy field buffer to dumb buffer");
+    gst_buffer_replace (&fieldbuf, NULL);
+    return GST_FLOW_ERROR;
+  }
+error_push_buffer:
+  {
+    GST_DEBUG_OBJECT (postproc, "failed to push output buffer: %s",
+        gst_flow_get_name (ret));
+    return ret;
+  }
+}
+
+static GstFlowReturn
+gst_vaapipostproc_process (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer * outbuf)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  GstVaapiVideoMeta *meta;
+  GstClockTime timestamp;
+  GstFlowReturn ret;
+  GstBuffer *fieldbuf;
+  guint fieldbuf_flags, outbuf_flags, flags;
+  gboolean tff, deint;
+
+  meta = gst_buffer_get_vaapi_video_meta (inbuf);
+  if (!meta)
+    goto error_invalid_buffer;
+
+  timestamp = GST_BUFFER_TIMESTAMP (inbuf);
+  tff = GST_BUFFER_FLAG_IS_SET (inbuf, GST_VIDEO_BUFFER_FLAG_TFF);
+  deint = should_deinterlace_buffer (postproc, inbuf);
+
+  flags = gst_vaapi_video_meta_get_render_flags (meta) &
+      ~GST_VAAPI_PICTURE_STRUCTURE_MASK;
+
+  /* First field */
+  fieldbuf = create_output_buffer (postproc);
+  if (!fieldbuf)
+    goto error_create_buffer;
+  append_output_buffer_metadata (postproc, fieldbuf, inbuf, 0);
+
+  meta = gst_buffer_get_vaapi_video_meta (fieldbuf);
+  fieldbuf_flags = flags;
+  fieldbuf_flags |= deint ? (tff ?
+      GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD :
+      GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) :
+      GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+  gst_vaapi_video_meta_set_render_flags (meta, fieldbuf_flags);
+
+  GST_BUFFER_TIMESTAMP (fieldbuf) = timestamp;
+  GST_BUFFER_DURATION (fieldbuf) = postproc->field_duration;
+
+  if (!replace_to_dumb_buffer_if_required (postproc, &fieldbuf))
+    goto error_copy_buffer;
+
+  ret = gst_pad_push (trans->srcpad, fieldbuf);
+  if (ret != GST_FLOW_OK)
+    goto error_push_buffer;
+
+  /* Second field */
+  append_output_buffer_metadata (postproc, outbuf, inbuf, 0);
+
+  meta = gst_buffer_get_vaapi_video_meta (outbuf);
+  outbuf_flags = flags;
+  outbuf_flags |= deint ? (tff ?
+      GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD :
+      GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) :
+      GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+  gst_vaapi_video_meta_set_render_flags (meta, outbuf_flags);
+
+  GST_BUFFER_TIMESTAMP (outbuf) = timestamp + postproc->field_duration;
+  GST_BUFFER_DURATION (outbuf) = postproc->field_duration;
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_invalid_buffer:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to validate source buffer");
+    return GST_FLOW_ERROR;
+  }
+error_create_buffer:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to create output buffer");
+    return GST_FLOW_EOS;
+  }
+error_copy_buffer:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to copy field buffer to dumb buffer");
+    gst_buffer_replace (&fieldbuf, NULL);
+    return GST_FLOW_ERROR;
+  }
+error_push_buffer:
+  {
+    GST_DEBUG_OBJECT (postproc, "failed to push output buffer: %s",
+        gst_flow_get_name (ret));
+    return ret;
+  }
+}
+
+static GstFlowReturn
+gst_vaapipostproc_passthrough (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer * outbuf)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  GstVaapiVideoMeta *meta;
+
+  /* No video processing needed, simply copy buffer metadata */
+  meta = gst_buffer_get_vaapi_video_meta (inbuf);
+  if (!meta)
+    goto error_invalid_buffer;
+
+  append_output_buffer_metadata (postproc, outbuf, inbuf,
+      GST_BUFFER_COPY_TIMESTAMPS);
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_invalid_buffer:
+  {
+    GST_ERROR_OBJECT (postproc, "failed to validate source buffer");
+    return GST_FLOW_ERROR;
+  }
+}
+
+static gboolean
+video_info_changed (GstVideoInfo * old_vip, GstVideoInfo * new_vip)
+{
+  if (gst_video_info_changed (old_vip, new_vip))
+    return TRUE;
+  if (GST_VIDEO_INFO_INTERLACE_MODE (old_vip) !=
+      GST_VIDEO_INFO_INTERLACE_MODE (new_vip))
+    return TRUE;
+  return FALSE;
+}
+
+static gboolean
+video_info_update (GstCaps * caps, GstVideoInfo * info,
+    gboolean * caps_changed_ptr)
+{
+  GstVideoInfo vi;
+
+  if (!gst_video_info_from_caps (&vi, caps))
+    return FALSE;
+
+  *caps_changed_ptr = FALSE;
+  if (video_info_changed (info, &vi)) {
+    *caps_changed_ptr = TRUE;
+    *info = vi;
+  }
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapipostproc_update_sink_caps (GstVaapiPostproc * postproc, GstCaps * caps,
+    gboolean * caps_changed_ptr)
+{
+  GstVideoInfo vi;
+  gboolean deinterlace;
+
+  GST_INFO_OBJECT (postproc, "new sink caps = %" GST_PTR_FORMAT, caps);
+
+  if (!video_info_update (caps, &postproc->sinkpad_info, caps_changed_ptr))
+    return FALSE;
+
+  vi = postproc->sinkpad_info;
+  deinterlace = is_deinterlace_enabled (postproc, &vi);
+  if (deinterlace)
+    postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DEINTERLACE;
+  postproc->field_duration = GST_VIDEO_INFO_FPS_N (&vi) > 0 ?
+      gst_util_uint64_scale (GST_SECOND, GST_VIDEO_INFO_FPS_D (&vi),
+      (1 + deinterlace) * GST_VIDEO_INFO_FPS_N (&vi)) : 0;
+
+  postproc->get_va_surfaces = gst_caps_has_vaapi_surface (caps);
+  return TRUE;
+}
+
+static gboolean
+gst_vaapipostproc_update_src_caps (GstVaapiPostproc * postproc, GstCaps * caps,
+    gboolean * caps_changed_ptr)
+{
+  GST_INFO_OBJECT (postproc, "new src caps = %" GST_PTR_FORMAT, caps);
+
+  if (!video_info_update (caps, &postproc->srcpad_info, caps_changed_ptr))
+    return FALSE;
+
+  if (postproc->format != GST_VIDEO_INFO_FORMAT (&postproc->sinkpad_info) &&
+      postproc->format != DEFAULT_FORMAT)
+    postproc->flags |= GST_VAAPI_POSTPROC_FLAG_FORMAT;
+
+  if (GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) !=
+      GST_VIDEO_INFO_WIDTH (&postproc->sinkpad_info)
+      || GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) !=
+      GST_VIDEO_INFO_HEIGHT (&postproc->sinkpad_info))
+    postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SIZE;
+
+  return TRUE;
+}
+
+static gboolean
+ensure_allowed_sinkpad_caps (GstVaapiPostproc * postproc)
+{
+  GstCaps *out_caps = NULL;
+  guint mem_types;
+  gint min_width, min_height, max_width, max_height;
+  GArray *mem_formats = NULL;
+  gboolean ret = TRUE;
+  guint i, num_structure;
+
+  if (postproc->allowed_sinkpad_caps) {
+    ret = TRUE;
+    goto out;
+  }
+
+  if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (postproc) ||
+      !gst_vaapipostproc_ensure_filter_caps (postproc)) {
+    ret = FALSE;
+    goto out;
+  }
+
+  mem_types = gst_vaapi_filter_get_memory_types (postproc->filter);
+  mem_formats = gst_vaapi_filter_get_formats (postproc->filter, &min_width,
+      &min_height, &max_width, &max_height);
+
+  out_caps = gst_vaapi_build_caps_from_formats (mem_formats, min_width,
+      min_height, max_width, max_height, mem_types);
+  if (!out_caps) {
+    GST_WARNING_OBJECT (postproc, "failed to create VA sink caps");
+    ret = FALSE;
+    goto out;
+  }
+
+  /* For raw yuv caps, we need to replace va attrib formats with all image formats */
+  num_structure = gst_caps_get_size (out_caps);
+  for (i = 0; i < num_structure; i++) {
+    GstStructure *structure;
+    GstCapsFeatures *features = gst_caps_get_features (out_caps, i);
+    GValue v_formats = G_VALUE_INIT;
+
+    structure = gst_caps_get_structure (out_caps, i);
+    if (!structure)
+      continue;
+
+    if (gst_caps_features_contains (features,
+            GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY)) {
+      mem_formats = gst_vaapi_display_get_image_formats
+          (GST_VAAPI_PLUGIN_BASE_DISPLAY (postproc));
+      if (!gst_vaapi_value_set_format_list (&v_formats, mem_formats)) {
+        ret = FALSE;
+        goto out;
+      }
+      gst_structure_set_value (structure, "format", &v_formats);
+      g_value_unset (&v_formats);
+    }
+  }
+
+  postproc->allowed_sinkpad_caps = out_caps;
+  out_caps = NULL;
+  GST_INFO_OBJECT (postproc, "postproc sink allowed caps is %" GST_PTR_FORMAT,
+      postproc->allowed_sinkpad_caps);
+out:
+  if (out_caps)
+    gst_caps_unref (out_caps);
+  if (mem_formats)
+    g_array_unref (mem_formats);
+
+  return ret;
+}
+
+/* Fixup output caps so that to reflect the supported set of pixel formats */
+static GstCaps *
+expand_allowed_srcpad_caps (GstVaapiPostproc * postproc, GstCaps * caps)
+{
+  GValue value = G_VALUE_INIT, v_format = G_VALUE_INIT;
+  guint i, num_structures;
+  gint gl_upload_meta_idx = -1;
+
+  if (postproc->filter == NULL)
+    goto cleanup;
+  if (!gst_vaapipostproc_ensure_filter_caps (postproc))
+    goto cleanup;
+
+  /* Reset "format" field for each structure */
+  if (!gst_vaapi_value_set_format_list (&value, postproc->filter_formats))
+    goto cleanup;
+  if (gst_vaapi_value_set_format (&v_format, GST_VIDEO_FORMAT_ENCODED)) {
+    gst_value_list_prepend_value (&value, &v_format);
+    g_value_unset (&v_format);
+  }
+
+  num_structures = gst_caps_get_size (caps);
+  for (i = 0; i < num_structures; i++) {
+    GstCapsFeatures *const features = gst_caps_get_features (caps, i);
+    GstStructure *structure;
+
+    structure = gst_caps_get_structure (caps, i);
+    if (!structure)
+      continue;
+
+    gst_vaapi_filter_append_caps (postproc->filter, structure);
+
+    if (gst_caps_features_contains (features,
+            GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META)) {
+      gl_upload_meta_idx = i;
+      continue;
+    }
+
+    gst_structure_set_value (structure, "format", &value);
+  }
+  g_value_unset (&value);
+
+  if ((GST_VAAPI_PLUGIN_BASE_SRC_PAD_CAN_DMABUF (postproc)
+          || !gst_vaapi_display_has_opengl (GST_VAAPI_PLUGIN_BASE_DISPLAY
+              (postproc)))
+      && gl_upload_meta_idx > -1) {
+    gst_caps_remove_structure (caps, gl_upload_meta_idx);
+  }
+
+cleanup:
+  return caps;
+}
+
+static gboolean
+ensure_allowed_srcpad_caps (GstVaapiPostproc * postproc)
+{
+  GstCaps *out_caps;
+
+  if (postproc->allowed_srcpad_caps)
+    return TRUE;
+
+  /* Create initial caps from pad template */
+  out_caps = gst_caps_from_string (gst_vaapipostproc_src_caps_str);
+  if (!out_caps) {
+    GST_ERROR_OBJECT (postproc, "failed to create VA src caps");
+    return FALSE;
+  }
+
+  postproc->allowed_srcpad_caps =
+      expand_allowed_srcpad_caps (postproc, out_caps);
+  return postproc->allowed_srcpad_caps != NULL;
+}
+
+static GstCaps *
+gst_vaapipostproc_transform_caps_impl (GstBaseTransform * trans,
+    GstPadDirection direction)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+
+  /* Generate the sink pad caps, that could be fixated afterwards */
+  if (direction == GST_PAD_SRC) {
+    if (!ensure_allowed_sinkpad_caps (postproc))
+      return gst_caps_from_string (gst_vaapipostproc_sink_caps_str);
+    return gst_caps_ref (postproc->allowed_sinkpad_caps);
+  }
+
+  /* Generate complete set of src pad caps */
+  if (!ensure_allowed_srcpad_caps (postproc))
+    return NULL;
+  return gst_vaapipostproc_transform_srccaps (postproc);
+}
+
+static GstCaps *
+gst_vaapipostproc_transform_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * filter)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  GstCaps *out_caps;
+
+  GST_DEBUG_OBJECT (trans,
+      "Transforming caps %" GST_PTR_FORMAT " in direction %s", caps,
+      (direction == GST_PAD_SINK) ? "sink" : "src");
+
+  g_mutex_lock (&postproc->postproc_lock);
+  out_caps = gst_vaapipostproc_transform_caps_impl (trans, direction);
+  g_mutex_unlock (&postproc->postproc_lock);
+
+  if (out_caps && filter) {
+    GstCaps *intersection;
+
+    intersection = gst_caps_intersect_full (out_caps, filter,
+        GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (out_caps);
+    out_caps = intersection;
+  }
+
+  GST_DEBUG_OBJECT (trans, "returning caps: %" GST_PTR_FORMAT, out_caps);
+
+  return out_caps;
+}
+
+static GstCaps *
+gst_vaapipostproc_fixate_caps (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, GstCaps * othercaps)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  GstCaps *outcaps = NULL;
+  gboolean same_caps, filter_updated = FALSE;
+
+  GST_DEBUG_OBJECT (trans, "trying to fixate othercaps %" GST_PTR_FORMAT
+      " based on caps %" GST_PTR_FORMAT " in direction %s", othercaps, caps,
+      (direction == GST_PAD_SINK) ? "sink" : "src");
+
+  if (direction == GST_PAD_SRC) {
+    /* @TODO: we can do better */
+    outcaps = gst_caps_fixate (othercaps);
+    goto done;
+  }
+
+  g_mutex_lock (&postproc->postproc_lock);
+  postproc->has_vpp = gst_vaapipostproc_ensure_filter_caps (postproc);
+  if (check_filter_update (postproc) && update_filter (postproc)) {
+    /* check again if changed value is default */
+    filter_updated = check_filter_update (postproc);
+  }
+
+  outcaps = gst_vaapipostproc_fixate_srccaps (postproc, caps, othercaps);
+  g_mutex_unlock (&postproc->postproc_lock);
+  if (!outcaps)
+    goto done;
+
+  /* set passthrough according to caps changes or filter changes */
+  same_caps = gst_caps_is_equal (caps, outcaps);
+  gst_base_transform_set_passthrough (trans, same_caps && !filter_updated);
+
+done:
+  if (outcaps)
+    GST_DEBUG_OBJECT (trans, "fixated othercaps to %" GST_PTR_FORMAT, outcaps);
+  gst_caps_unref (othercaps);
+
+  return outcaps;
+}
+
+static gboolean
+gst_vaapipostproc_transform_size (GstBaseTransform * trans,
+    GstPadDirection direction, GstCaps * caps, gsize size,
+    GstCaps * othercaps, gsize * othersize)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+
+  if (direction == GST_PAD_SINK || postproc->get_va_surfaces)
+    *othersize = 0;
+  else
+    *othersize = size;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapipostproc_transform_meta (GstBaseTransform * trans, GstBuffer * outbuf,
+    GstMeta * meta, GstBuffer * inbuf)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+
+  /* don't copy GstVideoCropMeta if we are using vpp crop */
+  if (meta->info->api == GST_VIDEO_CROP_META_API_TYPE
+      && use_vpp_crop (postproc))
+    return FALSE;
+
+  /* don't copy GstParentBufferMeta if use_vpp */
+  if (meta->info->api == GST_PARENT_BUFFER_META_API_TYPE && postproc->use_vpp)
+    return FALSE;
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_vaapipostproc_transform (GstBaseTransform * trans, GstBuffer * inbuf,
+    GstBuffer * outbuf)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (postproc);
+  GstBuffer *buf, *sys_buf = NULL;
+  GstFlowReturn ret;
+
+  ret = gst_vaapi_plugin_base_get_input_buffer (plugin, inbuf, &buf);
+  if (ret != GST_FLOW_OK)
+    return GST_FLOW_ERROR;
+
+  if (GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (trans)) {
+    GstBuffer *va_buf = create_output_buffer (postproc);
+    if (!va_buf) {
+      ret = GST_FLOW_ERROR;
+      goto done;
+    }
+    sys_buf = outbuf;
+    outbuf = va_buf;
+  }
+
+  ret = GST_FLOW_NOT_SUPPORTED;
+  if (postproc->flags) {
+    /* Use VA/VPP extensions to process this frame */
+    if (postproc->has_vpp) {
+      ret = gst_vaapipostproc_process_vpp (trans, buf, outbuf);
+      if (ret != GST_FLOW_NOT_SUPPORTED)
+        goto done;
+      GST_WARNING_OBJECT (postproc, "unsupported VPP filters. Disabling");
+    }
+
+    /* Only append picture structure meta data (top/bottom field) */
+    if (postproc->flags & GST_VAAPI_POSTPROC_FLAG_DEINTERLACE) {
+      ret = gst_vaapipostproc_process (trans, buf, outbuf);
+      if (ret != GST_FLOW_NOT_SUPPORTED)
+        goto done;
+    }
+  }
+
+  /* Fallback: passthrough to the downstream element as is */
+  ret = gst_vaapipostproc_passthrough (trans, buf, outbuf);
+
+done:
+  if (sys_buf)
+    copy_metadata (postproc, sys_buf, buf);
+
+  gst_buffer_unref (buf);
+
+  if (sys_buf) {
+    if (!gst_vaapi_plugin_copy_va_buffer (plugin, outbuf, sys_buf))
+      return GST_FLOW_ERROR;
+
+    gst_buffer_unref (outbuf);
+    outbuf = sys_buf;
+  }
+
+  return ret;
+}
+
+static gboolean
+ensure_buffer_pool (GstVaapiPostproc * postproc, GstVideoInfo * vi)
+{
+  GstVaapiVideoPool *pool;
+
+  if (!vi)
+    return FALSE;
+
+  gst_video_info_change_format (vi, postproc->format,
+      GST_VIDEO_INFO_WIDTH (vi), GST_VIDEO_INFO_HEIGHT (vi));
+
+  if (postproc->filter_pool
+      && !video_info_changed (&postproc->filter_pool_info, vi))
+    return TRUE;
+  postproc->filter_pool_info = *vi;
+
+  pool =
+      gst_vaapi_surface_pool_new_full (GST_VAAPI_PLUGIN_BASE_DISPLAY (postproc),
+      &postproc->filter_pool_info, 0);
+  if (!pool)
+    return FALSE;
+
+  gst_vaapi_video_pool_replace (&postproc->filter_pool, pool);
+  gst_vaapi_video_pool_unref (pool);
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_vaapipostproc_prepare_output_buffer (GstBaseTransform * trans,
+    GstBuffer * inbuf, GstBuffer ** outbuf_ptr)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  const GstVideoMeta *video_meta;
+  GstVideoInfo info;
+
+  if (gst_base_transform_is_passthrough (trans)) {
+    *outbuf_ptr = inbuf;
+    return GST_FLOW_OK;
+  }
+
+  /* If we are not using vpp crop (i.e. forwarding crop meta to downstream)
+   * then, ensure our output buffer pool is sized and rotated for uncropped
+   * output */
+  if (gst_buffer_get_video_crop_meta (inbuf) && !use_vpp_crop (postproc)) {
+    /* The video meta is required since the caps width/height are smaller,
+     * which would not result in a usable GstVideoInfo for mapping the
+     * buffer. */
+    video_meta = gst_buffer_get_video_meta (inbuf);
+    if (!video_meta)
+      return GST_FLOW_ERROR;
+
+    info = postproc->srcpad_info;
+    info.width = video_meta->width;
+    info.height = video_meta->height;
+
+    if (postproc->has_vpp) {
+      /* compensate for rotation if needed */
+      switch (gst_vaapi_filter_get_video_direction (postproc->filter)) {
+        case GST_VIDEO_ORIENTATION_90R:
+        case GST_VIDEO_ORIENTATION_UL_LR:
+        case GST_VIDEO_ORIENTATION_90L:
+        case GST_VIDEO_ORIENTATION_UR_LL:
+          G_PRIMITIVE_SWAP (guint, info.width, info.height);
+        default:
+          break;
+      }
+    }
+
+    ensure_buffer_pool (postproc, &info);
+  }
+
+  if (GST_VAAPI_PLUGIN_BASE_COPY_OUTPUT_FRAME (trans)) {
+    *outbuf_ptr = create_output_dump_buffer (postproc);
+  } else {
+    *outbuf_ptr = create_output_buffer (postproc);
+  }
+
+  if (!*outbuf_ptr)
+    return GST_FLOW_ERROR;
+
+  return GST_FLOW_OK;
+}
+
+static gboolean
+ensure_srcpad_buffer_pool (GstVaapiPostproc * postproc, GstCaps * caps)
+{
+  GstVideoInfo vi;
+
+  if (!gst_video_info_from_caps (&vi, caps))
+    return FALSE;
+
+  return ensure_buffer_pool (postproc, &vi);
+}
+
+static gboolean
+is_native_video_format (GstVideoFormat format)
+{
+  guint i = 0;
+  for (i = 0; i < G_N_ELEMENTS (native_formats); i++)
+    if (native_formats[i] == format)
+      return TRUE;
+  return FALSE;
+}
+
+static gboolean
+gst_vaapipostproc_set_caps (GstBaseTransform * trans, GstCaps * caps,
+    GstCaps * out_caps)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  gboolean sink_caps_changed = FALSE;
+  gboolean src_caps_changed = FALSE;
+  GstVideoInfo vinfo;
+  gboolean ret = FALSE;
+
+  g_mutex_lock (&postproc->postproc_lock);
+  if (!gst_vaapipostproc_update_sink_caps (postproc, caps, &sink_caps_changed))
+    goto done;
+  /* HACK: This is a workaround to deal with the va-intel-driver for non-native
+   * formats while doing advanced deinterlacing. The format of reference surfaces must
+   * be same as the format used by the driver internally for motion adaptive
+   * deinterlacing and motion compensated deinterlacing */
+  if (!gst_video_info_from_caps (&vinfo, caps))
+    goto done;
+  if (deint_method_is_advanced (postproc->deinterlace_method)
+      && !is_native_video_format (GST_VIDEO_INFO_FORMAT (&vinfo))) {
+    GST_WARNING_OBJECT (postproc,
+        "Advanced deinterlacing requires the native video formats used by the driver internally");
+    goto done;
+  }
+  if (!gst_vaapipostproc_update_src_caps (postproc, out_caps,
+          &src_caps_changed))
+    goto done;
+
+  if (sink_caps_changed || src_caps_changed) {
+    gst_vaapipostproc_destroy (postproc);
+    if (!gst_vaapipostproc_create (postproc))
+      goto done;
+    if (!gst_vaapi_plugin_base_set_caps (GST_VAAPI_PLUGIN_BASE (trans),
+            caps, out_caps))
+      goto done;
+  }
+
+  if (postproc->has_vpp) {
+    if (!gst_vaapi_filter_set_colorimetry (postproc->filter,
+            &GST_VIDEO_INFO_COLORIMETRY (GST_VAAPI_PLUGIN_BASE_SINK_PAD_INFO
+                (postproc)),
+            &GST_VIDEO_INFO_COLORIMETRY (GST_VAAPI_PLUGIN_BASE_SRC_PAD_INFO
+                (postproc))))
+      goto done;
+
+    if (!configure_hdr_tone_map (postproc,
+            GST_VAAPI_PLUGIN_BASE_SINK_PAD_CAPS (postproc)))
+      GST_WARNING_OBJECT (postproc,
+          "Failed to configure HDR tone mapping."
+          "  The driver may not support it.");
+  }
+
+  if (!ensure_srcpad_buffer_pool (postproc, out_caps))
+    goto done;
+
+  postproc->same_caps = gst_caps_is_equal (caps, out_caps);
+
+  if (!src_caps_changed) {
+    /* set passthrough according to caps changes or filter changes */
+    gst_vaapipostproc_set_passthrough (trans);
+  }
+
+  ret = TRUE;
+
+done:
+  g_mutex_unlock (&postproc->postproc_lock);
+
+  /* Updates the srcpad caps and send the caps downstream */
+  if (ret && src_caps_changed)
+    gst_base_transform_update_src_caps (trans, out_caps);
+
+  return ret;
+}
+
+static gboolean
+gst_vaapipostproc_query (GstBaseTransform * trans,
+    GstPadDirection direction, GstQuery * query)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  GstElement *const element = GST_ELEMENT (trans);
+
+  if (GST_QUERY_TYPE (query) == GST_QUERY_CONTEXT) {
+    if (gst_vaapi_handle_context_query (element, query)) {
+      GST_DEBUG_OBJECT (postproc, "sharing display %" GST_PTR_FORMAT,
+          GST_VAAPI_PLUGIN_BASE_DISPLAY (postproc));
+      return TRUE;
+    }
+  }
+
+  return
+      GST_BASE_TRANSFORM_CLASS (gst_vaapipostproc_parent_class)->query (trans,
+      direction, query);
+}
+
+static gboolean
+gst_vaapipostproc_propose_allocation (GstBaseTransform * trans,
+    GstQuery * decide_query, GstQuery * query)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (trans);
+  GstCaps *allocation_caps;
+  GstStructure *structure;
+  gint allocation_width, allocation_height;
+  gint negotiated_width, negotiated_height;
+
+  /* passthrough query, we just bypass to the peer */
+  if (decide_query == NULL) {
+    return GST_BASE_TRANSFORM_CLASS
+        (gst_vaapipostproc_parent_class)->propose_allocation (trans,
+        decide_query, query);
+  }
+
+  /* advertise to upstream that we can handle crop meta */
+  if (decide_query)
+    gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
+
+  negotiated_width = GST_VIDEO_INFO_WIDTH (&postproc->sinkpad_info);
+  negotiated_height = GST_VIDEO_INFO_HEIGHT (&postproc->sinkpad_info);
+
+  if (negotiated_width == 0 || negotiated_height == 0)
+    goto bail;
+
+  allocation_caps = NULL;
+  gst_query_parse_allocation (query, &allocation_caps, NULL);
+  if (!allocation_caps)
+    goto bail;
+
+  structure = gst_caps_get_structure (allocation_caps, 0);
+  if (!gst_structure_get_int (structure, "width", &allocation_width))
+    goto bail;
+  if (!gst_structure_get_int (structure, "height", &allocation_height))
+    goto bail;
+
+  if (allocation_width != negotiated_width
+      || allocation_height != negotiated_height) {
+    g_mutex_lock (&postproc->postproc_lock);
+    postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SIZE;
+    g_mutex_unlock (&postproc->postproc_lock);
+  }
+
+bail:
+  /* Let vaapidecode allocate the video buffers */
+  if (postproc->get_va_surfaces)
+    return FALSE;
+  if (!gst_vaapi_plugin_base_propose_allocation (plugin, query))
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+gst_vaapipostproc_decide_allocation (GstBaseTransform * trans, GstQuery * query)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+
+  g_mutex_lock (&postproc->postproc_lock);
+  /* Let downstream handle the crop meta if they support it */
+  postproc->forward_crop = (gst_query_find_allocation_meta (query,
+          GST_VIDEO_CROP_META_API_TYPE, NULL) &&
+      gst_query_find_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL));
+  GST_DEBUG_OBJECT (postproc, "use_vpp_crop=%d", use_vpp_crop (postproc));
+  g_mutex_unlock (&postproc->postproc_lock);
+
+  return gst_vaapi_plugin_base_decide_allocation (GST_VAAPI_PLUGIN_BASE (trans),
+      query);
+}
+
+static void
+get_scale_factor (GstVaapiPostproc * const postproc, gdouble * w_factor,
+    gdouble * h_factor)
+{
+  gdouble wd = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info);
+  gdouble hd = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info);
+
+  g_return_if_fail (postproc->has_vpp);
+
+  switch (gst_vaapi_filter_get_video_direction (postproc->filter)) {
+    case GST_VIDEO_ORIENTATION_90R:
+    case GST_VIDEO_ORIENTATION_90L:
+    case GST_VIDEO_ORIENTATION_UR_LL:
+    case GST_VIDEO_ORIENTATION_UL_LR:
+      G_PRIMITIVE_SWAP (gdouble, wd, hd);
+      break;
+    default:
+      break;
+  }
+
+  *w_factor = GST_VIDEO_INFO_WIDTH (&postproc->sinkpad_info)
+      - (postproc->crop_left + postproc->crop_right);
+  *w_factor /= wd;
+
+  *h_factor = GST_VIDEO_INFO_HEIGHT (&postproc->sinkpad_info)
+      - (postproc->crop_top + postproc->crop_bottom);
+  *h_factor /= hd;
+}
+
+static gboolean
+gst_vaapipostproc_src_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  gdouble new_x = 0, new_y = 0, x = 0, y = 0, w_factor = 1, h_factor = 1;
+  gboolean ret;
+
+  GST_TRACE_OBJECT (postproc, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_NAVIGATION:
+      event = gst_event_make_writable (event);
+
+      if (postproc->has_vpp &&
+          gst_navigation_event_get_coordinates (event, &x, &y)) {
+        GST_DEBUG_OBJECT (postproc, "converting %fx%f", x, y);
+
+        /* video-direction compensation */
+        switch (gst_vaapi_filter_get_video_direction (postproc->filter)) {
+          case GST_VIDEO_ORIENTATION_90R:
+            new_x = y;
+            new_y = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) - 1 - x;
+            break;
+          case GST_VIDEO_ORIENTATION_90L:
+            new_x = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) - 1 - y;
+            new_y = x;
+            break;
+          case GST_VIDEO_ORIENTATION_UR_LL:
+            new_x = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) - 1 - y;
+            new_y = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) - 1 - x;
+            break;
+          case GST_VIDEO_ORIENTATION_UL_LR:
+            new_x = y;
+            new_y = x;
+            break;
+          case GST_VIDEO_ORIENTATION_180:
+            new_x = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) - 1 - x;
+            new_y = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) - 1 - y;
+            break;
+          case GST_VIDEO_ORIENTATION_HORIZ:
+            new_x = GST_VIDEO_INFO_WIDTH (&postproc->srcpad_info) - 1 - x;
+            new_y = y;
+            break;
+          case GST_VIDEO_ORIENTATION_VERT:
+            new_x = x;
+            new_y = GST_VIDEO_INFO_HEIGHT (&postproc->srcpad_info) - 1 - y;
+            break;
+          default:
+            new_x = x;
+            new_y = y;
+            break;
+        }
+
+        /* scale compensation */
+        get_scale_factor (postproc, &w_factor, &h_factor);
+        new_x *= w_factor;
+        new_y *= h_factor;
+
+        /* crop compensation */
+        new_x += postproc->crop_left;
+        new_y += postproc->crop_top;
+
+        GST_DEBUG_OBJECT (postproc, "to %fx%f", new_x, new_y);
+        gst_navigation_event_set_coordinates (event, new_x, new_y);
+      }
+      break;
+    default:
+      break;
+  }
+
+  ret =
+      GST_BASE_TRANSFORM_CLASS (gst_vaapipostproc_parent_class)->src_event
+      (trans, event);
+
+  return ret;
+}
+
+static gboolean
+gst_vaapipostproc_sink_event (GstBaseTransform * trans, GstEvent * event)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (trans);
+  GstTagList *taglist;
+  GstVideoOrientationMethod method;
+  gboolean ret;
+  gboolean do_reconf;
+
+  GST_DEBUG_OBJECT (postproc, "handling %s event", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TAG:
+      gst_event_parse_tag (event, &taglist);
+
+      do_reconf = gst_video_orientation_from_tag (taglist, &method);
+
+      if (do_reconf) {
+        postproc->tag_video_direction = method;
+        postproc->flags |= GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION;
+        gst_base_transform_reconfigure_src (trans);
+      }
+      break;
+    default:
+      break;
+  }
+
+  ret =
+      GST_BASE_TRANSFORM_CLASS (gst_vaapipostproc_parent_class)->sink_event
+      (trans, event);
+
+  return ret;
+}
+
+static void
+gst_vaapipostproc_finalize (GObject * object)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (object);
+
+  gst_vaapipostproc_destroy (postproc);
+
+  g_mutex_clear (&postproc->postproc_lock);
+  gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (postproc));
+  G_OBJECT_CLASS (gst_vaapipostproc_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapipostproc_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (object);
+  gboolean do_reconf = FALSE;
+
+  g_mutex_lock (&postproc->postproc_lock);
+  switch (prop_id) {
+#ifndef GST_REMOVE_DEPRECATED
+    case PROP_FORMAT:
+      postproc->format = g_value_get_enum (value);
+      break;
+    case PROP_WIDTH:
+    {
+      guint prev_width = postproc->width;
+      postproc->width = g_value_get_uint (value);
+      do_reconf = (prev_width != postproc->width);
+      break;
+    }
+    case PROP_HEIGHT:
+    {
+      guint prev_height = postproc->height;
+      postproc->height = g_value_get_uint (value);
+      do_reconf = (prev_height != postproc->height);
+      break;
+    }
+#endif
+    case PROP_FORCE_ASPECT_RATIO:
+      postproc->keep_aspect = g_value_get_boolean (value);
+      break;
+    case PROP_DEINTERLACE_MODE:
+      postproc->deinterlace_mode = g_value_get_enum (value);
+      break;
+    case PROP_DEINTERLACE_METHOD:
+      postproc->deinterlace_method = g_value_get_enum (value);
+      break;
+    case PROP_DENOISE:
+      postproc->denoise_level = g_value_get_float (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_DENOISE;
+      break;
+    case PROP_SHARPEN:
+      postproc->sharpen_level = g_value_get_float (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SHARPEN;
+      break;
+    case PROP_HUE:
+      postproc->hue = g_value_get_float (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_HUE;
+      break;
+    case PROP_SATURATION:
+      postproc->saturation = g_value_get_float (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SATURATION;
+      break;
+    case PROP_BRIGHTNESS:
+      postproc->brightness = g_value_get_float (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS;
+      break;
+    case PROP_CONTRAST:
+      postproc->contrast = g_value_get_float (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CONTRAST;
+      break;
+    case PROP_SCALE_METHOD:
+      postproc->scale_method = g_value_get_enum (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SCALE;
+      break;
+    case PROP_VIDEO_DIRECTION:
+      postproc->video_direction = g_value_get_enum (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION;
+      break;
+#ifndef GST_REMOVE_DEPRECATED
+    case PROP_SKIN_TONE_ENHANCEMENT:
+      postproc->skintone_enhance = g_value_get_boolean (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SKINTONE;
+      break;
+#endif
+    case PROP_SKIN_TONE_ENHANCEMENT_LEVEL:
+      postproc->skintone_value = g_value_get_uint (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL;
+      break;
+    case PROP_CROP_LEFT:
+    {
+      guint prev_crop_left = postproc->crop_left;
+      postproc->crop_left = g_value_get_uint (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CROP;
+      do_reconf = (prev_crop_left != postproc->crop_left);
+      break;
+    }
+    case PROP_CROP_RIGHT:
+    {
+      guint prev_crop_right = postproc->crop_right;
+      postproc->crop_right = g_value_get_uint (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CROP;
+      do_reconf = (prev_crop_right != postproc->crop_right);
+      break;
+    }
+    case PROP_CROP_TOP:
+    {
+      guint prev_crop_top = postproc->crop_top;
+      postproc->crop_top = g_value_get_uint (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CROP;
+      do_reconf = (prev_crop_top != postproc->crop_top);
+      break;
+    }
+    case PROP_CROP_BOTTOM:
+    {
+      guint prev_crop_bottom = postproc->crop_bottom;
+      postproc->crop_bottom = g_value_get_uint (value);
+      postproc->flags |= GST_VAAPI_POSTPROC_FLAG_CROP;
+      do_reconf = (prev_crop_bottom != postproc->crop_bottom);
+      break;
+    }
+    case PROP_HDR_TONE_MAP:
+      postproc->hdr_tone_map = g_value_get_enum (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  g_mutex_unlock (&postproc->postproc_lock);
+
+  if (do_reconf || check_filter_update (postproc))
+    gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (postproc));
+}
+
+static void
+gst_vaapipostproc_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (object);
+
+  g_mutex_lock (&postproc->postproc_lock);
+  switch (prop_id) {
+#ifndef GST_REMOVE_DEPRECATED
+    case PROP_FORMAT:
+      g_value_set_enum (value, postproc->format);
+      break;
+    case PROP_WIDTH:
+      g_value_set_uint (value, postproc->width);
+      break;
+    case PROP_HEIGHT:
+      g_value_set_uint (value, postproc->height);
+      break;
+#endif
+    case PROP_FORCE_ASPECT_RATIO:
+      g_value_set_boolean (value, postproc->keep_aspect);
+      break;
+    case PROP_DEINTERLACE_MODE:
+      g_value_set_enum (value, postproc->deinterlace_mode);
+      break;
+    case PROP_DEINTERLACE_METHOD:
+      g_value_set_enum (value, postproc->deinterlace_method);
+      break;
+    case PROP_DENOISE:
+      g_value_set_float (value, postproc->denoise_level);
+      break;
+    case PROP_SHARPEN:
+      g_value_set_float (value, postproc->sharpen_level);
+      break;
+    case PROP_HUE:
+      g_value_set_float (value, postproc->hue);
+      break;
+    case PROP_SATURATION:
+      g_value_set_float (value, postproc->saturation);
+      break;
+    case PROP_BRIGHTNESS:
+      g_value_set_float (value, postproc->brightness);
+      break;
+    case PROP_CONTRAST:
+      g_value_set_float (value, postproc->contrast);
+      break;
+    case PROP_SCALE_METHOD:
+      g_value_set_enum (value, postproc->scale_method);
+      break;
+    case PROP_VIDEO_DIRECTION:
+      g_value_set_enum (value, postproc->video_direction);
+      break;
+#ifndef GST_REMOVE_DEPRECATED
+    case PROP_SKIN_TONE_ENHANCEMENT:
+      g_value_set_boolean (value, postproc->skintone_enhance);
+      break;
+#endif
+    case PROP_SKIN_TONE_ENHANCEMENT_LEVEL:
+      g_value_set_uint (value, postproc->skintone_value);
+      break;
+    case PROP_CROP_LEFT:
+      g_value_set_uint (value, postproc->crop_left);
+      break;
+    case PROP_CROP_RIGHT:
+      g_value_set_uint (value, postproc->crop_right);
+      break;
+    case PROP_CROP_TOP:
+      g_value_set_uint (value, postproc->crop_top);
+      break;
+    case PROP_CROP_BOTTOM:
+      g_value_set_uint (value, postproc->crop_bottom);
+      break;
+    case PROP_HDR_TONE_MAP:
+      g_value_set_enum (value, postproc->hdr_tone_map);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+  g_mutex_unlock (&postproc->postproc_lock);
+}
+
+static void
+gst_vaapipostproc_class_init (GstVaapiPostprocClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstBaseTransformClass *const trans_class = GST_BASE_TRANSFORM_CLASS (klass);
+  GPtrArray *filter_ops;
+  GstVaapiFilterOpInfo *filter_op;
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_vaapipostproc,
+      GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
+
+  gst_vaapi_plugin_base_class_init (GST_VAAPI_PLUGIN_BASE_CLASS (klass));
+
+  object_class->finalize = gst_vaapipostproc_finalize;
+  object_class->set_property = gst_vaapipostproc_set_property;
+  object_class->get_property = gst_vaapipostproc_get_property;
+  trans_class->start = gst_vaapipostproc_start;
+  trans_class->stop = gst_vaapipostproc_stop;
+  trans_class->fixate_caps = gst_vaapipostproc_fixate_caps;
+  trans_class->transform_caps = gst_vaapipostproc_transform_caps;
+  trans_class->transform_size = gst_vaapipostproc_transform_size;
+  trans_class->transform_meta = gst_vaapipostproc_transform_meta;
+  trans_class->transform = gst_vaapipostproc_transform;
+  trans_class->set_caps = gst_vaapipostproc_set_caps;
+  trans_class->query = gst_vaapipostproc_query;
+  trans_class->propose_allocation = gst_vaapipostproc_propose_allocation;
+  trans_class->decide_allocation = gst_vaapipostproc_decide_allocation;
+  trans_class->src_event = gst_vaapipostproc_src_event;
+  trans_class->sink_event = gst_vaapipostproc_sink_event;
+
+  trans_class->prepare_output_buffer = gst_vaapipostproc_prepare_output_buffer;
+
+  element_class->set_context = gst_vaapi_base_set_context;
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API video postprocessing",
+      "Filter/Converter/Effect/Video/Scaler/Deinterlace/Hardware",
+      GST_PLUGIN_DESC, "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
+
+  /* sink pad */
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vaapipostproc_sink_factory);
+
+  /* src pad */
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vaapipostproc_src_factory);
+
+  /**
+   * GstVaapiPostproc:hdr-tone-map:
+   *
+   * Selects whether HDR tone mapping should not be applied or if it
+   * should be only applied on content that has the HDR meta on the caps.
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_HDR_TONE_MAP,
+      g_param_spec_enum ("hdr-tone-map",
+          "HDR Tone Map",
+          "Apply HDR tone mapping algorithm",
+          GST_VAAPI_TYPE_HDR_TONE_MAP,
+          GST_VAAPI_HDR_TONE_MAP_AUTO,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstVaapiPostproc:deinterlace-mode:
+   *
+   * This selects whether the deinterlacing should always be applied
+   * or if they should only be applied on content that has the
+   * "interlaced" flag on the caps.
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_DEINTERLACE_MODE,
+      g_param_spec_enum ("deinterlace-mode",
+          "Deinterlace mode",
+          "Deinterlace mode to use",
+          GST_VAAPI_TYPE_DEINTERLACE_MODE,
+          DEFAULT_DEINTERLACE_MODE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstVaapiPostproc:deinterlace-method:
+   *
+   * This selects the deinterlacing method to apply.
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_DEINTERLACE_METHOD,
+      g_param_spec_enum ("deinterlace-method",
+          "Deinterlace method",
+          "Deinterlace method to use",
+          GST_VAAPI_TYPE_DEINTERLACE_METHOD,
+          DEFAULT_DEINTERLACE_METHOD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+
+  filter_ops = gst_vaapi_filter_get_operations (NULL);
+  if (!filter_ops)
+    return;
+
+#ifndef GST_REMOVE_DEPRECATED
+  /**
+   * GstVaapiPostproc:format:
+   *
+   * The forced output pixel format, expressed as a #GstVideoFormat.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_FORMAT);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_FORMAT, filter_op->pspec);
+
+  /**
+   * GstVaapiPostproc:width:
+   *
+   * The forced output width in pixels. If set to zero, the width is
+   * calculated from the height if aspect ration is preserved, or
+   * inherited from the sink caps width
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_WIDTH,
+      g_param_spec_uint ("width",
+          "Width",
+          "Forced output width",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstVaapiPostproc:height:
+   *
+   * The forced output height in pixels. If set to zero, the height is
+   * calculated from the width if aspect ration is preserved, or
+   * inherited from the sink caps height
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_HEIGHT,
+      g_param_spec_uint ("height",
+          "Height",
+          "Forced output height",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+
+  /**
+   * GstVaapiPostproc:crop-left:
+   *
+   * The number of pixels to crop at left.
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_CROP_LEFT,
+      g_param_spec_uint ("crop-left",
+          "Crop Left",
+          "Pixels to crop at left",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstVaapiPostproc:crop-right:
+   *
+   * The number of pixels to crop at right.
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_CROP_RIGHT,
+      g_param_spec_uint ("crop-right",
+          "Crop Right",
+          "Pixels to crop at right",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+  * GstVaapiPostproc:crop-top:
+  *
+  * The number of pixels to crop at top.
+  */
+  g_object_class_install_property
+      (object_class,
+      PROP_CROP_TOP,
+      g_param_spec_uint ("crop-top",
+          "Crop Top",
+          "Pixels to crop at top",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstVaapiPostproc:crop-bottom:
+   *
+   * The number of pixels to crop at bottom.
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_CROP_BOTTOM,
+      g_param_spec_uint ("crop-bottom",
+          "Crop Bottom",
+          "Pixels to crop at bottom",
+          0, G_MAXINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstVaapiPostproc:force-aspect-ratio:
+   *
+   * When enabled, scaling respects video aspect ratio; when disabled,
+   * the video is distorted to fit the width and height properties.
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_FORCE_ASPECT_RATIO,
+      g_param_spec_boolean ("force-aspect-ratio",
+          "Force aspect ratio",
+          "When enabled, scaling will respect original aspect ratio",
+          TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  /**
+   * GstVaapiPostproc:denoise:
+   *
+   * The level of noise reduction to apply.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_DENOISE);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_DENOISE, filter_op->pspec);
+
+  /**
+   * GstVaapiPostproc:sharpen:
+   *
+   * The level of sharpening to apply for positive values, or the
+   * level of blurring for negative values.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SHARPEN);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_SHARPEN, filter_op->pspec);
+
+  /**
+   * GstVaapiPostproc:hue:
+   *
+   * The color hue, expressed as a float value. Range is -180.0 to
+   * 180.0. Default value is 0.0 and represents no modification.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_HUE);
+  if (filter_op)
+    g_object_class_install_property (object_class, PROP_HUE, filter_op->pspec);
+
+  /**
+   * GstVaapiPostproc:saturation:
+   *
+   * The color saturation, expressed as a float value. Range is 0.0 to
+   * 2.0. Default value is 1.0 and represents no modification.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SATURATION);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_SATURATION, filter_op->pspec);
+
+  /**
+   * GstVaapiPostproc:brightness:
+   *
+   * The color brightness, expressed as a float value. Range is -1.0
+   * to 1.0. Default value is 0.0 and represents no modification.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_BRIGHTNESS);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_BRIGHTNESS, filter_op->pspec);
+
+  /**
+   * GstVaapiPostproc:contrast:
+   *
+   * The color contrast, expressed as a float value. Range is 0.0 to
+   * 2.0. Default value is 1.0 and represents no modification.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_CONTRAST);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_CONTRAST, filter_op->pspec);
+
+  /**
+   * GstVaapiPostproc:scale-method:
+   *
+   * The scaling method to use, expressed as an enum value. See
+   * #GstVaapiScaleMethod.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SCALING);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_SCALE_METHOD, filter_op->pspec);
+
+  /**
+   * GstVaapiPostproc:video-direction:
+   *
+   * The video-direction to use, expressed as an enum value. See
+   * #GstVideoDirection.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_VIDEO_DIRECTION);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_VIDEO_DIRECTION, filter_op->pspec);
+
+#ifndef GST_REMOVE_DEPRECATED
+  /**
+   * GstVaapiPostproc:skin-tone-enhancement:
+   *
+   * Apply the skin tone enhancement algorithm.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SKINTONE);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_SKIN_TONE_ENHANCEMENT, filter_op->pspec);
+#endif
+
+  /**
+   * GstVaapiPostproc:skin-tone-enhancement-setting:
+   *
+   * Apply the skin tone enhancement algorithm with specified value.
+   */
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL);
+  if (filter_op)
+    g_object_class_install_property (object_class,
+        PROP_SKIN_TONE_ENHANCEMENT_LEVEL, filter_op->pspec);
+
+  g_ptr_array_unref (filter_ops);
+}
+
+static float *
+find_value_ptr (GstVaapiPostproc * postproc, GstVaapiFilterOp op)
+{
+  switch (op) {
+    case GST_VAAPI_FILTER_OP_HUE:
+      return &postproc->hue;
+    case GST_VAAPI_FILTER_OP_SATURATION:
+      return &postproc->saturation;
+    case GST_VAAPI_FILTER_OP_BRIGHTNESS:
+      return &postproc->brightness;
+    case GST_VAAPI_FILTER_OP_CONTRAST:
+      return &postproc->contrast;
+    default:
+      return NULL;
+  }
+}
+
+static void
+cb_set_default_value (GstVaapiPostproc * postproc, GPtrArray * filter_ops,
+    GstVaapiFilterOp op)
+{
+  GstVaapiFilterOpInfo *filter_op;
+  GParamSpecFloat *pspec;
+  float *var;
+
+  filter_op = find_filter_op (filter_ops, op);
+  if (!filter_op)
+    return;
+  var = find_value_ptr (postproc, op);
+  if (!var)
+    return;
+  pspec = G_PARAM_SPEC_FLOAT (filter_op->pspec);
+  *var = pspec->default_value;
+}
+
+static void
+skintone_set_default_value (GstVaapiPostproc * postproc, GPtrArray * filter_ops)
+{
+  GstVaapiFilterOpInfo *filter_op;
+  GParamSpecUInt *pspec;
+
+  filter_op = find_filter_op (filter_ops, GST_VAAPI_FILTER_OP_SKINTONE_LEVEL);
+  if (!filter_op)
+    return;
+  pspec = G_PARAM_SPEC_UINT (filter_op->pspec);
+  postproc->skintone_value = pspec->default_value;
+}
+
+static void
+gst_vaapipostproc_init (GstVaapiPostproc * postproc)
+{
+  GPtrArray *filter_ops;
+  guint i;
+
+  gst_vaapi_plugin_base_init (GST_VAAPI_PLUGIN_BASE (postproc),
+      GST_CAT_DEFAULT);
+
+  g_mutex_init (&postproc->postproc_lock);
+  postproc->format = DEFAULT_FORMAT;
+  postproc->hdr_tone_map = GST_VAAPI_HDR_TONE_MAP_AUTO;
+  postproc->deinterlace_mode = DEFAULT_DEINTERLACE_MODE;
+  postproc->deinterlace_method = DEFAULT_DEINTERLACE_METHOD;
+  postproc->field_duration = GST_CLOCK_TIME_NONE;
+  postproc->keep_aspect = TRUE;
+  postproc->get_va_surfaces = TRUE;
+  postproc->forward_crop = FALSE;
+
+  /* AUTO is not valid for tag_video_direction, this is just to
+   * ensure we setup the method as sink event tag */
+  postproc->tag_video_direction = GST_VIDEO_ORIENTATION_AUTO;
+
+  filter_ops = gst_vaapi_filter_get_operations (NULL);
+  if (filter_ops) {
+    for (i = GST_VAAPI_FILTER_OP_HUE; i <= GST_VAAPI_FILTER_OP_CONTRAST; i++)
+      cb_set_default_value (postproc, filter_ops, i);
+
+    skintone_set_default_value (postproc, filter_ops);
+    g_ptr_array_unref (filter_ops);
+  }
+
+  gst_video_info_init (&postproc->sinkpad_info);
+  gst_video_info_init (&postproc->srcpad_info);
+  gst_video_info_init (&postproc->filter_pool_info);
+}
+
+/* ------------------------------------------------------------------------ */
+/* --- GstColorBalance interface                                        --- */
+/* ------------------------------------------------------------------------ */
+
+#define CB_CHANNEL_FACTOR 1000.0
+
+typedef struct
+{
+  GstVaapiFilterOp op;
+  const gchar *name;
+} ColorBalanceChannel;
+
+ColorBalanceChannel cb_channels[] = {
+  {
+      GST_VAAPI_FILTER_OP_HUE, "VA_FILTER_HUE"}, {
+      GST_VAAPI_FILTER_OP_SATURATION, "VA_FILTER_SATURATION"}, {
+      GST_VAAPI_FILTER_OP_BRIGHTNESS, "VA_FILTER_BRIGHTNESS"}, {
+      GST_VAAPI_FILTER_OP_CONTRAST, "VA_FILTER_CONTRAST"},
+};
+
+static void
+cb_channels_init (GstVaapiPostproc * postproc)
+{
+  GPtrArray *filter_ops;
+  GstVaapiFilterOpInfo *filter_op;
+  GParamSpecFloat *pspec;
+  GstColorBalanceChannel *channel;
+  guint i;
+
+  if (postproc->cb_channels)
+    return;
+
+  g_mutex_lock (&postproc->postproc_lock);
+  if (!gst_vaapipostproc_ensure_filter (postproc)) {
+    g_mutex_unlock (&postproc->postproc_lock);
+    return;
+  }
+  g_mutex_unlock (&postproc->postproc_lock);
+
+  filter_ops = postproc->filter_ops ? g_ptr_array_ref (postproc->filter_ops)
+      : gst_vaapi_filter_get_operations (postproc->filter);
+  if (!filter_ops)
+    return;
+
+  for (i = 0; i < G_N_ELEMENTS (cb_channels); i++) {
+    filter_op = find_filter_op (filter_ops, cb_channels[i].op);
+    if (!filter_op)
+      continue;
+
+    pspec = G_PARAM_SPEC_FLOAT (filter_op->pspec);
+    channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
+    channel->label = g_strdup (cb_channels[i].name);
+    channel->min_value = pspec->minimum * CB_CHANNEL_FACTOR;
+    channel->max_value = pspec->maximum * CB_CHANNEL_FACTOR;
+
+    postproc->cb_channels = g_list_prepend (postproc->cb_channels, channel);
+  }
+
+  g_ptr_array_unref (filter_ops);
+}
+
+static const GList *
+gst_vaapipostproc_colorbalance_list_channels (GstColorBalance * balance)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (balance);
+
+  cb_channels_init (postproc);
+  return postproc->cb_channels;
+}
+
+static gfloat *
+cb_get_value_ptr (GstVaapiPostproc * postproc,
+    GstColorBalanceChannel * channel, GstVaapiPostprocFlags * flags)
+{
+  guint i;
+  gfloat *ret = NULL;
+
+  for (i = 0; i < G_N_ELEMENTS (cb_channels); i++) {
+    if (g_ascii_strcasecmp (cb_channels[i].name, channel->label) == 0)
+      break;
+  }
+  if (i >= G_N_ELEMENTS (cb_channels))
+    return NULL;
+
+  ret = find_value_ptr (postproc, cb_channels[i].op);
+  if (flags)
+    *flags = 1 << cb_channels[i].op;
+  return ret;
+}
+
+static void
+gst_vaapipostproc_colorbalance_set_value (GstColorBalance * balance,
+    GstColorBalanceChannel * channel, gint value)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (balance);
+  GstVaapiPostprocFlags flags;
+  gfloat new_val, *var;
+
+  value = CLAMP (value, channel->min_value, channel->max_value);
+  new_val = (gfloat) value / CB_CHANNEL_FACTOR;
+
+  var = cb_get_value_ptr (postproc, channel, &flags);
+  if (var) {
+    *var = new_val;
+    g_mutex_lock (&postproc->postproc_lock);
+    postproc->flags |= flags;
+    g_mutex_unlock (&postproc->postproc_lock);
+    gst_color_balance_value_changed (balance, channel, value);
+    if (check_filter_update (postproc))
+      gst_base_transform_reconfigure_src (GST_BASE_TRANSFORM (postproc));
+    return;
+  }
+
+  GST_WARNING_OBJECT (postproc, "unknown channel %s", channel->label);
+}
+
+static gint
+gst_vaapipostproc_colorbalance_get_value (GstColorBalance * balance,
+    GstColorBalanceChannel * channel)
+{
+  GstVaapiPostproc *const postproc = GST_VAAPIPOSTPROC (balance);
+  gfloat *var;
+  gint new_val;
+
+  var = cb_get_value_ptr (postproc, channel, NULL);
+  if (var) {
+    new_val = (gint) ((*var) * CB_CHANNEL_FACTOR);
+    new_val = CLAMP (new_val, channel->min_value, channel->max_value);
+    return new_val;
+  }
+
+  GST_WARNING_OBJECT (postproc, "unknown channel %s", channel->label);
+  return G_MININT;
+}
+
+static GstColorBalanceType
+gst_vaapipostproc_colorbalance_get_balance_type (GstColorBalance * balance)
+{
+  return GST_COLOR_BALANCE_HARDWARE;
+}
+
+static void
+gst_vaapipostproc_colorbalance_init (gpointer iface, gpointer data)
+{
+  GstColorBalanceInterface *cbface = iface;
+  cbface->list_channels = gst_vaapipostproc_colorbalance_list_channels;
+  cbface->set_value = gst_vaapipostproc_colorbalance_set_value;
+  cbface->get_value = gst_vaapipostproc_colorbalance_get_value;
+  cbface->get_balance_type = gst_vaapipostproc_colorbalance_get_balance_type;
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostproc.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostproc.h
new file mode 100644 (file)
index 0000000..9a0d52d
--- /dev/null
@@ -0,0 +1,230 @@
+/*
+ *  gstvaapipostproc.h - VA-API video post processing
+ *
+ *  Copyright (C) 2012-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+*/
+
+#ifndef GST_VAAPIPOSTPROC_H
+#define GST_VAAPIPOSTPROC_H
+
+#include "gstvaapipluginbase.h"
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapisurfacepool.h>
+#include <gst/vaapi/gstvaapifilter.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPIPOSTPROC \
+  (gst_vaapipostproc_get_type ())
+#define GST_VAAPIPOSTPROC(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPIPOSTPROC, GstVaapiPostproc))
+#define GST_VAAPIPOSTPROC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPIPOSTPROC, \
+       GstVaapiPostprocClass))
+#define GST_IS_VAAPIPOSTPROC(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE((obj), GST_TYPE_VAAPIPOSTPROC))
+#define GST_IS_VAAPIPOSTPROC_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_VAAPIPOSTPROC))
+#define GST_VAAPIPOSTPROC_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS((obj), GST_TYPE_VAAPIPOSTPROC, \
+       GstVaapiPostprocClass))
+
+typedef struct _GstVaapiPostproc GstVaapiPostproc;
+typedef struct _GstVaapiPostprocClass GstVaapiPostprocClass;
+typedef struct _GstVaapiDeinterlaceState GstVaapiDeinterlaceState;
+
+/**
+ * GstVaapiHDRToneMap:
+ * @GST_VAAPI_TYPE_HDR_TONE_MAP_AUTO: Auto detect need for hdr tone map.
+ * @GST_VAAPI_TYPE_HDR_TONE_MAP_DISABLED: Never perform hdr tone map.
+ */
+typedef enum
+{
+  GST_VAAPI_HDR_TONE_MAP_AUTO = 0,
+  GST_VAAPI_HDR_TONE_MAP_DISABLED,
+} GstVaapiHDRToneMap;
+
+/**
+ * GstVaapiDeinterlaceMode:
+ * @GST_VAAPI_DEINTERLACE_MODE_AUTO: Auto detect needs for deinterlacing.
+ * @GST_VAAPI_DEINTERLACE_MODE_INTERLACED: Force deinterlacing.
+ * @GST_VAAPI_DEINTERLACE_MODE_DISABLED: Never perform deinterlacing.
+ */
+typedef enum
+{
+  GST_VAAPI_DEINTERLACE_MODE_AUTO = 0,
+  GST_VAAPI_DEINTERLACE_MODE_INTERLACED,
+  GST_VAAPI_DEINTERLACE_MODE_DISABLED,
+} GstVaapiDeinterlaceMode;
+
+/*
+ * GST_VAAPI_DEINTERLACE_MAX_REFERENCES:
+ *
+ * This represents the maximum number of VA surfaces we could keep as
+ * references for advanced deinterlacing.
+ *
+ * Note: if the upstream element is vaapidecode, then the maximum
+ * number of allowed surfaces used as references shall be less than
+ * the actual number of scratch surfaces used for decoding (4).
+ */
+#define GST_VAAPI_DEINTERLACE_MAX_REFERENCES 2
+
+/**
+ * GstVaapiPostprocFlags:
+ * @GST_VAAPI_POSTPROC_FLAG_FORMAT: Pixel format conversion.
+ * @GST_VAAPI_POSTPROC_FLAG_DENOISE: Noise reduction.
+ * @GST_VAAPI_POSTPROC_FLAG_SHARPEN: Sharpening.
+ * @GST_VAAPI_POSTPROC_FLAG_HUE: Change color hue.
+ * @GST_VAAPI_POSTPROC_FLAG_SATURATION: Change saturation.
+ * @GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS: Change brightness.
+ * @GST_VAAPI_POSTPROC_FLAG_CONTRAST: Change contrast.
+ * @GST_VAAPI_POSTPROC_FLAG_DEINTERLACE: Deinterlacing.
+ * @GST_VAAPI_POSTPROC_FLAG_SIZE: Video scaling.
+ * @GST_VAAPI_POSTPROC_FLAG_SCALE: Video scaling mode.
+ * @GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION: Video rotation and flip/mirroring.
+ * @GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP: HDR tone mapping.
+ * @GST_VAAPI_POSTPROC_FLAG_SKINTONE: Skin tone enhancement.
+ * @GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL: Skin tone enhancement with value.
+ *
+ * The set of operations that are to be performed for each frame.
+ */
+typedef enum
+{
+  GST_VAAPI_POSTPROC_FLAG_FORMAT      = 1 << GST_VAAPI_FILTER_OP_FORMAT,
+  GST_VAAPI_POSTPROC_FLAG_DENOISE     = 1 << GST_VAAPI_FILTER_OP_DENOISE,
+  GST_VAAPI_POSTPROC_FLAG_SHARPEN     = 1 << GST_VAAPI_FILTER_OP_SHARPEN,
+  GST_VAAPI_POSTPROC_FLAG_HUE         = 1 << GST_VAAPI_FILTER_OP_HUE,
+  GST_VAAPI_POSTPROC_FLAG_SATURATION  = 1 << GST_VAAPI_FILTER_OP_SATURATION,
+  GST_VAAPI_POSTPROC_FLAG_BRIGHTNESS  = 1 << GST_VAAPI_FILTER_OP_BRIGHTNESS,
+  GST_VAAPI_POSTPROC_FLAG_CONTRAST    = 1 << GST_VAAPI_FILTER_OP_CONTRAST,
+  GST_VAAPI_POSTPROC_FLAG_DEINTERLACE = 1 << GST_VAAPI_FILTER_OP_DEINTERLACING,
+  GST_VAAPI_POSTPROC_FLAG_SCALE       = 1 << GST_VAAPI_FILTER_OP_SCALING,
+  GST_VAAPI_POSTPROC_FLAG_VIDEO_DIRECTION =
+      1 << GST_VAAPI_FILTER_OP_VIDEO_DIRECTION,
+  GST_VAAPI_POSTPROC_FLAG_CROP        = 1 << GST_VAAPI_FILTER_OP_CROP,
+  GST_VAAPI_POSTPROC_FLAG_HDR_TONE_MAP = 1 << GST_VAAPI_FILTER_OP_HDR_TONE_MAP,
+#ifndef GST_REMOVE_DEPRECATED
+  GST_VAAPI_POSTPROC_FLAG_SKINTONE    = 1 << GST_VAAPI_FILTER_OP_SKINTONE,
+#endif
+  GST_VAAPI_POSTPROC_FLAG_SKINTONE_LEVEL =
+      1 << GST_VAAPI_FILTER_OP_SKINTONE_LEVEL,
+
+  /* Additional custom flags */
+  GST_VAAPI_POSTPROC_FLAG_CUSTOM      = 1 << 20,
+  GST_VAAPI_POSTPROC_FLAG_SIZE        = GST_VAAPI_POSTPROC_FLAG_CUSTOM,
+} GstVaapiPostprocFlags;
+
+/*
+ * GstVaapiDeinterlaceState:
+ * @buffers: history buffer, maintained as a cyclic array
+ * @buffers_index: next free slot in the history buffer
+ * @surfaces: array of surfaces used as references
+ * @num_surfaces: number of active surfaces in that array
+ * @deint: flag: previous buffers were interlaced?
+ * @tff: flag: previous buffers were organized as top-field-first?
+ *
+ * Context used to maintain deinterlacing state.
+ */
+struct _GstVaapiDeinterlaceState
+{
+  GstBuffer *buffers[GST_VAAPI_DEINTERLACE_MAX_REFERENCES];
+  guint buffers_index;
+  GstVaapiSurface *surfaces[GST_VAAPI_DEINTERLACE_MAX_REFERENCES];
+  guint num_surfaces;
+  guint deint:1;
+  guint tff:1;
+};
+
+struct _GstVaapiPostproc
+{
+  /*< private >*/
+  GstVaapiPluginBase parent_instance;
+
+  GMutex postproc_lock;
+  GstVaapiFilter *filter;
+  GPtrArray *filter_ops;
+  GstVaapiVideoPool *filter_pool;
+  GstVideoInfo filter_pool_info;
+  GArray *filter_formats;
+  GstVideoFormat format;        /* output video format (encoded) */
+  guint width;
+  guint height;
+  guint flags;
+
+  GstCaps *allowed_sinkpad_caps;
+  GstVideoInfo sinkpad_info;
+  GstCaps *allowed_srcpad_caps;
+  GstVideoInfo srcpad_info;
+
+  /* HDR Tone Mapping */
+  GstVaapiHDRToneMap hdr_tone_map;
+
+  /* Deinterlacing */
+  GstVaapiDeinterlaceMode deinterlace_mode;
+  GstVaapiDeinterlaceMethod deinterlace_method;
+  GstVaapiDeinterlaceState deinterlace_state;
+  GstClockTime field_duration;
+
+  /* Basic filter values */
+  gfloat denoise_level;
+  gfloat sharpen_level;
+
+  GstVaapiScaleMethod scale_method;
+
+  GstVideoOrientationMethod video_direction;
+  GstVideoOrientationMethod tag_video_direction;
+
+  /* Cropping */
+  guint crop_left;
+  guint crop_right;
+  guint crop_top;
+  guint crop_bottom;
+
+  /* Color balance filter values */
+  gfloat hue;
+  gfloat saturation;
+  gfloat brightness;
+  gfloat contrast;
+
+  gboolean skintone_enhance;
+  guint skintone_value;
+  gboolean forward_crop;
+
+  guint get_va_surfaces:1;
+  guint has_vpp:1;
+  guint use_vpp:1;
+  guint keep_aspect:1;
+
+  /* color balance's channel list */
+  GList *cb_channels;
+  gboolean same_caps;
+};
+
+struct _GstVaapiPostprocClass
+{
+  /*< private >*/
+  GstVaapiPluginBaseClass parent_class;
+};
+
+GType
+gst_vaapipostproc_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GST_VAAPIPOSTPROC_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostprocutil.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostprocutil.c
new file mode 100644 (file)
index 0000000..715a449
--- /dev/null
@@ -0,0 +1,786 @@
+/*
+ *  gstvaapipostprocutil.h - VA-API video post processing utilities
+ *
+ *  Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
+ *  Copyright (C) 2005-2012 David Schleef <ds@schleef.org>
+ *  Copyright (C) 2016 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *    Author: Victor Jaquez <victorx.jaquez@intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include <gst/vaapi/gstvaapifilter.h>
+
+#include "gstvaapipostprocutil.h"
+#include "gstvaapipluginutil.h"
+
+#define GST_CAT_DEFAULT (GST_VAAPI_PLUGIN_BASE (postproc)->debug_category)
+
+/* if format property is set */
+static void
+_transform_format (GstVaapiPostproc * postproc, GstCapsFeatures * features,
+    GstStructure * structure)
+{
+  GValue value = G_VALUE_INIT;
+
+  if (postproc->format == DEFAULT_FORMAT)
+    return;
+
+  if (!gst_caps_features_is_equal (features,
+          GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)
+      && !gst_caps_features_contains (features,
+          GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE))
+    return;
+
+  if (!gst_vaapi_value_set_format (&value, postproc->format))
+    return;
+
+  gst_structure_set_value (structure, "format", &value);
+  g_value_unset (&value);
+}
+
+static void
+_set_int (GValue * value, gint val)
+{
+  g_value_init (value, G_TYPE_INT);
+  g_value_set_int (value, val);
+}
+
+static void
+_set_int_range (GValue * value)
+{
+  g_value_init (value, GST_TYPE_INT_RANGE);
+  gst_value_set_int_range (value, 1, G_MAXINT);
+}
+
+static void
+_transform_frame_size (GstVaapiPostproc * postproc, GstStructure * structure)
+{
+  GValue width = G_VALUE_INIT;
+  GValue height = G_VALUE_INIT;
+
+  if (postproc->width && postproc->height) {
+    _set_int (&width, postproc->width);
+    _set_int (&height, postproc->height);
+  } else if (postproc->width) {
+    _set_int (&width, postproc->width);
+    _set_int_range (&height);
+  } else if (postproc->height) {
+    _set_int_range (&width);
+    _set_int (&height, postproc->height);
+  } else {
+    _set_int_range (&width);
+    _set_int_range (&height);
+  }
+
+  gst_structure_set_value (structure, "width", &width);
+  gst_structure_set_value (structure, "height", &height);
+}
+
+/**
+ * gst_vaapipostproc_transform_srccaps:
+ * @postproc: a #GstVaapiPostproc instance
+ *
+ * Early apply transformation of the src pad caps according to the set
+ * properties.
+ *
+ * Returns: A new allocated #GstCaps
+ **/
+GstCaps *
+gst_vaapipostproc_transform_srccaps (GstVaapiPostproc * postproc)
+{
+  GstCaps *out_caps;
+  GstStructure *structure;
+  GstCapsFeatures *features;
+  gint i, n;
+
+  out_caps = gst_caps_new_empty ();
+  n = gst_caps_get_size (postproc->allowed_srcpad_caps);
+
+  for (i = 0; i < n; i++) {
+    structure = gst_caps_get_structure (postproc->allowed_srcpad_caps, i);
+    features = gst_caps_get_features (postproc->allowed_srcpad_caps, i);
+
+    /* make copy */
+    structure = gst_structure_copy (structure);
+
+    if (postproc->keep_aspect)
+      gst_structure_set (structure, "pixel-aspect-ratio", GST_TYPE_FRACTION, 1,
+          1, NULL);
+
+    _transform_format (postproc, features, structure);
+    _transform_frame_size (postproc, structure);
+
+    gst_caps_append_structure_full (out_caps, structure,
+        gst_caps_features_copy (features));
+  }
+
+  return out_caps;
+}
+
+gboolean
+is_deinterlace_enabled (GstVaapiPostproc * postproc, GstVideoInfo * vip)
+{
+  gboolean deinterlace;
+
+  switch (postproc->deinterlace_mode) {
+    case GST_VAAPI_DEINTERLACE_MODE_AUTO:
+      deinterlace = GST_VIDEO_INFO_IS_INTERLACED (vip);
+      break;
+    case GST_VAAPI_DEINTERLACE_MODE_INTERLACED:
+      deinterlace = TRUE;
+      break;
+    default:
+      deinterlace = FALSE;
+      break;
+  }
+  return deinterlace;
+}
+
+static gboolean
+_fixate_frame_size (GstVaapiPostproc * postproc, GstVideoInfo * vinfo,
+    GstStructure * outs)
+{
+  const GValue *to_par;
+  GValue tpar = G_VALUE_INIT;
+  gboolean ret;
+
+  ret = TRUE;
+  to_par = gst_structure_get_value (outs, "pixel-aspect-ratio");
+  if (!to_par) {
+    g_value_init (&tpar, GST_TYPE_FRACTION_RANGE);
+    gst_value_set_fraction_range_full (&tpar, 1, G_MAXINT, G_MAXINT, 1);
+    to_par = &tpar;
+  }
+
+  /* we have both PAR but they might not be fixated */
+  {
+    gint from_w, from_h, from_par_n, from_par_d, to_par_n, to_par_d;
+    gint w = 0, h = 0;
+    gint from_dar_n, from_dar_d;
+    gint num, den;
+
+    from_par_n = GST_VIDEO_INFO_PAR_N (vinfo);
+    from_par_d = GST_VIDEO_INFO_PAR_D (vinfo);
+    from_w = GST_VIDEO_INFO_WIDTH (vinfo);
+    from_h = GST_VIDEO_INFO_HEIGHT (vinfo);
+
+    if (postproc->has_vpp) {
+      /* adjust for crop settings */
+      from_w -= postproc->crop_left + postproc->crop_right;
+      from_h -= postproc->crop_top + postproc->crop_bottom;
+
+      /* compensate for rotation if needed */
+      switch (gst_vaapi_filter_get_video_direction (postproc->filter)) {
+        case GST_VIDEO_ORIENTATION_90R:
+        case GST_VIDEO_ORIENTATION_90L:
+        case GST_VIDEO_ORIENTATION_UL_LR:
+        case GST_VIDEO_ORIENTATION_UR_LL:
+          G_PRIMITIVE_SWAP (gint, from_w, from_h);
+          G_PRIMITIVE_SWAP (gint, from_par_n, from_par_d);
+        default:
+          break;
+      }
+    }
+
+    gst_structure_get_int (outs, "width", &w);
+    gst_structure_get_int (outs, "height", &h);
+
+    /* if both width and height are already fixed, we can't do anything
+     * about it anymore */
+    if (w && h) {
+      guint n, d;
+
+      GST_DEBUG_OBJECT (postproc,
+          "dimensions already set to %dx%d, not fixating", w, h);
+
+      if (!gst_value_is_fixed (to_par)) {
+        if (gst_video_calculate_display_ratio (&n, &d, from_w, from_h,
+                from_par_n, from_par_d, w, h)) {
+          GST_DEBUG_OBJECT (postproc, "fixating to_par to %dx%d", n, d);
+          if (gst_structure_has_field (outs, "pixel-aspect-ratio"))
+            gst_structure_fixate_field_nearest_fraction (outs,
+                "pixel-aspect-ratio", n, d);
+          else if (n != d)
+            gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+                n, d, NULL);
+        }
+      }
+
+      goto done;
+    }
+
+    /* Calculate input DAR */
+    if (!gst_util_fraction_multiply (from_w, from_h, from_par_n, from_par_d,
+            &from_dar_n, &from_dar_d))
+      goto overflow_error;
+
+    GST_DEBUG_OBJECT (postproc, "Input DAR is %d/%d", from_dar_n, from_dar_d);
+
+    /* If either width or height are fixed there's not much we
+     * can do either except choosing a height or width and PAR
+     * that matches the DAR as good as possible
+     */
+    if (h) {
+      GstStructure *tmp;
+      gint set_w, set_par_n, set_par_d;
+
+      GST_DEBUG_OBJECT (postproc, "height is fixed (%d)", h);
+
+      /* If the PAR is fixed too, there's not much to do
+       * except choosing the width that is nearest to the
+       * width with the same DAR */
+      if (gst_value_is_fixed (to_par)) {
+        to_par_n = gst_value_get_fraction_numerator (to_par);
+        to_par_d = gst_value_get_fraction_denominator (to_par);
+
+        GST_DEBUG_OBJECT (postproc, "PAR is fixed %d/%d", to_par_n, to_par_d);
+
+        if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
+                to_par_n, &num, &den))
+          goto overflow_error;
+
+        w = (guint) gst_util_uint64_scale_int (h, num, den);
+        gst_structure_fixate_field_nearest_int (outs, "width", w);
+
+        goto done;
+      }
+
+      /* The PAR is not fixed and it's quite likely that we can set
+       * an arbitrary PAR. */
+
+      /* Check if we can keep the input width */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
+      gst_structure_get_int (tmp, "width", &set_w);
+
+      /* Might have failed but try to keep the DAR nonetheless by
+       * adjusting the PAR */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, h, set_w,
+              &to_par_n, &to_par_d)) {
+        gst_structure_free (tmp);
+        goto overflow_error;
+      }
+
+      if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
+        gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
+      gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
+          to_par_n, to_par_d);
+      gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
+          &set_par_d);
+      gst_structure_free (tmp);
+
+      /* Check if the adjusted PAR is accepted */
+      if (set_par_n == to_par_n && set_par_d == to_par_d) {
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "width", G_TYPE_INT, set_w,
+              "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
+              NULL);
+        goto done;
+      }
+
+      /* Otherwise scale the width to the new PAR and check if the
+       * adjusted with is accepted. If all that fails we can't keep
+       * the DAR */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
+              set_par_n, &num, &den))
+        goto overflow_error;
+
+      w = (guint) gst_util_uint64_scale_int (h, num, den);
+      gst_structure_fixate_field_nearest_int (outs, "width", w);
+      if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+          set_par_n != set_par_d)
+        gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+            set_par_n, set_par_d, NULL);
+
+      goto done;
+    } else if (w) {
+      GstStructure *tmp;
+      gint set_h, set_par_n, set_par_d;
+
+      GST_DEBUG_OBJECT (postproc, "width is fixed (%d)", w);
+
+      /* If the PAR is fixed too, there's not much to do
+       * except choosing the height that is nearest to the
+       * height with the same DAR */
+      if (gst_value_is_fixed (to_par)) {
+        to_par_n = gst_value_get_fraction_numerator (to_par);
+        to_par_d = gst_value_get_fraction_denominator (to_par);
+
+        GST_DEBUG_OBJECT (postproc, "PAR is fixed %d/%d", to_par_n, to_par_d);
+
+        if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_d,
+                to_par_n, &num, &den))
+          goto overflow_error;
+
+        h = (guint) gst_util_uint64_scale_int (w, den, num);
+        gst_structure_fixate_field_nearest_int (outs, "height", h);
+
+        goto done;
+      }
+
+      /* The PAR is not fixed and it's quite likely that we can set
+       * an arbitrary PAR. */
+
+      /* Check if we can keep the input height */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
+      gst_structure_get_int (tmp, "height", &set_h);
+
+      /* Might have failed but try to keep the DAR nonetheless by
+       * adjusting the PAR */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, w,
+              &to_par_n, &to_par_d)) {
+        gst_structure_free (tmp);
+        goto overflow_error;
+      }
+
+      if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
+        gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
+      gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
+          to_par_n, to_par_d);
+      gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
+          &set_par_d);
+      gst_structure_free (tmp);
+
+      /* Check if the adjusted PAR is accepted */
+      if (set_par_n == to_par_n && set_par_d == to_par_d) {
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "height", G_TYPE_INT, set_h,
+              "pixel-aspect-ratio", GST_TYPE_FRACTION, set_par_n, set_par_d,
+              NULL);
+        goto done;
+      }
+
+      /* Otherwise scale the height to the new PAR and check if the
+       * adjusted with is accepted. If all that fails we can't keep
+       * the DAR */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
+              set_par_n, &num, &den))
+        goto overflow_error;
+
+      h = (guint) gst_util_uint64_scale_int (w, den, num);
+      gst_structure_fixate_field_nearest_int (outs, "height", h);
+      if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+          set_par_n != set_par_d)
+        gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+            set_par_n, set_par_d, NULL);
+
+      goto done;
+    } else if (gst_value_is_fixed (to_par)) {
+      GstStructure *tmp;
+      gint set_h, set_w, f_h, f_w;
+
+      to_par_n = gst_value_get_fraction_numerator (to_par);
+      to_par_d = gst_value_get_fraction_denominator (to_par);
+
+      /* Calculate scale factor for the PAR change */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, to_par_n,
+              to_par_d, &num, &den))
+        goto overflow_error;
+
+      /* Try to keep the input height (because of interlacing) */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
+      gst_structure_get_int (tmp, "height", &set_h);
+
+      /* This might have failed but try to scale the width
+       * to keep the DAR nonetheless */
+      w = (guint) gst_util_uint64_scale_int (set_h, num, den);
+      gst_structure_fixate_field_nearest_int (tmp, "width", w);
+      gst_structure_get_int (tmp, "width", &set_w);
+      gst_structure_free (tmp);
+
+      /* We kept the DAR and the height is nearest to the original height */
+      if (set_w == w) {
+        gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+            G_TYPE_INT, set_h, NULL);
+        goto done;
+      }
+
+      f_h = set_h;
+      f_w = set_w;
+
+      /* If the former failed, try to keep the input width at least */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
+      gst_structure_get_int (tmp, "width", &set_w);
+
+      /* This might have failed but try to scale the width
+       * to keep the DAR nonetheless */
+      h = (guint) gst_util_uint64_scale_int (set_w, den, num);
+      gst_structure_fixate_field_nearest_int (tmp, "height", h);
+      gst_structure_get_int (tmp, "height", &set_h);
+      gst_structure_free (tmp);
+
+      /* We kept the DAR and the width is nearest to the original width */
+      if (set_h == h) {
+        gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+            G_TYPE_INT, set_h, NULL);
+        goto done;
+      }
+
+      /* If all this failed, keep the height that was nearest to the orignal
+       * height and the nearest possible width. This changes the DAR but
+       * there's not much else to do here.
+       */
+      gst_structure_set (outs, "width", G_TYPE_INT, f_w, "height", G_TYPE_INT,
+          f_h, NULL);
+      goto done;
+    } else {
+      GstStructure *tmp;
+      gint set_h, set_w, set_par_n, set_par_d, tmp2;
+
+      /* width, height and PAR are not fixed but passthrough is not possible */
+
+      /* First try to keep the height and width as good as possible
+       * and scale PAR */
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "height", from_h);
+      gst_structure_get_int (tmp, "height", &set_h);
+      gst_structure_fixate_field_nearest_int (tmp, "width", from_w);
+      gst_structure_get_int (tmp, "width", &set_w);
+
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_h, set_w,
+              &to_par_n, &to_par_d)) {
+        gst_structure_free (tmp);
+        goto overflow_error;
+      }
+
+      if (!gst_structure_has_field (tmp, "pixel-aspect-ratio"))
+        gst_structure_set_value (tmp, "pixel-aspect-ratio", to_par);
+      gst_structure_fixate_field_nearest_fraction (tmp, "pixel-aspect-ratio",
+          to_par_n, to_par_d);
+      gst_structure_get_fraction (tmp, "pixel-aspect-ratio", &set_par_n,
+          &set_par_d);
+      gst_structure_free (tmp);
+
+      if (set_par_n == to_par_n && set_par_d == to_par_d) {
+        gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+            G_TYPE_INT, set_h, NULL);
+
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+              set_par_n, set_par_d, NULL);
+        goto done;
+      }
+
+      /* Otherwise try to scale width to keep the DAR with the set
+       * PAR and height */
+      if (!gst_util_fraction_multiply (from_dar_n, from_dar_d, set_par_d,
+              set_par_n, &num, &den))
+        goto overflow_error;
+
+      w = (guint) gst_util_uint64_scale_int (set_h, num, den);
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "width", w);
+      gst_structure_get_int (tmp, "width", &tmp2);
+      gst_structure_free (tmp);
+
+      if (tmp2 == w) {
+        gst_structure_set (outs, "width", G_TYPE_INT, tmp2, "height",
+            G_TYPE_INT, set_h, NULL);
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+              set_par_n, set_par_d, NULL);
+        goto done;
+      }
+
+      /* ... or try the same with the height */
+      h = (guint) gst_util_uint64_scale_int (set_w, den, num);
+      tmp = gst_structure_copy (outs);
+      gst_structure_fixate_field_nearest_int (tmp, "height", h);
+      gst_structure_get_int (tmp, "height", &tmp2);
+      gst_structure_free (tmp);
+
+      if (tmp2 == h) {
+        gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+            G_TYPE_INT, tmp2, NULL);
+        if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+            set_par_n != set_par_d)
+          gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+              set_par_n, set_par_d, NULL);
+        goto done;
+      }
+
+      /* If all fails we can't keep the DAR and take the nearest values
+       * for everything from the first try */
+      gst_structure_set (outs, "width", G_TYPE_INT, set_w, "height",
+          G_TYPE_INT, set_h, NULL);
+      if (gst_structure_has_field (outs, "pixel-aspect-ratio") ||
+          set_par_n != set_par_d)
+        gst_structure_set (outs, "pixel-aspect-ratio", GST_TYPE_FRACTION,
+            set_par_n, set_par_d, NULL);
+    }
+  }
+
+done:
+  if (to_par == &tpar)
+    g_value_unset (&tpar);
+
+  return ret;
+
+  /* ERRORS */
+overflow_error:
+  {
+    ret = FALSE;
+    GST_ELEMENT_ERROR (postproc, CORE, NEGOTIATION, (NULL),
+        ("Error calculating the output scaled size - integer overflow"));
+    goto done;
+  }
+}
+
+static gboolean
+_fixate_frame_rate (GstVaapiPostproc * postproc, GstVideoInfo * vinfo,
+    GstStructure * outs)
+{
+  gint fps_n, fps_d;
+
+  fps_n = GST_VIDEO_INFO_FPS_N (vinfo);
+  fps_d = GST_VIDEO_INFO_FPS_D (vinfo);
+  if (is_deinterlace_enabled (postproc, vinfo)) {
+    if (!gst_util_fraction_multiply (fps_n, fps_d, 2, 1, &fps_n, &fps_d))
+      goto overflow_error;
+  }
+  gst_structure_set (outs, "framerate", GST_TYPE_FRACTION, fps_n, fps_d, NULL);
+  return TRUE;
+
+  /* ERRORS */
+overflow_error:
+  {
+    GST_ELEMENT_ERROR (postproc, CORE, NEGOTIATION, (NULL),
+        ("Error calculating the output framerate - integer overflow"));
+    return FALSE;
+  }
+}
+
+static gboolean
+_set_multiview_mode (GstVaapiPostproc * postproc, GstVideoInfo * vinfo,
+    GstStructure * outs)
+{
+  const gchar *caps_str;
+
+  caps_str =
+      gst_video_multiview_mode_to_caps_string (GST_VIDEO_INFO_MULTIVIEW_MODE
+      (vinfo));
+  if (!caps_str)
+    return TRUE;
+
+  gst_structure_set (outs, "multiview-mode", G_TYPE_STRING, caps_str,
+      "multiview-flags", GST_TYPE_VIDEO_MULTIVIEW_FLAGSET,
+      GST_VIDEO_INFO_MULTIVIEW_FLAGS (vinfo), GST_FLAG_SET_MASK_EXACT, NULL);
+
+  if (GST_VIDEO_INFO_VIEWS (vinfo) > 1) {
+    gst_structure_set (outs, "views", G_TYPE_INT, GST_VIDEO_INFO_VIEWS (vinfo),
+        NULL);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+_set_colorimetry (GstVaapiPostproc * postproc, GstVideoInfo * sinkinfo,
+    GstVideoFormat format, GstStructure * outs)
+{
+  GstVideoInfo vinfo;
+  GstVideoColorimetry colorimetry;
+  gchar *color;
+  gint width, height;
+
+  if (!gst_structure_get_int (outs, "width", &width)
+      || !gst_structure_get_int (outs, "height", &height))
+    return FALSE;
+
+  /* Use the sink resolution and the src format to correctly determine the
+   * default src colorimetry. */
+  gst_video_info_set_format (&vinfo, format, GST_VIDEO_INFO_WIDTH (sinkinfo),
+      GST_VIDEO_INFO_HEIGHT (sinkinfo));
+
+  if (GST_VIDEO_INFO_CHROMA_SITE (&vinfo) != GST_VIDEO_CHROMA_SITE_UNKNOWN) {
+    gst_structure_set (outs, "chroma-site", G_TYPE_STRING,
+        gst_video_chroma_to_string (GST_VIDEO_INFO_CHROMA_SITE (&vinfo)), NULL);
+  }
+
+  /* if outs structure already specifies colorimetry, use it */
+  if (gst_structure_has_field (outs, "colorimetry"))
+    return TRUE;
+
+  /* make sure we set the RGB matrix for RGB formats */
+  colorimetry = GST_VIDEO_INFO_COLORIMETRY (&vinfo);
+  if (GST_VIDEO_FORMAT_INFO_IS_RGB (vinfo.finfo) &&
+      colorimetry.matrix != GST_VIDEO_COLOR_MATRIX_RGB) {
+    GST_WARNING ("invalid matrix %d for RGB format, using RGB",
+        colorimetry.matrix);
+    colorimetry.matrix = GST_VIDEO_COLOR_MATRIX_RGB;
+  }
+
+  if ((color = gst_video_colorimetry_to_string (&colorimetry))) {
+    gst_structure_set (outs, "colorimetry", G_TYPE_STRING, color, NULL);
+    g_free (color);
+  }
+
+  return TRUE;
+}
+
+static gboolean
+_set_interlace_mode (GstVaapiPostproc * postproc, GstVideoInfo * vinfo,
+    GstStructure * outs)
+{
+  const gchar *interlace_mode = NULL;
+
+  if (is_deinterlace_enabled (postproc, vinfo)) {
+    interlace_mode = "progressive";
+  } else {
+    interlace_mode =
+        gst_video_interlace_mode_to_string (GST_VIDEO_INFO_INTERLACE_MODE
+        (vinfo));
+  }
+
+  if (!interlace_mode)
+    return FALSE;
+
+  gst_structure_set (outs, "interlace-mode", G_TYPE_STRING, interlace_mode,
+      NULL);
+  return TRUE;
+}
+
+static gboolean
+_set_preferred_format (GstStructure * outs, GstVideoFormat format)
+{
+  GValue value = G_VALUE_INIT;
+
+  if (format == GST_VIDEO_FORMAT_UNKNOWN || format == GST_VIDEO_FORMAT_ENCODED)
+    return FALSE;
+
+  if (!gst_vaapi_value_set_format (&value, format))
+    return FALSE;
+  gst_structure_set_value (outs, "format", &value);
+  g_value_unset (&value);
+  return TRUE;
+}
+
+static GstCaps *
+_get_preferred_caps (GstVaapiPostproc * postproc, GstVideoInfo * vinfo,
+    GstCaps * srccaps)
+{
+  GstPad *srcpad;
+  GstVideoFormat format;
+  GstVaapiCapsFeature f;
+  const gchar *feature;
+  GstStructure *structure;
+  GstCapsFeatures *features;
+  GstCaps *outcaps;
+  gint i, n;
+
+  format = GST_VIDEO_FORMAT_UNKNOWN;
+  srcpad = GST_BASE_TRANSFORM_SRC_PAD (postproc);
+  f = gst_vaapi_find_preferred_caps_feature (srcpad, srccaps, &format);
+  if (f == GST_VAAPI_CAPS_FEATURE_NOT_NEGOTIATED)
+    return NULL;
+
+  feature = gst_vaapi_caps_feature_to_string (f);
+  if (!feature)
+    feature = GST_CAPS_FEATURE_MEMORY_SYSTEM_MEMORY;
+
+  n = gst_caps_get_size (srccaps);
+  for (i = 0; i < n; i++) {
+    structure = gst_caps_get_structure (srccaps, i);
+    features = gst_caps_get_features (srccaps, i);
+
+    if (!gst_caps_features_is_any (features)
+        && gst_caps_features_contains (features, feature))
+      break;
+  }
+
+  if (i >= n)
+    goto invalid_caps;
+
+  /* make copy */
+  structure = gst_structure_copy (structure);
+
+  if (!_set_preferred_format (structure, format))
+    goto fixate_failed;
+  if (!_fixate_frame_size (postproc, vinfo, structure))
+    goto fixate_failed;
+  if (!_fixate_frame_rate (postproc, vinfo, structure))
+    goto fixate_failed;
+  _set_multiview_mode (postproc, vinfo, structure);
+
+  if (!_set_colorimetry (postproc, vinfo, format, structure))
+    goto fixate_failed;
+
+  if (!_set_interlace_mode (postproc, vinfo, structure))
+    goto interlace_mode_failed;
+
+  outcaps = gst_caps_new_empty ();
+  gst_caps_append_structure_full (outcaps, structure,
+      gst_caps_features_copy (features));
+
+  /* we don't need to do format conversion if GL_TEXTURE_UPLOAD_META
+   * is negotiated */
+  if (f == GST_VAAPI_CAPS_FEATURE_GL_TEXTURE_UPLOAD_META) {
+    postproc->format = DEFAULT_FORMAT;
+  } else if (postproc->format != format) {
+    postproc->format = format;
+  }
+
+  return gst_caps_fixate (outcaps);
+
+  /* ERRORS */
+fixate_failed:
+  {
+    GST_WARNING_OBJECT (postproc, "Could not fixate src caps");
+    gst_structure_free (structure);
+    return NULL;
+  }
+invalid_caps:
+  {
+    GST_WARNING_OBJECT (postproc, "No valid src caps found");
+    return NULL;
+  }
+interlace_mode_failed:
+  {
+    GST_WARNING_OBJECT (postproc, "Invalid sink caps interlace mode");
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapipostproc_fixate_srccaps:
+ * @postproc: a #GstVaapiPostproc instance
+ * @sinkcaps: fixed #GstCaps from sink pad
+ * @srccaps: #GstCaps from src pad to fixate
+ *
+ * Given @srccaps and @sinkcaps returns a new allocated #GstCaps with
+ * the fixated caps for the src pad.
+ *
+ * Returns: A new allocated #GstCaps
+ **/
+GstCaps *
+gst_vaapipostproc_fixate_srccaps (GstVaapiPostproc * postproc,
+    GstCaps * sinkcaps, GstCaps * srccaps)
+{
+  GstVideoInfo vi;
+
+  if (!gst_video_info_from_caps (&vi, sinkcaps))
+    return NULL;
+  return _get_preferred_caps (postproc, &vi, srccaps);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostprocutil.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapipostprocutil.h
new file mode 100644 (file)
index 0000000..db5d303
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ *  gstvaapipostprocutil.h - VA-API video post processing utilities
+ *
+ *  Copyright (C) 2016 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *    Author: Victor Jaquez <victorx.jaquez@intel.com>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this program; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPIPOSTPROCUTIL_H
+#define GST_VAAPIPOSTPROCUTIL_H
+
+#include "gstvaapipostproc.h"
+
+G_BEGIN_DECLS
+
+#define DEFAULT_FORMAT                  GST_VIDEO_FORMAT_ENCODED
+#define DEFAULT_DEINTERLACE_MODE        GST_VAAPI_DEINTERLACE_MODE_AUTO
+#define DEFAULT_DEINTERLACE_METHOD      GST_VAAPI_DEINTERLACE_METHOD_BOB
+
+GstCaps *gst_vaapipostproc_transform_srccaps (GstVaapiPostproc * postproc);
+
+GstCaps *gst_vaapipostproc_fixate_srccaps (GstVaapiPostproc * postproc,
+    GstCaps * sinkcaps, GstCaps * srccaps);
+
+gboolean is_deinterlace_enabled (GstVaapiPostproc * postproc,
+    GstVideoInfo * vip);
+
+G_END_DECLS
+
+#endif /* GST_VAAPIPOSTPROCUTIL_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapisink.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapisink.c
new file mode 100644 (file)
index 0000000..b318f70
--- /dev/null
@@ -0,0 +1,1986 @@
+/*
+ *  gstvaapisink.c - VA-API video sink
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:element-vaapisink
+ * @short_description: A VA-API based video sink
+ *
+ * vaapisink renders video frames to a drawable (X Window) on a local
+ * display using the Video Acceleration (VA) API. The element will
+ * create its own internal window and render into it.
+ *
+ * ## Example launch line
+ *
+ * |[
+ * gst-launch-1.0 videotestsrc ! vaapisink
+ * ]|
+ */
+
+#include "gstcompat.h"
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <gst/vaapi/gstvaapivalue.h>
+
+/* Supported interfaces */
+# include <gst/video/videooverlay.h>
+# include <gst/video/colorbalance.h>
+# include <gst/video/navigation.h>
+
+#include "gstvaapisink.h"
+#include "gstvaapipluginutil.h"
+#include "gstvaapivideometa.h"
+#include "gstvaapivideobufferpool.h"
+#include "gstvaapivideomemory.h"
+
+#define GST_PLUGIN_NAME "vaapisink"
+#define GST_PLUGIN_DESC "A VA-API based videosink"
+
+GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapisink);
+#ifndef GST_DISABLE_GST_DEBUG
+#define GST_CAT_DEFAULT gst_debug_vaapisink
+#else
+#define GST_CAT_DEFAULT NULL
+#endif
+
+/* Default template */
+/* *INDENT-OFF* */
+static const char gst_vaapisink_sink_caps_str[] =
+    GST_VAAPI_MAKE_SURFACE_CAPS ";"
+    GST_VIDEO_CAPS_MAKE_WITH_FEATURES (
+        GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE ","
+            GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION,
+        "{ ENCODED, NV12, I420, YV12, P010_10LE }") ";"
+    GST_VIDEO_CAPS_MAKE_WITH_FEATURES (
+        GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION,
+        GST_VIDEO_FORMATS_ALL) ";"
+    GST_VIDEO_CAPS_MAKE (GST_VIDEO_FORMATS_ALL);
+/* *INDENT-ON* */
+
+static GstStaticPadTemplate gst_vaapisink_sink_factory =
+GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    GST_STATIC_CAPS (gst_vaapisink_sink_caps_str));
+
+static gboolean
+gst_vaapisink_has_interface (GstVaapiPluginBase * plugin, GType type)
+{
+  return type == GST_TYPE_VIDEO_OVERLAY || type == GST_TYPE_COLOR_BALANCE;
+}
+
+static void
+gst_vaapisink_video_overlay_iface_init (GstVideoOverlayInterface * iface);
+
+static void
+gst_vaapisink_color_balance_iface_init (GstColorBalanceInterface * iface);
+
+static void
+gst_vaapisink_navigation_iface_init (GstNavigationInterface * iface);
+
+G_DEFINE_TYPE_WITH_CODE (GstVaapiSink,
+    gst_vaapisink,
+    GST_TYPE_VIDEO_SINK,
+    GST_VAAPI_PLUGIN_BASE_INIT_INTERFACES
+    G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
+        gst_vaapisink_video_overlay_iface_init);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_COLOR_BALANCE,
+        gst_vaapisink_color_balance_iface_init);
+    G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
+        gst_vaapisink_navigation_iface_init));
+
+GST_VAAPI_PLUGIN_BASE_DEFINE_SET_CONTEXT (gst_vaapisink_parent_class);
+
+enum
+{
+  HANDOFF_SIGNAL,
+  LAST_SIGNAL
+};
+
+static guint gst_vaapisink_signals[LAST_SIGNAL] = { 0 };
+
+enum
+{
+  PROP_0,
+
+  PROP_DISPLAY_TYPE,
+  PROP_DISPLAY_NAME,
+  PROP_FULLSCREEN,
+  PROP_ROTATION,
+  PROP_FORCE_ASPECT_RATIO,
+  PROP_VIEW_ID,
+  PROP_HUE,
+  PROP_SATURATION,
+  PROP_BRIGHTNESS,
+  PROP_CONTRAST,
+  PROP_SIGNAL_HANDOFFS,
+
+  N_PROPERTIES
+};
+
+#define DEFAULT_DISPLAY_TYPE            GST_VAAPI_DISPLAY_TYPE_ANY
+#define DEFAULT_ROTATION                GST_VAAPI_ROTATION_0
+#define DEFAULT_SIGNAL_HANDOFFS         FALSE
+
+static GParamSpec *g_properties[N_PROPERTIES] = { NULL, };
+
+static void gst_vaapisink_video_overlay_expose (GstVideoOverlay * overlay);
+
+static gboolean gst_vaapisink_reconfigure_window (GstVaapiSink * sink);
+
+static void
+gst_vaapisink_set_event_handling (GstVaapiSink * sink, gboolean handle_events);
+
+static GstFlowReturn
+gst_vaapisink_show_frame (GstVideoSink * video_sink, GstBuffer * buffer);
+
+static gboolean
+gst_vaapisink_ensure_render_rect (GstVaapiSink * sink, guint width,
+    guint height);
+
+static inline gboolean
+gst_vaapisink_ensure_display (GstVaapiSink * sink)
+{
+  return gst_vaapi_plugin_base_ensure_display (GST_VAAPI_PLUGIN_BASE (sink));
+}
+
+static inline gboolean
+gst_vaapisink_render_surface (GstVaapiSink * sink, GstVaapiSurface * surface,
+    const GstVaapiRectangle * surface_rect, guint flags)
+{
+  return sink->window && gst_vaapi_window_put_surface (sink->window, surface,
+      surface_rect, &sink->display_rect, flags);
+}
+
+/* ------------------------------------------------------------------------ */
+/* --- DRM Backend                                                      --- */
+/* ------------------------------------------------------------------------ */
+
+#if GST_VAAPI_USE_DRM
+#include <gst/vaapi/gstvaapidisplay_drm.h>
+
+static gboolean
+gst_vaapisink_drm_create_window (GstVaapiSink * sink, guint width, guint height)
+{
+  g_return_val_if_fail (sink->window == NULL, FALSE);
+
+  GST_ERROR ("failed to create a window for VA/DRM display");
+  return FALSE;
+}
+
+static gboolean
+gst_vaapisink_drm_render_surface (GstVaapiSink * sink,
+    GstVaapiSurface * surface, const GstVaapiRectangle * surface_rect,
+    guint flags)
+{
+  return TRUE;
+}
+
+static const inline GstVaapiSinkBackend *
+gst_vaapisink_backend_drm (void)
+{
+  static const GstVaapiSinkBackend GstVaapiSinkBackendDRM = {
+    .create_window = gst_vaapisink_drm_create_window,
+    .render_surface = gst_vaapisink_drm_render_surface,
+  };
+  return &GstVaapiSinkBackendDRM;
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+/* --- X11 Backend                                                      --- */
+/* ------------------------------------------------------------------------ */
+
+#if GST_VAAPI_USE_X11
+#include <gst/vaapi/gstvaapidisplay_x11.h>
+#include <gst/vaapi/gstvaapiwindow_x11.h>
+
+#if HAVE_XKBLIB
+# include <X11/XKBlib.h>
+#endif
+
+static inline KeySym
+x11_keycode_to_keysym (Display * dpy, unsigned int kc)
+{
+#if HAVE_XKBLIB
+  return XkbKeycodeToKeysym (dpy, kc, 0, 0);
+#else
+  return XKeycodeToKeysym (dpy, kc, 0);
+#endif
+}
+
+/* Checks whether a ConfigureNotify event is in the queue */
+typedef struct _ConfigureNotifyEventPendingArgs ConfigureNotifyEventPendingArgs;
+struct _ConfigureNotifyEventPendingArgs
+{
+  Window window;
+  guint width;
+  guint height;
+  gboolean match;
+};
+
+static Bool
+configure_notify_event_pending_cb (Display * dpy, XEvent * xev, XPointer arg)
+{
+  ConfigureNotifyEventPendingArgs *const args =
+      (ConfigureNotifyEventPendingArgs *) arg;
+
+  if (xev->type == ConfigureNotify &&
+      xev->xconfigure.window == args->window &&
+      xev->xconfigure.width == args->width &&
+      xev->xconfigure.height == args->height)
+    args->match = TRUE;
+
+  /* XXX: this is a hack to traverse the whole queue because we
+     can't use XPeekIfEvent() since it could block */
+  return False;
+}
+
+static gboolean
+configure_notify_event_pending (GstVaapiSink * sink, Window window,
+    guint width, guint height)
+{
+  GstVaapiDisplayX11 *const display =
+      GST_VAAPI_DISPLAY_X11 (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink));
+  ConfigureNotifyEventPendingArgs args;
+  XEvent xev;
+
+  args.window = window;
+  args.width = width;
+  args.height = height;
+  args.match = FALSE;
+
+  /* XXX: don't use XPeekIfEvent() because it might block */
+  XCheckIfEvent (gst_vaapi_display_x11_get_display (display),
+      &xev, configure_notify_event_pending_cb, (XPointer) & args);
+  return args.match;
+}
+
+static gboolean
+gst_vaapisink_x11_create_window (GstVaapiSink * sink, guint width, guint height)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
+
+  g_return_val_if_fail (sink->window == NULL, FALSE);
+
+  sink->window = gst_vaapi_window_x11_new (display, width, height);
+  if (!sink->window)
+    return FALSE;
+
+  gst_video_overlay_got_window_handle (GST_VIDEO_OVERLAY (sink),
+      gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window)));
+  return TRUE;
+}
+
+static gboolean
+gst_vaapisink_x11_create_window_from_handle (GstVaapiSink * sink,
+    guintptr window)
+{
+  GstVaapiDisplay *display;
+  Window rootwin;
+  unsigned int width, height, border_width, depth;
+  int x, y;
+  XID xid = window;
+
+  if (!gst_vaapisink_ensure_display (sink))
+    return FALSE;
+  display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
+
+  gst_vaapi_display_lock (display);
+  XGetGeometry (gst_vaapi_display_x11_get_display (GST_VAAPI_DISPLAY_X11
+          (display)), xid, &rootwin, &x, &y, &width, &height, &border_width,
+      &depth);
+  gst_vaapi_display_unlock (display);
+
+  if ((width != sink->window_width || height != sink->window_height) &&
+      !configure_notify_event_pending (sink, xid, width, height)) {
+    if (!gst_vaapisink_ensure_render_rect (sink, width, height))
+      return FALSE;
+    sink->window_width = width;
+    sink->window_height = height;
+  }
+
+  if (!sink->window
+      || gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window)) !=
+      xid) {
+    gst_vaapi_window_replace (&sink->window, NULL);
+    sink->window = gst_vaapi_window_x11_new_with_xid (display, xid);
+    if (!sink->window)
+      return FALSE;
+  }
+
+  gst_vaapisink_set_event_handling (sink, sink->handle_events);
+  return TRUE;
+}
+
+static gboolean
+gst_vaapisink_x11_handle_events (GstVaapiSink * sink)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
+  gboolean has_events, do_expose = FALSE;
+  guint pointer_x = 0, pointer_y = 0;
+  gboolean pointer_moved = FALSE;
+  XEvent e;
+
+  if (sink->window) {
+    Display *const x11_dpy =
+        gst_vaapi_display_x11_get_display (GST_VAAPI_DISPLAY_X11 (display));
+    Window x11_win =
+        gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window));
+
+    /* Track MousePointer interaction */
+    for (;;) {
+      gst_vaapi_display_lock (display);
+      has_events = XCheckWindowEvent (x11_dpy, x11_win, PointerMotionMask, &e);
+      gst_vaapi_display_unlock (display);
+      if (!has_events)
+        break;
+
+      switch (e.type) {
+        case MotionNotify:
+          pointer_x = e.xmotion.x;
+          pointer_y = e.xmotion.y;
+          pointer_moved = TRUE;
+          break;
+        default:
+          break;
+      }
+    }
+    if (pointer_moved) {
+      gst_vaapi_display_lock (display);
+      gst_navigation_send_mouse_event (GST_NAVIGATION (sink),
+          "mouse-move", 0, pointer_x, pointer_y);
+      gst_vaapi_display_unlock (display);
+    }
+
+    /* Track KeyPress, KeyRelease, ButtonPress, ButtonRelease */
+    for (;;) {
+      KeySym keysym;
+      const char *key_str = NULL;
+      gst_vaapi_display_lock (display);
+      has_events = XCheckWindowEvent (x11_dpy, x11_win,
+          KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask,
+          &e);
+      gst_vaapi_display_unlock (display);
+      if (!has_events)
+        break;
+
+      switch (e.type) {
+        case ButtonPress:
+          gst_navigation_send_mouse_event (GST_NAVIGATION (sink),
+              "mouse-button-press", e.xbutton.button, e.xbutton.x, e.xbutton.y);
+          break;
+        case ButtonRelease:
+          gst_navigation_send_mouse_event (GST_NAVIGATION (sink),
+              "mouse-button-release", e.xbutton.button, e.xbutton.x,
+              e.xbutton.y);
+          break;
+        case KeyPress:
+        case KeyRelease:
+          gst_vaapi_display_lock (display);
+          keysym = x11_keycode_to_keysym (x11_dpy, e.xkey.keycode);
+          if (keysym != NoSymbol) {
+            key_str = XKeysymToString (keysym);
+          } else {
+            key_str = "unknown";
+          }
+          gst_vaapi_display_unlock (display);
+          gst_navigation_send_key_event (GST_NAVIGATION (sink),
+              e.type == KeyPress ? "key-press" : "key-release", key_str);
+          break;
+        default:
+          break;
+      }
+    }
+
+    /* Handle Expose + ConfigureNotify */
+    /* Need to lock whole loop or we corrupt the XEvent queue: */
+    for (;;) {
+      gst_vaapi_display_lock (display);
+      has_events = XCheckWindowEvent (x11_dpy, x11_win,
+          StructureNotifyMask | ExposureMask, &e);
+      gst_vaapi_display_unlock (display);
+      if (!has_events)
+        break;
+
+      switch (e.type) {
+        case Expose:
+          do_expose = TRUE;
+          break;
+        case ConfigureNotify:
+          if (gst_vaapisink_reconfigure_window (sink))
+            do_expose = TRUE;
+          break;
+        default:
+          break;
+      }
+    }
+    if (do_expose)
+      gst_vaapisink_video_overlay_expose (GST_VIDEO_OVERLAY (sink));
+
+    /* Handle Display events */
+    for (;;) {
+      gst_vaapi_display_lock (display);
+      if (XPending (x11_dpy) == 0) {
+        gst_vaapi_display_unlock (display);
+        break;
+      }
+      XNextEvent (x11_dpy, &e);
+      gst_vaapi_display_unlock (display);
+
+      switch (e.type) {
+        case ClientMessage:{
+          Atom wm_delete;
+
+          wm_delete = XInternAtom (x11_dpy, "WM_DELETE_WINDOW", False);
+          if (wm_delete == (Atom) e.xclient.data.l[0]) {
+            /* Handle window deletion by posting an error on the bus */
+            GST_ELEMENT_ERROR (sink, RESOURCE, NOT_FOUND,
+                ("Output window was closed"), (NULL));
+            return FALSE;
+          }
+          break;
+        }
+        default:
+          break;
+      }
+    }
+
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_vaapisink_x11_pre_start_event_thread (GstVaapiSink * sink)
+{
+  GstVaapiDisplayX11 *const display =
+      GST_VAAPI_DISPLAY_X11 (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink));
+  int x11_event_mask = (KeyPressMask | KeyReleaseMask |
+      PointerMotionMask | ExposureMask | StructureNotifyMask);
+
+  if (!sink->foreign_window)
+    x11_event_mask |= ButtonPressMask | ButtonReleaseMask;
+
+  if (sink->window) {
+    gst_vaapi_display_lock (GST_VAAPI_DISPLAY (display));
+    XSelectInput (gst_vaapi_display_x11_get_display (display),
+        gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window)),
+        x11_event_mask);
+    gst_vaapi_display_unlock (GST_VAAPI_DISPLAY (display));
+  }
+  return TRUE;
+}
+
+static gboolean
+gst_vaapisink_x11_pre_stop_event_thread (GstVaapiSink * sink)
+{
+  GstVaapiDisplayX11 *const display =
+      GST_VAAPI_DISPLAY_X11 (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink));
+
+  if (sink->window) {
+    gst_vaapi_display_lock (GST_VAAPI_DISPLAY (display));
+    XSelectInput (gst_vaapi_display_x11_get_display (display),
+        gst_vaapi_window_x11_get_xid (GST_VAAPI_WINDOW_X11 (sink->window)), 0);
+    gst_vaapi_display_unlock (GST_VAAPI_DISPLAY (display));
+  }
+  return TRUE;
+}
+
+static const inline GstVaapiSinkBackend *
+gst_vaapisink_backend_x11 (void)
+{
+  static const GstVaapiSinkBackend GstVaapiSinkBackendX11 = {
+    .create_window = gst_vaapisink_x11_create_window,
+    .create_window_from_handle = gst_vaapisink_x11_create_window_from_handle,
+    .render_surface = gst_vaapisink_render_surface,
+
+    .event_thread_needed = TRUE,
+    .handle_events = gst_vaapisink_x11_handle_events,
+    .pre_start_event_thread = gst_vaapisink_x11_pre_start_event_thread,
+    .pre_stop_event_thread = gst_vaapisink_x11_pre_stop_event_thread,
+  };
+  return &GstVaapiSinkBackendX11;
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+/* --- Wayland Backend                                                  --- */
+/* ------------------------------------------------------------------------ */
+
+#if GST_VAAPI_USE_WAYLAND
+#include <gst/vaapi/gstvaapidisplay_wayland.h>
+#include <gst/vaapi/gstvaapiwindow_wayland.h>
+
+static void
+on_window_wayland_size_changed (GstVaapiWindowWayland * window, gint width,
+    gint height, gpointer user_data)
+{
+  GstVaapiSink *sink = GST_VAAPISINK (user_data);
+
+  GST_DEBUG ("Wayland window size changed to: %dx%d", width, height);
+  gst_vaapisink_reconfigure_window (sink);
+  gst_vaapisink_show_frame (GST_VIDEO_SINK_CAST (sink), NULL);
+}
+
+static gboolean
+gst_vaapisink_wayland_create_window (GstVaapiSink * sink, guint width,
+    guint height)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
+
+  g_return_val_if_fail (sink->window == NULL, FALSE);
+
+  sink->window = gst_vaapi_window_wayland_new (display, width, height);
+  if (!sink->window)
+    return FALSE;
+
+  g_signal_connect_object (sink->window, "size-changed",
+      G_CALLBACK (on_window_wayland_size_changed), sink, 0);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapisink_wayland_create_window_from_handle (GstVaapiSink * sink,
+    guintptr window)
+{
+  GstVaapiDisplay *display;
+
+  if (!gst_vaapisink_ensure_display (sink))
+    return FALSE;
+  display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
+
+  if (sink->window == NULL || (guintptr) sink->window != window) {
+    gst_vaapi_window_replace (&sink->window, NULL);
+    sink->window = gst_vaapi_window_wayland_new_with_surface (display, window);
+  }
+
+  return sink->window != NULL;
+}
+
+static const inline GstVaapiSinkBackend *
+gst_vaapisink_backend_wayland (void)
+{
+  static const GstVaapiSinkBackend GstVaapiSinkBackendWayland = {
+    .create_window = gst_vaapisink_wayland_create_window,
+    .create_window_from_handle =
+        gst_vaapisink_wayland_create_window_from_handle,
+    .render_surface = gst_vaapisink_render_surface,
+  };
+  return &GstVaapiSinkBackendWayland;
+}
+#endif
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVideoOverlay interface                                        --- */
+/* ------------------------------------------------------------------------ */
+
+static void
+gst_vaapisink_video_overlay_set_window_handle (GstVideoOverlay * overlay,
+    guintptr window)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK (overlay);
+  GstVaapiDisplayType display_type;
+
+  if (!gst_vaapisink_ensure_display (sink))
+    return;
+
+  display_type = GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE (sink);
+
+  /* Disable GLX rendering when vaapisink is using a foreign X
+     window. It's pretty much useless */
+  if (display_type == GST_VAAPI_DISPLAY_TYPE_GLX) {
+    display_type = GST_VAAPI_DISPLAY_TYPE_X11;
+    gst_vaapi_plugin_base_set_display_type (GST_VAAPI_PLUGIN_BASE (sink),
+        display_type);
+  }
+
+  sink->foreign_window = TRUE;
+  if (sink->backend->create_window_from_handle)
+    sink->backend->create_window_from_handle (sink, window);
+}
+
+static void
+gst_vaapisink_video_overlay_set_render_rectangle (GstVideoOverlay * overlay,
+    gint x, gint y, gint width, gint height)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK (overlay);
+  GstVaapiRectangle *const display_rect = &sink->display_rect;
+
+  display_rect->x = x;
+  display_rect->y = y;
+  display_rect->width = width;
+  display_rect->height = height;
+
+  if (gst_vaapisink_ensure_render_rect (sink, width, height) && sink->window) {
+    gst_vaapi_window_set_render_rectangle (sink->window, x, y, width, height);
+    gst_vaapi_window_set_size (sink->window, width, height);
+    gst_vaapisink_reconfigure_window (sink);
+  }
+
+  GST_DEBUG ("render rect (%d,%d):%ux%u",
+      display_rect->x, display_rect->y,
+      display_rect->width, display_rect->height);
+}
+
+static void
+gst_vaapisink_video_overlay_expose (GstVideoOverlay * overlay)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK (overlay);
+
+  gst_vaapisink_reconfigure_window (sink);
+  gst_vaapisink_show_frame (GST_VIDEO_SINK_CAST (sink), NULL);
+}
+
+static void
+gst_vaapisink_video_overlay_set_event_handling (GstVideoOverlay * overlay,
+    gboolean handle_events)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK (overlay);
+
+  sink->handle_events = handle_events;
+  gst_vaapisink_set_event_handling (sink, handle_events);
+}
+
+static void
+gst_vaapisink_video_overlay_iface_init (GstVideoOverlayInterface * iface)
+{
+  iface->set_window_handle = gst_vaapisink_video_overlay_set_window_handle;
+  iface->set_render_rectangle =
+      gst_vaapisink_video_overlay_set_render_rectangle;
+  iface->expose = gst_vaapisink_video_overlay_expose;
+  iface->handle_events = gst_vaapisink_video_overlay_set_event_handling;
+}
+
+/* ------------------------------------------------------------------------ */
+/* --- GstColorBalance interface                                        --- */
+/* ------------------------------------------------------------------------ */
+
+enum
+{
+  CB_HUE = 1,
+  CB_SATURATION,
+  CB_BRIGHTNESS,
+  CB_CONTRAST
+};
+
+typedef struct
+{
+  guint cb_id;
+  const gchar *prop_name;
+  const gchar *channel_name;
+} ColorBalanceMap;
+
+static const ColorBalanceMap cb_map[4] = {
+  {CB_HUE, GST_VAAPI_DISPLAY_PROP_HUE, "VA_HUE"},
+  {CB_SATURATION, GST_VAAPI_DISPLAY_PROP_SATURATION, "VA_SATURATION"},
+  {CB_BRIGHTNESS, GST_VAAPI_DISPLAY_PROP_BRIGHTNESS, "VA_BRIGHTNESS"},
+  {CB_CONTRAST, GST_VAAPI_DISPLAY_PROP_CONTRAST, "VA_CONTRAST"}
+};
+
+static guint
+cb_get_id_from_channel_name (GstVaapiSink * sink, const gchar * name)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++) {
+    if (g_ascii_strcasecmp (cb_map[i].channel_name, name) == 0)
+      return cb_map[i].cb_id;
+  }
+
+  GST_WARNING ("got an unknown channel %s", name);
+  return 0;
+}
+
+static inline GValue *
+cb_get_gvalue (GstVaapiSink * sink, guint id)
+{
+  g_return_val_if_fail ((guint) (id - CB_HUE) < G_N_ELEMENTS (sink->cb_values),
+      NULL);
+
+  return &sink->cb_values[id - CB_HUE];
+}
+
+static gboolean
+cb_set_value (GstVaapiSink * sink, guint id, gfloat value)
+{
+  GValue *const v_value = cb_get_gvalue (sink, id);
+
+  if (!v_value)
+    return FALSE;
+
+  g_value_set_float (v_value, value);
+  sink->cb_changed |= (1U << id);
+  return TRUE;
+}
+
+static inline gfloat
+cb_get_value (GstVaapiSink * sink, guint id)
+{
+  const GValue *const v_value = cb_get_gvalue (sink, id);
+
+  return v_value ? g_value_get_float (v_value) : 0.0;
+}
+
+static gboolean
+cb_sync_values_from_display (GstVaapiSink * sink, GstVaapiDisplay * display)
+{
+  guint i;
+  gfloat value;
+
+  for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++) {
+    const guint cb_id = CB_HUE + i;
+    if (!gst_vaapi_display_has_property (display, cb_map[i].prop_name)) {
+      GST_INFO_OBJECT (sink, "backend does not handle %s", cb_map[i].prop_name);
+      continue;
+    }
+
+    value = 0.0;
+    g_object_get (display, cb_map[i].prop_name, &value, NULL);
+    cb_set_value (sink, cb_id, value);
+  }
+  sink->cb_changed = 0;
+  return TRUE;
+}
+
+static gboolean
+cb_sync_values_to_display (GstVaapiSink * sink, GstVaapiDisplay * display)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++) {
+    const guint cb_id = CB_HUE + i;
+    if (!(sink->cb_changed & (1U << cb_id)))
+      continue;
+    if (!gst_vaapi_display_has_property (display, cb_map[i].prop_name)) {
+      GST_INFO_OBJECT (sink, "backend does not handle %s", cb_map[i].prop_name);
+      continue;
+    }
+
+    g_object_set_property (G_OBJECT (display), cb_map[i].prop_name,
+        cb_get_gvalue (sink, cb_id));
+  }
+  sink->cb_changed = 0;
+  return TRUE;
+}
+
+#define CB_CHANNEL_FACTOR (1000.0)
+
+static void
+cb_channels_init (GstVaapiSink * sink)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
+  GstColorBalanceChannel *channel;
+  GParamSpecFloat *pspec;
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++) {
+    if (!gst_vaapi_display_has_property (display, cb_map[i].prop_name))
+      continue;
+
+    pspec = G_PARAM_SPEC_FLOAT (g_properties[PROP_HUE + i]);
+    if (!pspec)
+      continue;
+
+    channel = g_object_new (GST_TYPE_COLOR_BALANCE_CHANNEL, NULL);
+    channel->label = g_strdup (cb_map[i].channel_name);
+    channel->min_value = pspec->minimum * CB_CHANNEL_FACTOR;
+    channel->max_value = pspec->maximum * CB_CHANNEL_FACTOR;
+
+    sink->cb_channels = g_list_prepend (sink->cb_channels, channel);
+  }
+
+  if (sink->cb_channels)
+    sink->cb_channels = g_list_reverse (sink->cb_channels);
+}
+
+static void
+cb_channels_finalize (GstVaapiSink * sink)
+{
+  if (sink->cb_channels) {
+    g_list_free_full (sink->cb_channels, g_object_unref);
+    sink->cb_channels = NULL;
+  }
+}
+
+static const GList *
+gst_vaapisink_color_balance_list_channels (GstColorBalance * cb)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK (cb);
+
+  if (!gst_vaapisink_ensure_display (sink))
+    return NULL;
+
+  if (!sink->cb_channels)
+    cb_channels_init (sink);
+  return sink->cb_channels;
+}
+
+static void
+gst_vaapisink_color_balance_set_value (GstColorBalance * cb,
+    GstColorBalanceChannel * channel, gint value)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK (cb);
+  guint cb_id;
+
+  g_return_if_fail (channel->label != NULL);
+
+  if (!gst_vaapisink_ensure_display (sink))
+    return;
+
+  cb_id = cb_get_id_from_channel_name (sink, channel->label);
+  if (!cb_id)
+    return;
+
+  cb_set_value (sink, cb_id, value / CB_CHANNEL_FACTOR);
+}
+
+static gint
+gst_vaapisink_color_balance_get_value (GstColorBalance * cb,
+    GstColorBalanceChannel * channel)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK (cb);
+  guint cb_id;
+
+  g_return_val_if_fail (channel->label != NULL, 0);
+
+  if (!gst_vaapisink_ensure_display (sink))
+    return 0;
+
+  cb_id = cb_get_id_from_channel_name (sink, channel->label);
+  if (!cb_id)
+    return 0;
+
+  return cb_get_value (sink, cb_id) * CB_CHANNEL_FACTOR;
+}
+
+static GstColorBalanceType
+gst_vaapisink_color_balance_get_type (GstColorBalance * cb)
+{
+  return GST_COLOR_BALANCE_HARDWARE;
+}
+
+static void
+gst_vaapisink_color_balance_iface_init (GstColorBalanceInterface * iface)
+{
+  iface->list_channels = gst_vaapisink_color_balance_list_channels;
+  iface->set_value = gst_vaapisink_color_balance_set_value;
+  iface->get_value = gst_vaapisink_color_balance_get_value;
+  iface->get_balance_type = gst_vaapisink_color_balance_get_type;
+}
+
+/* ------------------------------------------------------------------------ */
+/* --- GstNavigation interface                                          --- */
+/* ------------------------------------------------------------------------ */
+
+static void
+gst_vaapisink_navigation_send_event (GstNavigation * navigation,
+    GstEvent * event)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK (navigation);
+  GstPad *peer;
+
+  if (!sink->window) {
+    gst_event_unref (event);
+    return;
+  }
+
+  if ((peer = gst_pad_get_peer (GST_VAAPI_PLUGIN_BASE_SINK_PAD (sink)))) {
+    GstVaapiRectangle *disp_rect = &sink->display_rect;
+    gdouble x, y, xscale = 1.0, yscale = 1.0;
+
+    /* We calculate scaling using the original video frames geometry to include
+       pixel aspect ratio scaling. */
+    xscale = (gdouble) sink->video_width / disp_rect->width;
+    yscale = (gdouble) sink->video_height / disp_rect->height;
+
+    event = gst_event_make_writable (event);
+
+    /* Converting pointer coordinates to the non scaled geometry */
+    if (gst_navigation_event_get_coordinates (event, &x, &y)) {
+      x = MIN (x, disp_rect->x + disp_rect->width);
+      x = MAX (x - disp_rect->x, 0);
+      y = MIN (y, disp_rect->y + disp_rect->height);
+      y = MAX (y - disp_rect->y, 0);
+      gst_navigation_event_set_coordinates (event, x * xscale, y * yscale);
+    }
+
+    if (!gst_pad_send_event (peer, gst_event_ref (event))) {
+      /* If upstream didn't handle the event we'll post a message with it
+       * for the application in case it wants to do something with it */
+      gst_element_post_message (GST_ELEMENT_CAST (sink),
+          gst_navigation_message_new_event (GST_OBJECT_CAST (sink), event));
+    }
+    gst_event_unref (event);
+    gst_object_unref (peer);
+  }
+}
+
+static void
+gst_vaapisink_navigation_iface_init (GstNavigationInterface * iface)
+{
+  iface->send_event_simple = gst_vaapisink_navigation_send_event;
+}
+
+/* ------------------------------------------------------------------------ */
+/* --- Common implementation                                            --- */
+/* ------------------------------------------------------------------------ */
+
+static gboolean
+gst_vaapisink_reconfigure_window (GstVaapiSink * sink)
+{
+  guint win_width, win_height;
+
+  gst_vaapi_window_reconfigure (sink->window);
+  gst_vaapi_window_get_size (sink->window, &win_width, &win_height);
+  if (win_width != sink->window_width || win_height != sink->window_height) {
+    if (!gst_vaapisink_ensure_render_rect (sink, win_width, win_height))
+      return FALSE;
+    GST_INFO ("window was resized from %ux%u to %ux%u",
+        sink->window_width, sink->window_height, win_width, win_height);
+    sink->window_width = win_width;
+    sink->window_height = win_height;
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static gpointer
+gst_vaapisink_event_thread (GstVaapiSink * sink)
+{
+  GST_OBJECT_LOCK (sink);
+  while (!g_atomic_int_get (&sink->event_thread_cancel)) {
+    GST_OBJECT_UNLOCK (sink);
+    sink->backend->handle_events (sink);
+    g_usleep (G_USEC_PER_SEC / 20);
+    GST_OBJECT_LOCK (sink);
+  }
+  GST_OBJECT_UNLOCK (sink);
+  return NULL;
+}
+
+static void
+gst_vaapisink_set_event_handling (GstVaapiSink * sink, gboolean handle_events)
+{
+  GThread *thread = NULL;
+
+  if (!sink->backend || !sink->backend->event_thread_needed)
+    return;
+
+  GST_OBJECT_LOCK (sink);
+  if (handle_events && !sink->event_thread) {
+    /* Setup our event listening thread */
+    GST_DEBUG ("starting xevent thread");
+    if (sink->backend->pre_start_event_thread)
+      sink->backend->pre_start_event_thread (sink);
+
+    g_atomic_int_set (&sink->event_thread_cancel, FALSE);
+    sink->event_thread = g_thread_try_new ("vaapisink-events",
+        (GThreadFunc) gst_vaapisink_event_thread, sink, NULL);
+  } else if (!handle_events && sink->event_thread) {
+    GST_DEBUG ("stopping xevent thread");
+    if (sink->backend->pre_stop_event_thread)
+      sink->backend->pre_stop_event_thread (sink);
+
+    /* Grab thread and mark it as NULL */
+    thread = sink->event_thread;
+    sink->event_thread = NULL;
+    g_atomic_int_set (&sink->event_thread_cancel, TRUE);
+  }
+  GST_OBJECT_UNLOCK (sink);
+
+  /* Wait for our event thread to finish */
+  if (thread) {
+    g_thread_join (thread);
+    GST_DEBUG ("xevent thread stopped");
+  }
+}
+
+static void
+gst_vaapisink_ensure_backend (GstVaapiSink * sink)
+{
+  switch (GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE (sink)) {
+#if GST_VAAPI_USE_DRM
+    case GST_VAAPI_DISPLAY_TYPE_DRM:
+      sink->backend = gst_vaapisink_backend_drm ();
+      break;
+#endif
+#if GST_VAAPI_USE_X11
+    case GST_VAAPI_DISPLAY_TYPE_X11:
+      sink->backend = gst_vaapisink_backend_x11 ();
+      break;
+#endif
+#if GST_VAAPI_USE_GLX
+    case GST_VAAPI_DISPLAY_TYPE_GLX:
+      sink->backend = gst_vaapisink_backend_x11 ();
+      break;
+#endif
+#if GST_VAAPI_USE_WAYLAND
+    case GST_VAAPI_DISPLAY_TYPE_WAYLAND:
+      sink->backend = gst_vaapisink_backend_wayland ();
+      break;
+#endif
+    default:
+      GST_ERROR ("failed to initialize GstVaapiSink backend");
+      g_assert_not_reached ();
+      break;
+  }
+}
+
+static gboolean
+gst_vaapisink_ensure_render_rect (GstVaapiSink * sink, guint width,
+    guint height)
+{
+  GstVaapiRectangle *const display_rect = &sink->display_rect;
+  guint num, den, display_par_n, display_par_d;
+  gboolean success;
+
+  /* Return success if caps are not set yet */
+  if (!sink->caps)
+    return TRUE;
+
+  if (!sink->keep_aspect) {
+    display_rect->width = width;
+    display_rect->height = height;
+    display_rect->x = 0;
+    display_rect->y = 0;
+
+    GST_DEBUG ("force-aspect-ratio is false; distorting while scaling video");
+    GST_DEBUG ("render rect (%d,%d):%ux%u",
+        display_rect->x, display_rect->y,
+        display_rect->width, display_rect->height);
+    return TRUE;
+  }
+
+  GST_DEBUG ("ensure render rect within %ux%u bounds", width, height);
+
+  gst_vaapi_display_get_pixel_aspect_ratio (GST_VAAPI_PLUGIN_BASE_DISPLAY
+      (sink), &display_par_n, &display_par_d);
+  GST_DEBUG ("display pixel-aspect-ratio %d/%d", display_par_n, display_par_d);
+
+  success = gst_video_calculate_display_ratio (&num, &den,
+      sink->video_width, sink->video_height,
+      sink->video_par_n, sink->video_par_d, display_par_n, display_par_d);
+  if (!success)
+    return FALSE;
+  GST_DEBUG ("video size %dx%d, calculated ratio %d/%d",
+      sink->video_width, sink->video_height, num, den);
+
+  display_rect->width = gst_util_uint64_scale_int (height, num, den);
+  if (display_rect->width <= width) {
+    GST_DEBUG ("keeping window height");
+    display_rect->height = height;
+  } else {
+    GST_DEBUG ("keeping window width");
+    display_rect->width = width;
+    display_rect->height = gst_util_uint64_scale_int (width, den, num);
+  }
+  GST_DEBUG ("scaling video to %ux%u", display_rect->width,
+      display_rect->height);
+
+  g_assert (display_rect->width <= width);
+  g_assert (display_rect->height <= height);
+
+  display_rect->x = (width - display_rect->width) / 2;
+  display_rect->y = (height - display_rect->height) / 2;
+
+  GST_DEBUG ("render rect (%d,%d):%ux%u",
+      display_rect->x, display_rect->y,
+      display_rect->width, display_rect->height);
+  return TRUE;
+}
+
+static inline gboolean
+gst_vaapisink_ensure_window (GstVaapiSink * sink, guint width, guint height)
+{
+  return sink->window || sink->backend->create_window (sink, width, height);
+}
+
+static void
+gst_vaapisink_ensure_window_size (GstVaapiSink * sink, guint * width_ptr,
+    guint * height_ptr)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
+  GstVideoRectangle src_rect, dst_rect, out_rect;
+  guint num, den, display_width, display_height, display_par_n, display_par_d;
+  gboolean success, scale;
+
+  if (sink->foreign_window) {
+    *width_ptr = sink->window_width;
+    *height_ptr = sink->window_height;
+    return;
+  }
+
+  gst_vaapi_display_get_size (display, &display_width, &display_height);
+  if (sink->fullscreen) {
+    *width_ptr = display_width;
+    *height_ptr = display_height;
+    return;
+  }
+
+  gst_vaapi_display_get_pixel_aspect_ratio (display,
+      &display_par_n, &display_par_d);
+
+  success = gst_video_calculate_display_ratio (&num, &den,
+      sink->video_width, sink->video_height,
+      sink->video_par_n, sink->video_par_d, display_par_n, display_par_d);
+  if (!success) {
+    num = sink->video_par_n;
+    den = sink->video_par_d;
+  }
+
+  src_rect.x = 0;
+  src_rect.y = 0;
+  src_rect.w = gst_util_uint64_scale_int (sink->video_height, num, den);
+  src_rect.h = sink->video_height;
+  dst_rect.x = 0;
+  dst_rect.y = 0;
+  dst_rect.w = display_width;
+  dst_rect.h = display_height;
+  scale = (src_rect.w > dst_rect.w || src_rect.h > dst_rect.h);
+  gst_video_sink_center_rect (src_rect, dst_rect, &out_rect, scale);
+  *width_ptr = out_rect.w;
+  *height_ptr = out_rect.h;
+}
+
+static inline gboolean
+gst_vaapisink_ensure_colorbalance (GstVaapiSink * sink)
+{
+  return cb_sync_values_to_display (sink, GST_VAAPI_PLUGIN_BASE_DISPLAY (sink));
+}
+
+
+static void
+gst_vaapisink_set_rotation (GstVaapiSink * sink, GstVaapiRotation rotation,
+    gboolean from_tag)
+{
+  GST_OBJECT_LOCK (sink);
+
+  if (from_tag)
+    sink->rotation_tag = rotation;
+  else
+    sink->rotation_prop = rotation;
+
+  if (sink->rotation_prop == GST_VAAPI_ROTATION_AUTOMATIC)
+    sink->rotation_req = sink->rotation_tag;
+  else
+    sink->rotation_req = sink->rotation_prop;
+
+  GST_OBJECT_UNLOCK (sink);
+}
+
+static gboolean
+gst_vaapisink_ensure_rotation (GstVaapiSink * sink,
+    gboolean recalc_display_rect)
+{
+  GstVaapiDisplay *const display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
+  gboolean success = FALSE;
+
+  g_return_val_if_fail (display, FALSE);
+
+  if (sink->rotation == sink->rotation_req)
+    return TRUE;
+
+  if (!sink->use_rotation) {
+    GST_WARNING ("VA display does not support rotation");
+    goto end;
+  }
+
+  gst_vaapi_display_lock (display);
+  success = gst_vaapi_display_set_rotation (display, sink->rotation_req);
+  gst_vaapi_display_unlock (display);
+  if (!success) {
+    GST_ERROR ("failed to change VA display rotation mode");
+    goto end;
+  }
+
+  if (((sink->rotation + sink->rotation_req) % 180) == 90) {
+    /* Orientation changed */
+    G_PRIMITIVE_SWAP (guint, sink->video_width, sink->video_height);
+    G_PRIMITIVE_SWAP (gint, sink->video_par_n, sink->video_par_d);
+  }
+
+  if (recalc_display_rect && !sink->foreign_window)
+    gst_vaapisink_ensure_render_rect (sink, sink->window_width,
+        sink->window_height);
+  success = TRUE;
+
+end:
+  sink->rotation = sink->rotation_req;
+  return success;
+}
+
+static const gchar *
+get_display_type_name (GstVaapiDisplayType display_type)
+{
+  gpointer const klass = g_type_class_peek (GST_VAAPI_TYPE_DISPLAY_TYPE);
+  GEnumValue *const e = g_enum_get_value (klass, display_type);
+
+  if (e)
+    return e->value_name;
+  return "<unknown-type>";
+}
+
+static void
+gst_vaapisink_display_changed (GstVaapiPluginBase * plugin)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (plugin);
+  GstVaapiRenderMode render_mode;
+
+  GST_INFO ("created %s %p", get_display_type_name (plugin->display_type),
+      plugin->display);
+
+  gst_vaapisink_ensure_backend (sink);
+
+  sink->use_overlay =
+      gst_vaapi_display_get_render_mode (plugin->display, &render_mode) &&
+      render_mode == GST_VAAPI_RENDER_MODE_OVERLAY;
+  GST_DEBUG ("use %s rendering mode",
+      sink->use_overlay ? "overlay" : "texture");
+
+  /* Keep our own colorbalance values, should we have any change pending */
+  if (!sink->cb_changed)
+    cb_sync_values_from_display (sink, plugin->display);
+
+  sink->use_rotation = gst_vaapi_display_has_property (plugin->display,
+      GST_VAAPI_DISPLAY_PROP_ROTATION);
+}
+
+static gboolean
+gst_vaapisink_start (GstBaseSink * base_sink)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink);
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (base_sink);
+
+  if (!gst_vaapisink_ensure_display (sink))
+    return FALSE;
+
+  /* Ensures possible raw caps earlier to avoid race conditions at
+   * get_caps() */
+  if (!gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (plugin))
+    return FALSE;
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapisink_stop (GstBaseSink * base_sink)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink);
+
+  gst_vaapisink_set_event_handling (sink, FALSE);
+  gst_buffer_replace (&sink->video_buffer, NULL);
+  gst_vaapi_window_replace (&sink->window, NULL);
+
+  gst_vaapi_plugin_base_close (GST_VAAPI_PLUGIN_BASE (sink));
+  return TRUE;
+}
+
+static GstCaps *
+gst_vaapisink_get_caps_impl (GstBaseSink * base_sink)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink);
+  GstCaps *out_caps, *raw_caps, *feature_caps;
+  static const char surface_caps_str[] =
+      GST_VAAPI_MAKE_SURFACE_CAPS ";"
+      GST_VIDEO_CAPS_MAKE_WITH_FEATURES (GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE
+      "," GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION,
+      "{ ENCODED, NV12, I420, YV12 }");
+  GstCapsFeatures *features;
+
+  if (!GST_VAAPI_PLUGIN_BASE_DISPLAY (sink))
+    return gst_static_pad_template_get_caps (&gst_vaapisink_sink_factory);
+
+  out_caps = gst_caps_from_string (surface_caps_str);
+  raw_caps =
+      gst_vaapi_plugin_base_get_allowed_sinkpad_raw_caps (GST_VAAPI_PLUGIN_BASE
+      (sink));
+  if (!raw_caps)
+    return out_caps;
+
+  out_caps = gst_caps_make_writable (out_caps);
+  gst_caps_append (out_caps, gst_caps_copy (raw_caps));
+
+  feature_caps = gst_caps_copy (raw_caps);
+  features = gst_caps_features_new
+      (GST_CAPS_FEATURE_META_GST_VIDEO_OVERLAY_COMPOSITION, NULL);
+  gst_caps_set_features (feature_caps, 0, features);
+  gst_caps_append (out_caps, feature_caps);
+
+  return out_caps;
+}
+
+static inline GstCaps *
+gst_vaapisink_get_caps (GstBaseSink * base_sink, GstCaps * filter)
+{
+  GstCaps *caps, *out_caps;
+
+  caps = gst_vaapisink_get_caps_impl (base_sink);
+  if (caps && filter) {
+    out_caps = gst_caps_intersect_full (caps, filter, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+  } else
+    out_caps = caps;
+  return out_caps;
+}
+
+static void
+update_colorimetry (GstVaapiSink * sink, GstVideoColorimetry * cinfo)
+{
+  if (gst_video_colorimetry_matches (cinfo, GST_VIDEO_COLORIMETRY_BT601))
+    sink->color_standard = GST_VAAPI_COLOR_STANDARD_ITUR_BT_601;
+  else if (gst_video_colorimetry_matches (cinfo, GST_VIDEO_COLORIMETRY_BT709))
+    sink->color_standard = GST_VAAPI_COLOR_STANDARD_ITUR_BT_709;
+  else if (gst_video_colorimetry_matches (cinfo,
+          GST_VIDEO_COLORIMETRY_SMPTE240M))
+    sink->color_standard = GST_VAAPI_COLOR_STANDARD_SMPTE_240M;
+  else
+    sink->color_standard = 0;
+
+#ifndef GST_DISABLE_GST_DEBUG
+  {
+    gchar *const colorimetry_string = gst_video_colorimetry_to_string (cinfo);
+    GST_DEBUG ("colorimetry %s", colorimetry_string);
+    g_free (colorimetry_string);
+  }
+#endif
+}
+
+static gboolean
+gst_vaapisink_set_caps (GstBaseSink * base_sink, GstCaps * caps)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (base_sink);
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink);
+  GstVideoInfo *const vip = GST_VAAPI_PLUGIN_BASE_SINK_PAD_INFO (sink);
+  GstVaapiDisplay *display;
+  guint win_width, win_height;
+
+  if (!gst_vaapisink_ensure_display (sink))
+    return FALSE;
+  display = GST_VAAPI_PLUGIN_BASE_DISPLAY (sink);
+
+  if (!gst_vaapi_plugin_base_set_caps (plugin, caps, NULL))
+    return FALSE;
+
+  sink->video_width = GST_VIDEO_INFO_WIDTH (vip);
+  sink->video_height = GST_VIDEO_INFO_HEIGHT (vip);
+  sink->video_par_n = GST_VIDEO_INFO_PAR_N (vip);
+  sink->video_par_d = GST_VIDEO_INFO_PAR_D (vip);
+  if (sink->video_par_n == 0)
+    sink->video_par_n = 1;
+  GST_DEBUG ("video pixel-aspect-ratio %d/%d",
+      sink->video_par_n, sink->video_par_d);
+
+  update_colorimetry (sink, &GST_VIDEO_INFO_COLORIMETRY (vip));
+  gst_caps_replace (&sink->caps, caps);
+
+  /* Reset the rotation to the default when new caps are coming in. This
+   * forces re-evaluating if the rotation needs to be done */
+  sink->rotation = DEFAULT_ROTATION;
+  gst_vaapisink_ensure_colorbalance (sink);
+  gst_vaapisink_ensure_rotation (sink, FALSE);
+
+  if (GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE (sink) == GST_VAAPI_DISPLAY_TYPE_DRM)
+    return TRUE;
+
+  gst_vaapisink_ensure_window_size (sink, &win_width, &win_height);
+  if (sink->window) {
+    if (!sink->foreign_window || sink->fullscreen)
+      gst_vaapi_window_set_size (sink->window, win_width, win_height);
+  } else {
+    gst_vaapi_display_lock (display);
+    gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
+    gst_vaapi_display_unlock (display);
+    if (sink->window)
+      return TRUE;
+    if (!gst_vaapisink_ensure_window (sink, win_width, win_height))
+      return FALSE;
+    gst_vaapi_window_set_fullscreen (sink->window, sink->fullscreen);
+    gst_vaapi_window_show (sink->window);
+    gst_vaapi_window_get_size (sink->window, &win_width, &win_height);
+    gst_vaapisink_set_event_handling (sink, sink->handle_events);
+  }
+  sink->window_width = win_width;
+  sink->window_height = win_height;
+  GST_DEBUG ("window size %ux%u", win_width, win_height);
+
+  return gst_vaapisink_ensure_render_rect (sink, win_width, win_height);
+}
+
+static GstFlowReturn
+gst_vaapisink_show_frame_unlocked (GstVaapiSink * sink, GstBuffer * src_buffer)
+{
+  GstVaapiVideoMeta *meta;
+  GstVaapiSurfaceProxy *proxy;
+  GstVaapiSurface *surface;
+  GstBuffer *buffer;
+  GstBuffer *old_buf;
+  guint flags;
+  GstVaapiRectangle *surface_rect = NULL;
+  GstVaapiRectangle tmp_rect;
+  GstFlowReturn ret;
+  gint32 view_id;
+  GstVideoCropMeta *crop_meta;
+
+  if (!src_buffer) {
+    if (sink->video_buffer)
+      src_buffer = sink->video_buffer;
+    else
+      return GST_FLOW_OK;
+  }
+
+  crop_meta = gst_buffer_get_video_crop_meta (src_buffer);
+  if (crop_meta) {
+    surface_rect = &tmp_rect;
+    surface_rect->x = crop_meta->x;
+    surface_rect->y = crop_meta->y;
+    surface_rect->width = crop_meta->width;
+    surface_rect->height = crop_meta->height;
+  }
+
+  ret = gst_vaapi_plugin_base_get_input_buffer (GST_VAAPI_PLUGIN_BASE (sink),
+      src_buffer, &buffer);
+  if (ret == GST_FLOW_NOT_SUPPORTED)
+    return GST_FLOW_OK;         /* let's ignore the frame if it couldn't be uploaded */
+  if (ret != GST_FLOW_OK)
+    return ret;
+
+  meta = gst_buffer_get_vaapi_video_meta (buffer);
+  if (gst_vaapi_video_meta_get_display (meta) !=
+      GST_VAAPI_PLUGIN_BASE_DISPLAY (sink))
+    goto different_display;
+
+  proxy = gst_vaapi_video_meta_get_surface_proxy (meta);
+  if (!proxy)
+    goto no_surface;
+
+  surface = gst_vaapi_video_meta_get_surface (meta);
+  if (!surface)
+    goto no_surface;
+
+  /* Validate view component to display */
+  view_id = GST_VAAPI_SURFACE_PROXY_VIEW_ID (proxy);
+  if (G_UNLIKELY (sink->view_id == -1))
+    sink->view_id = view_id;
+  else if (sink->view_id != view_id) {
+    ret = GST_FLOW_OK;
+    goto done;
+  }
+
+  gst_vaapisink_ensure_colorbalance (sink);
+  gst_vaapisink_ensure_rotation (sink, TRUE);
+
+  GST_TRACE_OBJECT (sink, "render surface %" GST_VAAPI_ID_FORMAT,
+      GST_VAAPI_ID_ARGS (gst_vaapi_surface_get_id (surface)));
+
+  if (!surface_rect)
+    surface_rect = (GstVaapiRectangle *)
+        gst_vaapi_video_meta_get_render_rect (meta);
+
+  if (surface_rect)
+    GST_DEBUG ("render rect (%d,%d), size %ux%u",
+        surface_rect->x, surface_rect->y,
+        surface_rect->width, surface_rect->height);
+
+  flags = gst_vaapi_video_meta_get_render_flags (meta);
+
+  /* Append default color standard obtained from caps if none was
+     available on a per-buffer basis */
+  if (!(flags & GST_VAAPI_COLOR_STANDARD_MASK))
+    flags |= sink->color_standard;
+
+  if (!gst_vaapi_apply_composition (surface, src_buffer))
+    GST_WARNING ("could not update subtitles");
+
+  if (!sink->backend->render_surface (sink, surface, surface_rect, flags))
+    goto error;
+
+  if (sink->signal_handoffs)
+    g_signal_emit (sink, gst_vaapisink_signals[HANDOFF_SIGNAL], 0, buffer);
+
+  /* Retain VA surface until the next one is displayed */
+  old_buf = sink->video_buffer;
+  sink->video_buffer = gst_buffer_ref (buffer);
+  /* Need to release the lock while releasing old buffer, otherwise a
+   * deadlock is possible */
+  gst_vaapi_display_unlock (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink));
+  if (old_buf)
+    gst_buffer_unref (old_buf);
+  gst_vaapi_display_lock (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink));
+
+  ret = GST_FLOW_OK;
+
+done:
+  gst_buffer_unref (buffer);
+  return ret;
+
+  /* ERRORS */
+error:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
+        ("Internal error: could not render surface"), (NULL));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+
+no_surface:
+  {
+    /* No surface or surface proxy. That's very bad! */
+    GST_WARNING_OBJECT (sink, "could not get surface");
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+
+different_display:
+  {
+    GST_WARNING_OBJECT (sink, "incoming surface has different VAAPI Display");
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+}
+
+static GstFlowReturn
+gst_vaapisink_show_frame (GstVideoSink * video_sink, GstBuffer * src_buffer)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (video_sink);
+  GstFlowReturn ret;
+
+  /* We need at least to protect the gst_vaapi_aplpy_composition()
+   * call to prevent a race during subpicture destruction.
+   * FIXME: a less coarse grained lock could be used, though */
+  gst_vaapi_display_lock (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink));
+  ret = gst_vaapisink_show_frame_unlocked (sink, src_buffer);
+  gst_vaapi_display_unlock (GST_VAAPI_PLUGIN_BASE_DISPLAY (sink));
+
+  return ret;
+}
+
+static gboolean
+gst_vaapisink_propose_allocation (GstBaseSink * base_sink, GstQuery * query)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (base_sink);
+
+  if (!gst_vaapi_plugin_base_propose_allocation (plugin, query))
+    return FALSE;
+
+  gst_query_add_allocation_meta (query, GST_VIDEO_CROP_META_API_TYPE, NULL);
+  gst_query_add_allocation_meta (query,
+      GST_VIDEO_OVERLAY_COMPOSITION_META_API_TYPE, NULL);
+  return TRUE;
+}
+
+static gboolean
+gst_vaapisink_query (GstBaseSink * base_sink, GstQuery * query)
+{
+  GstElement *const element = GST_ELEMENT (base_sink);
+  gboolean ret = FALSE;
+
+  switch (GST_QUERY_TYPE (query)) {
+    case GST_QUERY_CONTEXT:
+      ret = gst_vaapi_handle_context_query (element, query);
+      break;
+    default:
+      ret = GST_BASE_SINK_CLASS (gst_vaapisink_parent_class)->query (base_sink,
+          query);
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_vaapisink_destroy (GstVaapiSink * sink)
+{
+  cb_channels_finalize (sink);
+  gst_buffer_replace (&sink->video_buffer, NULL);
+  gst_caps_replace (&sink->caps, NULL);
+}
+
+static void
+gst_vaapisink_finalize (GObject * object)
+{
+  gst_vaapisink_destroy (GST_VAAPISINK_CAST (object));
+
+  gst_vaapi_plugin_base_finalize (GST_VAAPI_PLUGIN_BASE (object));
+  G_OBJECT_CLASS (gst_vaapisink_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapisink_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DISPLAY_TYPE:
+      gst_vaapi_plugin_base_set_display_type (GST_VAAPI_PLUGIN_BASE (sink),
+          g_value_get_enum (value));
+      break;
+    case PROP_DISPLAY_NAME:
+      gst_vaapi_plugin_base_set_display_name (GST_VAAPI_PLUGIN_BASE (sink),
+          g_value_get_string (value));
+      break;
+    case PROP_FULLSCREEN:
+      sink->fullscreen = g_value_get_boolean (value);
+      break;
+    case PROP_VIEW_ID:
+      sink->view_id = g_value_get_int (value);
+      break;
+    case PROP_ROTATION:
+      gst_vaapisink_set_rotation (sink, g_value_get_enum (value), FALSE);
+      break;
+    case PROP_FORCE_ASPECT_RATIO:
+      sink->keep_aspect = g_value_get_boolean (value);
+      break;
+    case PROP_SIGNAL_HANDOFFS:
+      sink->signal_handoffs = g_value_get_boolean (value);
+      break;
+    case PROP_HUE:
+    case PROP_SATURATION:
+    case PROP_BRIGHTNESS:
+    case PROP_CONTRAST:
+      cb_set_value (sink, (prop_id - PROP_HUE) + CB_HUE,
+          g_value_get_float (value));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapisink_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (object);
+
+  switch (prop_id) {
+    case PROP_DISPLAY_TYPE:
+      g_value_set_enum (value, GST_VAAPI_PLUGIN_BASE_DISPLAY_TYPE (sink));
+      break;
+    case PROP_DISPLAY_NAME:
+      g_value_set_string (value, GST_VAAPI_PLUGIN_BASE_DISPLAY_NAME (sink));
+      break;
+    case PROP_FULLSCREEN:
+      g_value_set_boolean (value, sink->fullscreen);
+      break;
+    case PROP_VIEW_ID:
+      g_value_set_int (value, sink->view_id);
+      break;
+    case PROP_ROTATION:
+      g_value_set_enum (value, sink->rotation);
+      break;
+    case PROP_FORCE_ASPECT_RATIO:
+      g_value_set_boolean (value, sink->keep_aspect);
+      break;
+    case PROP_SIGNAL_HANDOFFS:
+      g_value_set_boolean (value, sink->signal_handoffs);
+      break;
+    case PROP_HUE:
+    case PROP_SATURATION:
+    case PROP_BRIGHTNESS:
+    case PROP_CONTRAST:
+      g_value_set_float (value, cb_get_value (sink,
+              (prop_id - PROP_HUE) + CB_HUE));
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static gboolean
+gst_vaapisink_unlock (GstBaseSink * base_sink)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink);
+
+  if (sink->window)
+    return gst_vaapi_window_unblock (sink->window);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapisink_unlock_stop (GstBaseSink * base_sink)
+{
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink);
+
+  if (sink->window)
+    return gst_vaapi_window_unblock_cancel (sink->window);
+
+  return TRUE;
+}
+
+static gboolean
+gst_vaapisink_event (GstBaseSink * base_sink, GstEvent * event)
+{
+  gboolean res = TRUE;
+  GstTagList *taglist;
+  gchar *orientation;
+
+  GstVaapiSink *const sink = GST_VAAPISINK_CAST (base_sink);
+
+  GST_DEBUG_OBJECT (sink, "handling event %s", GST_EVENT_TYPE_NAME (event));
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_TAG:
+      gst_event_parse_tag (event, &taglist);
+
+      if (gst_tag_list_get_string (taglist, GST_TAG_IMAGE_ORIENTATION,
+              &orientation)) {
+        if (!g_strcmp0 ("rotate-0", orientation)) {
+          gst_vaapisink_set_rotation (sink, GST_VAAPI_ROTATION_0, TRUE);
+        } else if (!g_strcmp0 ("rotate-90", orientation)) {
+          gst_vaapisink_set_rotation (sink, GST_VAAPI_ROTATION_90, TRUE);
+        } else if (!g_strcmp0 ("rotate-180", orientation)) {
+          gst_vaapisink_set_rotation (sink, GST_VAAPI_ROTATION_180, TRUE);
+        } else if (!g_strcmp0 ("rotate-270", orientation)) {
+          gst_vaapisink_set_rotation (sink, GST_VAAPI_ROTATION_270, TRUE);
+        }
+
+        /* Do not support for flip yet.
+         * It should be implemented in the near future.
+         * See https://bugs.freedesktop.org/show_bug.cgi?id=90654
+         */
+        g_free (orientation);
+      }
+      break;
+    default:
+      break;
+  }
+
+  res =
+      GST_BASE_SINK_CLASS (gst_vaapisink_parent_class)->event (base_sink,
+      event);
+
+  return res;
+}
+
+static void
+gst_vaapisink_class_init (GstVaapiSinkClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstElementClass *const element_class = GST_ELEMENT_CLASS (klass);
+  GstBaseSinkClass *const basesink_class = GST_BASE_SINK_CLASS (klass);
+  GstVideoSinkClass *const videosink_class = GST_VIDEO_SINK_CLASS (klass);
+  GstVaapiPluginBaseClass *const base_plugin_class =
+      GST_VAAPI_PLUGIN_BASE_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_vaapisink,
+      GST_PLUGIN_NAME, 0, GST_PLUGIN_DESC);
+
+  gst_vaapi_plugin_base_class_init (base_plugin_class);
+  base_plugin_class->has_interface = gst_vaapisink_has_interface;
+  base_plugin_class->display_changed = gst_vaapisink_display_changed;
+
+  object_class->finalize = gst_vaapisink_finalize;
+  object_class->set_property = gst_vaapisink_set_property;
+  object_class->get_property = gst_vaapisink_get_property;
+
+  basesink_class->start = gst_vaapisink_start;
+  basesink_class->stop = gst_vaapisink_stop;
+  basesink_class->get_caps = gst_vaapisink_get_caps;
+  basesink_class->set_caps = gst_vaapisink_set_caps;
+  basesink_class->query = GST_DEBUG_FUNCPTR (gst_vaapisink_query);
+  basesink_class->propose_allocation = gst_vaapisink_propose_allocation;
+  basesink_class->unlock = gst_vaapisink_unlock;
+  basesink_class->unlock_stop = gst_vaapisink_unlock_stop;
+  basesink_class->event = gst_vaapisink_event;
+
+  videosink_class->show_frame = GST_DEBUG_FUNCPTR (gst_vaapisink_show_frame);
+
+  element_class->set_context = gst_vaapi_base_set_context;
+  gst_element_class_set_static_metadata (element_class,
+      "VA-API sink", "Sink/Video", GST_PLUGIN_DESC,
+      "Gwenole Beauchesne <gwenole.beauchesne@intel.com>");
+
+  gst_element_class_add_static_pad_template (element_class,
+      &gst_vaapisink_sink_factory);
+
+  /**
+   * GstVaapiSink:display:
+   *
+   * The type of display to use.
+   */
+  g_properties[PROP_DISPLAY_TYPE] =
+      g_param_spec_enum ("display",
+      "display type",
+      "display type to use",
+      GST_VAAPI_TYPE_DISPLAY_TYPE,
+      GST_VAAPI_DISPLAY_TYPE_ANY, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiSink:display-name:
+   *
+   * The native display name.
+   */
+  g_properties[PROP_DISPLAY_NAME] =
+      g_param_spec_string ("display-name",
+      "display name",
+      "display name to use", NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiSink:fullscreen:
+   *
+   * Selects whether fullscreen mode is enabled or not.
+   */
+  g_properties[PROP_FULLSCREEN] =
+      g_param_spec_boolean ("fullscreen",
+      "Fullscreen",
+      "Requests window in fullscreen state",
+      FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiSink:rotation:
+   *
+   * The VA display rotation mode, expressed as a #GstVaapiRotation.
+   */
+  g_properties[PROP_ROTATION] =
+      g_param_spec_enum (GST_VAAPI_DISPLAY_PROP_ROTATION,
+      "rotation",
+      "The display rotation mode",
+      GST_VAAPI_TYPE_ROTATION,
+      DEFAULT_ROTATION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiSink:force-aspect-ratio:
+   *
+   * When enabled, scaling respects video aspect ratio; when disabled,
+   * the video is distorted to fit the window.
+   */
+  g_properties[PROP_FORCE_ASPECT_RATIO] =
+      g_param_spec_boolean ("force-aspect-ratio",
+      "Force aspect ratio",
+      "When enabled, scaling will respect original aspect ratio",
+      TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiSink:signal-handoffs:
+   *
+   * Send a signal after rendering the buffer.
+   */
+  g_properties[PROP_SIGNAL_HANDOFFS] =
+      g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
+      "Send a signal after rendering the buffer", DEFAULT_SIGNAL_HANDOFFS,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiSink:view-id:
+   *
+   * When not set to -1, the displayed frame will always be the one
+   * that matches the view-id of the very first displayed frame. Any
+   * other number will indicate the desire to display the supplied
+   * view-id only.
+   */
+  g_properties[PROP_VIEW_ID] =
+      g_param_spec_int ("view-id",
+      "View ID",
+      "ID of the view component of interest to display",
+      -1, G_MAXINT32, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
+
+  /**
+   * GstVaapiSink:hue:
+   *
+   * The VA display hue, expressed as a float value. Range is -180.0
+   * to 180.0. Default value is 0.0 and represents no modification.
+   */
+  g_properties[PROP_HUE] =
+      g_param_spec_float (GST_VAAPI_DISPLAY_PROP_HUE,
+      "hue", "The display hue value", -180.0, 180.0, 0.0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
+
+  /**
+   * GstVaapiSink:saturation:
+   *
+   * The VA display saturation, expressed as a float value. Range is
+   * 0.0 to 2.0. Default value is 1.0 and represents no modification.
+   */
+  g_properties[PROP_SATURATION] =
+      g_param_spec_float (GST_VAAPI_DISPLAY_PROP_SATURATION,
+      "saturation",
+      "The display saturation value", 0.0, 2.0, 1.0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
+
+  /**
+   * GstVaapiSink:brightness:
+   *
+   * The VA display brightness, expressed as a float value. Range is
+   * -1.0 to 1.0. Default value is 0.0 and represents no modification.
+   */
+  g_properties[PROP_BRIGHTNESS] =
+      g_param_spec_float (GST_VAAPI_DISPLAY_PROP_BRIGHTNESS,
+      "brightness",
+      "The display brightness value", -1.0, 1.0, 0.0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
+
+  /**
+   * GstVaapiSink:contrast:
+   *
+   * The VA display contrast, expressed as a float value. Range is 0.0
+   * to 2.0. Default value is 1.0 and represents no modification.
+   */
+  g_properties[PROP_CONTRAST] =
+      g_param_spec_float (GST_VAAPI_DISPLAY_PROP_CONTRAST,
+      "contrast",
+      "The display contrast value", 0.0, 2.0, 1.0,
+      G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT);
+
+  g_object_class_install_properties (object_class, N_PROPERTIES, g_properties);
+
+  /**
+   * GstVaapiSink::handoff:
+   * @object: the #GstVaapiSink instance
+   * @buffer: the buffer that was rendered
+   *
+   * This signal gets emitted after rendering the frame.
+   */
+  gst_vaapisink_signals[HANDOFF_SIGNAL] =
+      g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic,
+      G_TYPE_NONE, 1, GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE);
+}
+
+static void
+gst_vaapisink_init (GstVaapiSink * sink)
+{
+  GstVaapiPluginBase *const plugin = GST_VAAPI_PLUGIN_BASE (sink);
+  guint i;
+
+  gst_vaapi_plugin_base_init (plugin, GST_CAT_DEFAULT);
+  gst_vaapi_plugin_base_set_display_type (plugin, DEFAULT_DISPLAY_TYPE);
+
+  sink->video_par_n = 1;
+  sink->video_par_d = 1;
+  sink->view_id = -1;
+  sink->handle_events = TRUE;
+  sink->rotation = DEFAULT_ROTATION;
+  sink->rotation_req = DEFAULT_ROTATION;
+  sink->rotation_tag = DEFAULT_ROTATION;
+  sink->keep_aspect = TRUE;
+  sink->signal_handoffs = DEFAULT_SIGNAL_HANDOFFS;
+  gst_video_info_init (&sink->video_info);
+
+  for (i = 0; i < G_N_ELEMENTS (sink->cb_values); i++)
+    g_value_init (&sink->cb_values[i], G_TYPE_FLOAT);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapisink.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapisink.h
new file mode 100644 (file)
index 0000000..525f422
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *  gstvaapisink.h - VA-API video sink
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPISINK_H
+#define GST_VAAPISINK_H
+
+#include "gstvaapipluginbase.h"
+#include <gst/vaapi/gstvaapiwindow.h>
+#include "gstvaapipluginutil.h"
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_VAAPISINK \
+  (gst_vaapisink_get_type ())
+#define GST_VAAPISINK_CAST(obj) \
+  ((GstVaapiSink *)(obj))
+#define GST_VAAPISINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_VAAPISINK, GstVaapiSink))
+#define GST_VAAPISINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_VAAPISINK, GstVaapiSinkClass))
+#define GST_IS_VAAPISINK(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_VAAPISINK))
+#define GST_IS_VAAPISINK_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_VAAPISINK))
+#define GST_VAAPISINK_GET_CLASS(obj) \
+  (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_VAAPISINK, GstVaapiSinkClass))
+
+typedef struct _GstVaapiSink                    GstVaapiSink;
+typedef struct _GstVaapiSinkClass               GstVaapiSinkClass;
+typedef struct _GstVaapiSinkBackend             GstVaapiSinkBackend;
+
+typedef gboolean (*GstVaapiSinkCreateWindowFunc) (GstVaapiSink * sink,
+    guint width, guint height);
+typedef gboolean (*GstVaapiSinkCreateWindowFromHandleFunc) (GstVaapiSink * sink,
+    guintptr window);
+typedef gboolean (*GstVaapiSinkRenderSurfaceFunc) (GstVaapiSink * sink,
+    GstVaapiSurface * surface, const GstVaapiRectangle * surface_rect,
+    guint flags);
+typedef gboolean (*GstVaapiSinkHandleEventsFunc) (GstVaapiSink * sink);
+typedef gboolean (*GstVaapiSinkPreStartEventThreadFunc) (GstVaapiSink * sink);
+typedef gboolean (*GstVaapiSinkPreStopEventThreadFunc) (GstVaapiSink * sink);
+
+struct _GstVaapiSinkBackend
+{
+  GstVaapiSinkCreateWindowFunc create_window;
+  GstVaapiSinkCreateWindowFromHandleFunc create_window_from_handle;
+  GstVaapiSinkRenderSurfaceFunc render_surface;
+
+  /* Event threads handling */
+  gboolean event_thread_needed;
+  GstVaapiSinkHandleEventsFunc handle_events;
+  GstVaapiSinkPreStartEventThreadFunc pre_start_event_thread;
+  GstVaapiSinkPreStopEventThreadFunc pre_stop_event_thread;
+};
+
+struct _GstVaapiSink
+{
+  /*< private >*/
+  GstVaapiPluginBase parent_instance;
+
+  const GstVaapiSinkBackend *backend;
+
+  GstCaps *caps;
+  GstVaapiWindow *window;
+  guint window_width;
+  guint window_height;
+  GstBuffer *video_buffer;
+  guint video_width;
+  guint video_height;
+  gint video_par_n;
+  gint video_par_d;
+  GstVideoInfo video_info;
+  GstVaapiRectangle display_rect;
+  GstVaapiRotation rotation;
+  GstVaapiRotation rotation_req;
+  GstVaapiRotation rotation_tag;
+  GstVaapiRotation rotation_prop;
+  guint color_standard;
+  gint32 view_id;
+  GThread *event_thread;
+  gboolean event_thread_cancel;
+
+  /* Color balance values */
+  guint cb_changed;
+  GValue cb_values[4];
+  GList *cb_channels;
+
+  guint handle_events : 1;
+  guint foreign_window : 1;
+  guint fullscreen : 1;
+  guint use_overlay : 1;
+  guint use_rotation : 1;
+  guint keep_aspect : 1;
+  guint signal_handoffs : 1;
+};
+
+struct _GstVaapiSinkClass
+{
+  /*< private >*/
+  GstVaapiPluginBaseClass parent_class;
+};
+
+GType
+gst_vaapisink_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* GST_VAAPISINK_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobuffer.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobuffer.c
new file mode 100644 (file)
index 0000000..af79338
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ *  gstvaapivideobuffer.c - Gstreamer/VA video buffer
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapivideobuffer
+ * @short_description: VA video buffer for GStreamer
+ *
+ * This functions creates and decorates a #GstBuffer that is going to
+ * be used by VA base gstreamer elements.
+ */
+
+#include "gstcompat.h"
+#include "gstvaapivideobuffer.h"
+
+static GstBuffer *
+new_vbuffer (GstVaapiVideoMeta * meta)
+{
+  GstBuffer *buffer;
+
+  g_return_val_if_fail (meta != NULL, NULL);
+
+  buffer = gst_buffer_new ();
+  if (buffer)
+    gst_buffer_set_vaapi_video_meta (buffer, meta);
+  gst_vaapi_video_meta_unref (meta);
+  return buffer;
+}
+
+GstBuffer *
+gst_vaapi_video_buffer_new (GstVaapiVideoMeta * meta)
+{
+  g_return_val_if_fail (meta != NULL, NULL);
+
+  return new_vbuffer (gst_vaapi_video_meta_ref (meta));
+}
+
+GstBuffer *
+gst_vaapi_video_buffer_new_empty (void)
+{
+  return gst_buffer_new ();
+}
+
+GstBuffer *
+gst_vaapi_video_buffer_new_from_pool (GstVaapiVideoPool * pool)
+{
+  return new_vbuffer (gst_vaapi_video_meta_new_from_pool (pool));
+}
+
+GstBuffer *
+gst_vaapi_video_buffer_new_from_buffer (GstBuffer * buffer)
+{
+  GstVaapiVideoMeta *const meta = gst_buffer_get_vaapi_video_meta (buffer);
+
+  return meta ? new_vbuffer (gst_vaapi_video_meta_ref (meta)) : NULL;
+}
+
+GstBuffer *
+gst_vaapi_video_buffer_new_with_image (GstVaapiImage * image)
+{
+  return new_vbuffer (gst_vaapi_video_meta_new_with_image (image));
+}
+
+GstBuffer *
+gst_vaapi_video_buffer_new_with_surface_proxy (GstVaapiSurfaceProxy * proxy)
+{
+  return new_vbuffer (gst_vaapi_video_meta_new_with_surface_proxy (proxy));
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobuffer.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobuffer.h
new file mode 100644 (file)
index 0000000..f751bc3
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *  gstvaapivideobuffer.h - Gstreamer/VA video buffer
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VIDEO_BUFFER_H
+#define GST_VAAPI_VIDEO_BUFFER_H
+
+#include "gstvaapivideometa.h"
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiVideoBuffer GstVaapiVideoBuffer;
+
+G_GNUC_INTERNAL
+GstBuffer *
+gst_vaapi_video_buffer_new (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+GstBuffer *
+gst_vaapi_video_buffer_new_empty (void);
+
+G_GNUC_INTERNAL
+GstBuffer *
+gst_vaapi_video_buffer_new_from_pool (GstVaapiVideoPool * pool);
+
+G_GNUC_INTERNAL
+GstBuffer *
+gst_vaapi_video_buffer_new_from_buffer (GstBuffer * buffer);
+
+G_GNUC_INTERNAL
+GstBuffer *
+gst_vaapi_video_buffer_new_with_image (GstVaapiImage * image);
+
+G_GNUC_INTERNAL
+GstBuffer *
+gst_vaapi_video_buffer_new_with_surface_proxy (GstVaapiSurfaceProxy * proxy);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_VIDEO_BUFFER_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobufferpool.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobufferpool.c
new file mode 100644 (file)
index 0000000..9e21669
--- /dev/null
@@ -0,0 +1,637 @@
+/*
+ *  gstvaapivideobufferpool.c - Gstreamer/VA video buffer pool
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstcompat.h"
+#include "gstvaapivideobufferpool.h"
+#include "gstvaapivideobuffer.h"
+#include "gstvaapivideomemory.h"
+#include "gstvaapipluginutil.h"
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+#include "gstvaapivideometa_texture.h"
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapivideopool);
+#define GST_CAT_DEFAULT gst_debug_vaapivideopool
+
+enum
+{
+  PROP_0,
+
+  PROP_DISPLAY,
+};
+
+struct _GstVaapiVideoBufferPoolPrivate
+{
+  GstAllocator *allocator;
+  GstVideoInfo vmeta_vinfo;
+  GstVaapiDisplay *display;
+  guint options;
+  guint use_dmabuf_memory:1;
+  guint forced_video_meta:1;
+  /* Map between surface and GstMemory, only DMA */
+  GHashTable *dma_mem_map;
+};
+
+G_DEFINE_TYPE_WITH_PRIVATE (GstVaapiVideoBufferPool,
+    gst_vaapi_video_buffer_pool, GST_TYPE_BUFFER_POOL);
+
+static void
+gst_vaapi_video_buffer_pool_finalize (GObject * object)
+{
+  GstVaapiVideoBufferPoolPrivate *const priv =
+      GST_VAAPI_VIDEO_BUFFER_POOL (object)->priv;
+
+  gst_vaapi_display_replace (&priv->display, NULL);
+  gst_clear_object (&priv->allocator);
+  if (priv->dma_mem_map)
+    g_hash_table_destroy (priv->dma_mem_map);
+
+  G_OBJECT_CLASS (gst_vaapi_video_buffer_pool_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_video_buffer_pool_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstVaapiVideoBufferPoolPrivate *const priv =
+      GST_VAAPI_VIDEO_BUFFER_POOL (object)->priv;
+
+  switch (prop_id) {
+    case PROP_DISPLAY:
+      priv->display = g_value_dup_object (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_vaapi_video_buffer_pool_get_property (GObject * object, guint prop_id,
+    GValue * value, GParamSpec * pspec)
+{
+  GstVaapiVideoBufferPoolPrivate *const priv =
+      GST_VAAPI_VIDEO_BUFFER_POOL (object)->priv;
+
+  switch (prop_id) {
+    case PROP_DISPLAY:
+      g_value_set_pointer (value, priv->display);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+fill_video_alignment (GstVaapiVideoBufferPool * pool, GstVideoAlignment * align)
+{
+  GstVideoInfo *const vip = &pool->priv->vmeta_vinfo;
+  guint i;
+  gint nth_bit;
+
+  gst_video_alignment_reset (align);
+  for (i = 0; i < GST_VIDEO_INFO_N_PLANES (vip); i++) {
+    nth_bit = g_bit_nth_lsf (GST_VIDEO_INFO_PLANE_STRIDE (vip, i), 0);
+    if (nth_bit >= 0)
+      align->stride_align[i] = (1U << nth_bit) - 1;
+  }
+}
+
+static const gchar **
+gst_vaapi_video_buffer_pool_get_options (GstBufferPool * pool)
+{
+  static const gchar *g_options[] = {
+    GST_BUFFER_POOL_OPTION_VIDEO_META,
+    GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META,
+    GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META,
+    GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT,
+    NULL,
+  };
+
+  return g_options;
+}
+
+static gboolean
+gst_vaapi_video_buffer_pool_set_config (GstBufferPool * pool,
+    GstStructure * config)
+{
+  GstVaapiVideoBufferPool *const base_pool = GST_VAAPI_VIDEO_BUFFER_POOL (pool);
+  GstVaapiVideoBufferPoolPrivate *const priv = base_pool->priv;
+  GstCaps *caps;
+  GstVideoInfo new_allocation_vinfo;
+  const GstVideoInfo *allocator_vinfo;
+  const GstVideoInfo *negotiated_vinfo;
+  GstVideoAlignment align;
+  GstAllocator *allocator;
+  gboolean ret;
+  guint size, min_buffers, max_buffers;
+  guint surface_alloc_flags;
+
+  GST_DEBUG_OBJECT (base_pool, "config %" GST_PTR_FORMAT, config);
+
+  caps = NULL;
+  if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers,
+          &max_buffers))
+    goto error_invalid_config;
+  if (!caps)
+    goto error_no_caps;
+  if (!gst_video_info_from_caps (&new_allocation_vinfo, caps))
+    goto error_invalid_caps;
+
+  if (!gst_buffer_pool_config_has_option (config,
+          GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META))
+    goto error_no_vaapi_video_meta_option;
+
+  allocator = NULL;
+  if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL))
+    goto error_invalid_allocator;
+
+  /* it is a valid allocator? */
+  if (allocator
+      && (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0
+          && g_strcmp0 (allocator->mem_type,
+              GST_VAAPI_DMABUF_ALLOCATOR_NAME) != 0))
+    goto error_invalid_allocator;
+
+  /* get the allocator properties */
+  if (allocator) {
+    priv->use_dmabuf_memory = gst_vaapi_is_dmabuf_allocator (allocator);
+    negotiated_vinfo =
+        gst_allocator_get_vaapi_negotiated_video_info (allocator);
+    allocator_vinfo =
+        gst_allocator_get_vaapi_video_info (allocator, &surface_alloc_flags);
+  } else {
+    priv->use_dmabuf_memory = FALSE;
+    negotiated_vinfo = NULL;
+    allocator_vinfo = NULL;
+    surface_alloc_flags = 0;
+  }
+
+  /* reset or update the allocator if video resolution changed */
+  if (allocator_vinfo
+      && gst_video_info_changed (allocator_vinfo, &new_allocation_vinfo)) {
+    gst_object_replace ((GstObject **) & priv->allocator, NULL);
+
+    /* dmabuf allocator can change its parameters: no need to create a
+     * new one */
+    if (priv->use_dmabuf_memory) {
+      gst_allocator_set_vaapi_video_info (allocator, &new_allocation_vinfo,
+          surface_alloc_flags);
+    } else {
+      allocator = NULL;
+    }
+  }
+
+  /* create a new allocator if needed */
+  if (!allocator) {
+    /* if no allocator set, let's create a VAAPI one */
+    allocator = gst_vaapi_video_allocator_new (priv->display,
+        &new_allocation_vinfo, surface_alloc_flags, 0);
+    if (!allocator)
+      goto error_no_allocator;
+
+    if (negotiated_vinfo) {
+      gst_allocator_set_vaapi_negotiated_video_info (allocator,
+          negotiated_vinfo);
+    }
+
+    GST_INFO_OBJECT (base_pool, "created new allocator %" GST_PTR_FORMAT,
+        allocator);
+    gst_buffer_pool_config_set_allocator (config, allocator, NULL);
+    gst_object_unref (allocator);
+  }
+
+  /* use the allocator and set the video info for the vmeta */
+  if (allocator) {
+    if (priv->allocator)
+      gst_object_unref (priv->allocator);
+    if ((priv->allocator = allocator))
+      gst_object_ref (allocator);
+
+    negotiated_vinfo =
+        gst_allocator_get_vaapi_negotiated_video_info (priv->allocator);
+    allocator_vinfo = gst_allocator_get_vaapi_video_info (allocator, NULL);
+    priv->vmeta_vinfo = (negotiated_vinfo) ?
+        *negotiated_vinfo : *allocator_vinfo;
+
+    /* last resource to set the correct buffer size */
+    if (GST_VIDEO_INFO_SIZE (allocator_vinfo) != size) {
+      gst_buffer_pool_config_set_params (config, caps,
+          GST_VIDEO_INFO_SIZE (allocator_vinfo), min_buffers, max_buffers);
+    }
+  }
+  if (!priv->allocator)
+    goto error_no_allocator;
+
+  priv->options = 0;
+  if (gst_buffer_pool_config_has_option (config,
+          GST_BUFFER_POOL_OPTION_VIDEO_META)) {
+    priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META;
+  } else if (gst_caps_is_video_raw (caps) && !priv->use_dmabuf_memory) {
+    gint i;
+
+    for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&new_allocation_vinfo); i++) {
+      if (GST_VIDEO_INFO_PLANE_OFFSET (&new_allocation_vinfo, i) !=
+          GST_VIDEO_INFO_PLANE_OFFSET (&priv->vmeta_vinfo, i) ||
+          GST_VIDEO_INFO_PLANE_STRIDE (&new_allocation_vinfo, i) !=
+          GST_VIDEO_INFO_PLANE_STRIDE (&priv->vmeta_vinfo, i) ||
+          GST_VIDEO_INFO_SIZE (&new_allocation_vinfo) !=
+          GST_VIDEO_INFO_SIZE (&priv->vmeta_vinfo)) {
+        priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META;
+        priv->forced_video_meta = TRUE;
+        GST_INFO_OBJECT (base_pool, "adding unrequested video meta");
+        break;
+      }
+    }
+  }
+
+  if (gst_buffer_pool_config_has_option (config,
+          GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) {
+    fill_video_alignment (GST_VAAPI_VIDEO_BUFFER_POOL (pool), &align);
+    gst_buffer_pool_config_set_video_alignment (config, &align);
+  }
+
+  if (!priv->use_dmabuf_memory && gst_buffer_pool_config_has_option (config,
+          GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META))
+    priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD;
+
+  ret =
+      GST_BUFFER_POOL_CLASS
+      (gst_vaapi_video_buffer_pool_parent_class)->set_config (pool, config);
+  return ret;
+
+  /* ERRORS */
+error_invalid_config:
+  {
+    GST_WARNING_OBJECT (base_pool, "invalid config");
+    return FALSE;
+  }
+error_no_caps:
+  {
+    GST_WARNING_OBJECT (base_pool, "no caps in config");
+    return FALSE;
+  }
+error_invalid_caps:
+  {
+    GST_WARNING_OBJECT (base_pool, "invalid caps %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+error_invalid_allocator:
+  {
+    GST_INFO_OBJECT (base_pool, "no allocator in config");
+    return FALSE;
+  }
+error_no_vaapi_video_meta_option:
+  {
+    GST_WARNING_OBJECT (base_pool, "no GstVaapiVideoMeta option in config");
+    return FALSE;
+  }
+error_no_allocator:
+  {
+    GST_WARNING_OBJECT (base_pool, "no allocator defined");
+    return FALSE;
+  }
+}
+
+static void
+vaapi_buffer_pool_cache_dma_mem (GstVaapiVideoBufferPool * pool,
+    GstVaapiSurfaceProxy * proxy, GstMemory * mem)
+{
+  GstVaapiVideoBufferPoolPrivate *const priv = pool->priv;
+  GstVaapiSurface *surface;
+
+  surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
+  g_assert (surface);
+  g_assert (gst_vaapi_surface_peek_buffer_proxy (surface));
+
+  if (!priv->dma_mem_map)
+    priv->dma_mem_map = g_hash_table_new_full (g_direct_hash,
+        g_direct_equal, NULL, (GDestroyNotify) gst_memory_unref);
+
+  if (!g_hash_table_contains (priv->dma_mem_map, surface)) {
+    g_hash_table_insert (priv->dma_mem_map, surface, gst_memory_ref (mem));
+  } else {
+    g_assert (g_hash_table_lookup (priv->dma_mem_map, surface) == mem);
+  }
+}
+
+static GstMemory *
+vaapi_buffer_pool_lookup_dma_mem (GstVaapiVideoBufferPool * pool,
+    GstVaapiSurfaceProxy * proxy)
+{
+  GstVaapiSurface *surface;
+  GstVaapiVideoBufferPoolPrivate *const priv = pool->priv;
+  GstVaapiBufferProxy *buf_proxy;
+  GstMemory *mem;
+
+  g_assert (priv->use_dmabuf_memory);
+
+  if (!priv->dma_mem_map)
+    return NULL;
+
+  surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
+  g_assert (surface);
+
+  buf_proxy = gst_vaapi_surface_peek_buffer_proxy (surface);
+  /* Have not exported yet */
+  if (!buf_proxy) {
+    g_assert (!g_hash_table_contains (priv->dma_mem_map, surface));
+    return NULL;
+  }
+
+  mem = g_hash_table_lookup (priv->dma_mem_map, surface);
+  g_assert (mem);
+
+  return gst_memory_ref (mem);
+}
+
+static GstFlowReturn
+gst_vaapi_video_buffer_pool_alloc_buffer (GstBufferPool * pool,
+    GstBuffer ** out_buffer_ptr, GstBufferPoolAcquireParams * params)
+{
+  GstVaapiVideoBufferPool *const base_pool = GST_VAAPI_VIDEO_BUFFER_POOL (pool);
+  GstVaapiVideoBufferPoolPrivate *const priv = base_pool->priv;
+  GstVaapiVideoBufferPoolAcquireParams *const priv_params =
+      (GstVaapiVideoBufferPoolAcquireParams *) params;
+  GstVaapiVideoMeta *meta;
+  GstMemory *mem;
+  GstBuffer *buffer;
+
+  if (!priv->allocator)
+    goto error_no_allocator;
+
+  meta = gst_vaapi_video_meta_new (priv->display);
+  if (!meta)
+    goto error_create_meta;
+
+  buffer = gst_vaapi_video_buffer_new (meta);
+
+  if (!buffer)
+    goto error_create_buffer;
+
+  if (priv_params && priv_params->proxy)
+    gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy);
+
+  if (priv->use_dmabuf_memory) {
+    mem = NULL;
+    if (priv_params && priv_params->proxy) {
+      mem = vaapi_buffer_pool_lookup_dma_mem (base_pool, priv_params->proxy);
+      if (!mem) {
+        mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta);
+        if (!mem)
+          goto error_create_memory;
+
+        vaapi_buffer_pool_cache_dma_mem (base_pool, priv_params->proxy, mem);
+      }
+    } else {
+      mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta);
+    }
+  } else {
+    mem = gst_vaapi_video_memory_new (priv->allocator, meta);
+  }
+  if (!mem)
+    goto error_create_memory;
+  gst_vaapi_video_meta_replace (&meta, NULL);
+  gst_buffer_append_memory (buffer, mem);
+
+  if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) {
+    GstVideoInfo *const vip = &priv->vmeta_vinfo;
+    GstVideoMeta *vmeta;
+
+    vmeta = gst_buffer_add_video_meta_full (buffer, 0,
+        GST_VIDEO_INFO_FORMAT (vip), GST_VIDEO_INFO_WIDTH (vip),
+        GST_VIDEO_INFO_HEIGHT (vip), GST_VIDEO_INFO_N_PLANES (vip),
+        &GST_VIDEO_INFO_PLANE_OFFSET (vip, 0),
+        &GST_VIDEO_INFO_PLANE_STRIDE (vip, 0));
+
+    if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) {
+      vmeta->map = gst_video_meta_map_vaapi_memory;
+      vmeta->unmap = gst_video_meta_unmap_vaapi_memory;
+    }
+
+    GST_META_FLAG_SET (vmeta, GST_META_FLAG_POOLED);
+  }
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+  if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) {
+    GstMeta *tex_meta = gst_buffer_add_texture_upload_meta (buffer);
+    if (tex_meta)
+      GST_META_FLAG_SET (tex_meta, GST_META_FLAG_POOLED);
+  }
+#endif
+
+  *out_buffer_ptr = buffer;
+  return GST_FLOW_OK;
+
+  /* ERRORS */
+error_no_allocator:
+  {
+    GST_ERROR_OBJECT (base_pool, "no GstAllocator in buffer pool");
+    return GST_FLOW_ERROR;
+  }
+error_create_meta:
+  {
+    GST_ERROR_OBJECT (base_pool, "failed to allocate vaapi video meta");
+    return GST_FLOW_ERROR;
+  }
+error_create_buffer:
+  {
+    GST_ERROR_OBJECT (base_pool, "failed to create video buffer");
+    gst_vaapi_video_meta_unref (meta);
+    return GST_FLOW_ERROR;
+  }
+error_create_memory:
+  {
+    GST_ERROR_OBJECT (base_pool, "failed to create video memory");
+    gst_buffer_unref (buffer);
+    gst_vaapi_video_meta_unref (meta);
+    return GST_FLOW_ERROR;
+  }
+}
+
+static GstFlowReturn
+gst_vaapi_video_buffer_pool_acquire_buffer (GstBufferPool * pool,
+    GstBuffer ** out_buffer_ptr, GstBufferPoolAcquireParams * params)
+{
+  GstVaapiVideoBufferPool *const base_pool = GST_VAAPI_VIDEO_BUFFER_POOL (pool);
+  GstVaapiVideoBufferPoolPrivate *const priv = base_pool->priv;
+  GstVaapiVideoBufferPoolAcquireParams *const priv_params =
+      (GstVaapiVideoBufferPoolAcquireParams *) params;
+  GstFlowReturn ret;
+  GstBuffer *buffer;
+  GstMemory *mem;
+  GstVaapiVideoMeta *meta;
+  GstVaapiSurface *surface;
+
+  ret =
+      GST_BUFFER_POOL_CLASS
+      (gst_vaapi_video_buffer_pool_parent_class)->acquire_buffer (pool, &buffer,
+      params);
+
+  if (!priv->use_dmabuf_memory || !params || !priv_params->proxy
+      || ret != GST_FLOW_OK) {
+    *out_buffer_ptr = buffer;
+    return ret;
+  }
+
+  /* Some pool users, such as decode, needs to acquire a buffer for a
+   * specified surface (via surface proxy). If not it is a DMABuf, we
+   * just replace the underlying surface proxy of buffer's
+   * GstVaapiVideoMeta. But in DMABuf case, the thing is a little bit
+   * more complicated:
+   *
+   * For DMABuf, GstMemory is-a GstFdMemory, which doesn't provide a
+   * way to change its FD, thus once created it's bound to a
+   * surface. On the other side, for performace reason, when the
+   * buffer is released, the buffer and its memory are cached in the
+   * buffer pool, and at next acquire_buffer() may still reuse a
+   * buffer and its memory. But the pushed surface by the decoder may
+   * be different from the one popped by the pool, so we need to
+   * replace the buffer's memory with the correct one. */
+  g_assert (gst_buffer_n_memory (buffer) == 1);
+
+  /* Update the underlying surface proxy */
+  meta = gst_buffer_get_vaapi_video_meta (buffer);
+  if (!meta) {
+    *out_buffer_ptr = buffer;
+    return GST_FLOW_ERROR;
+  }
+  gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy);
+
+  mem = vaapi_buffer_pool_lookup_dma_mem (base_pool, priv_params->proxy);
+  if (mem) {
+    if (mem == gst_buffer_peek_memory (buffer, 0)) {
+      gst_memory_unref (mem);
+      *out_buffer_ptr = buffer;
+      return GST_FLOW_OK;
+    }
+  } else {
+    /* Should be an unexported surface */
+    surface = GST_VAAPI_SURFACE_PROXY_SURFACE (priv_params->proxy);
+    g_assert (surface);
+    g_assert (gst_vaapi_surface_peek_buffer_proxy (surface) == NULL);
+    gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy);
+    mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta);
+    if (mem)
+      vaapi_buffer_pool_cache_dma_mem (base_pool, priv_params->proxy, mem);
+  }
+
+  if (mem) {
+    gst_buffer_replace_memory (buffer, 0, mem);
+    gst_buffer_unset_flags (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
+    *out_buffer_ptr = buffer;
+    return GST_FLOW_OK;
+  } else {
+    gst_buffer_unref (buffer);
+    *out_buffer_ptr = NULL;
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_vaapi_video_buffer_pool_reset_buffer (GstBufferPool * pool,
+    GstBuffer * buffer)
+{
+  GstMemory *const mem = gst_buffer_peek_memory (buffer, 0);
+  GstVaapiVideoMeta *meta;
+
+  /* Release the underlying surface proxy */
+  if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) {
+    gst_vaapi_video_memory_reset_surface (GST_VAAPI_VIDEO_MEMORY_CAST (mem));
+  } else if (!gst_vaapi_dmabuf_memory_holds_surface (mem)) {
+    /* If mem holds an internally created surface, don't reset it!
+     * While surface is passed, we should clear it to avoid wrong
+     * reference. */
+    meta = gst_buffer_get_vaapi_video_meta (buffer);
+    g_assert (meta);
+    gst_vaapi_video_meta_set_surface_proxy (meta, NULL);
+  }
+
+  GST_BUFFER_POOL_CLASS (gst_vaapi_video_buffer_pool_parent_class)->reset_buffer
+      (pool, buffer);
+}
+
+static void
+gst_vaapi_video_buffer_pool_class_init (GstVaapiVideoBufferPoolClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstBufferPoolClass *const pool_class = GST_BUFFER_POOL_CLASS (klass);
+
+  GST_DEBUG_CATEGORY_INIT (gst_debug_vaapivideopool,
+      "vaapivideopool", 0, "VA-API video pool");
+
+  object_class->finalize = gst_vaapi_video_buffer_pool_finalize;
+  object_class->set_property = gst_vaapi_video_buffer_pool_set_property;
+  object_class->get_property = gst_vaapi_video_buffer_pool_get_property;
+  pool_class->get_options = gst_vaapi_video_buffer_pool_get_options;
+  pool_class->set_config = gst_vaapi_video_buffer_pool_set_config;
+  pool_class->alloc_buffer = gst_vaapi_video_buffer_pool_alloc_buffer;
+  pool_class->acquire_buffer = gst_vaapi_video_buffer_pool_acquire_buffer;
+  pool_class->reset_buffer = gst_vaapi_video_buffer_pool_reset_buffer;
+
+  /**
+   * GstVaapiVideoBufferPool:display:
+   *
+   * The #GstVaapiDisplay this object is bound to.
+   */
+  g_object_class_install_property
+      (object_class,
+      PROP_DISPLAY,
+      g_param_spec_object ("display", "Display",
+          "The GstVaapiDisplay to use for this video pool",
+          GST_TYPE_VAAPI_DISPLAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gst_vaapi_video_buffer_pool_init (GstVaapiVideoBufferPool * pool)
+{
+  pool->priv = gst_vaapi_video_buffer_pool_get_instance_private (pool);
+  pool->priv->dma_mem_map = NULL;
+}
+
+GstBufferPool *
+gst_vaapi_video_buffer_pool_new (GstVaapiDisplay * display)
+{
+  return g_object_new (GST_VAAPI_TYPE_VIDEO_BUFFER_POOL,
+      "display", display, NULL);
+}
+
+/**
+ * gst_vaapi_video_buffer_pool_copy_buffer:
+ * @pool: a #GstVaapiVideoBufferPool
+ *
+ * Returns if the @pool force set of #GstVideoMeta. If so, the element
+ * should copy the generated buffer by the pool to a system allocated
+ * buffer. Otherwise, downstream could not display correctly the
+ * frame.
+ *
+ * Returns: %TRUE if #GstVideoMeta is forced.
+ **/
+gboolean
+gst_vaapi_video_buffer_pool_copy_buffer (GstBufferPool * pool)
+{
+  GstVaapiVideoBufferPool *va_pool = (GstVaapiVideoBufferPool *) pool;
+
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_BUFFER_POOL (pool), FALSE);
+
+  return va_pool->priv->forced_video_meta;
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobufferpool.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideobufferpool.h
new file mode 100644 (file)
index 0000000..23321fc
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ *  gstvaapivideobufferpool.h - Gstreamer/VA video buffer pool
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VIDEO_BUFFER_POOL_H
+#define GST_VAAPI_VIDEO_BUFFER_POOL_H
+
+#include <gst/video/gstvideopool.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapisurfaceproxy.h>
+
+G_BEGIN_DECLS
+
+#define GST_VAAPI_TYPE_VIDEO_BUFFER_POOL \
+  (gst_vaapi_video_buffer_pool_get_type ())
+#define GST_VAAPI_VIDEO_BUFFER_POOL(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_VAAPI_TYPE_VIDEO_BUFFER_POOL, \
+      GstVaapiVideoBufferPool))
+#define GST_VAAPI_VIDEO_BUFFER_POOL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_CAST ((klass), GST_VAAPI_TYPE_VIDEO_BUFFER_POOL, \
+      GstVaapiVideoBufferPoolClass))
+#define GST_VAAPI_IS_VIDEO_BUFFER_POOL(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_VAAPI_TYPE_VIDEO_BUFFER_POOL))
+#define GST_VAAPI_IS_VIDEO_BUFFER_POOL_CLASS(klass) \
+  (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_VAAPI_TYPE_VIDEO_BUFFER_POOL))
+
+typedef struct _GstVaapiVideoBufferPoolAcquireParams GstVaapiVideoBufferPoolAcquireParams;
+typedef struct _GstVaapiVideoBufferPool GstVaapiVideoBufferPool;
+typedef struct _GstVaapiVideoBufferPoolClass GstVaapiVideoBufferPoolClass;
+typedef struct _GstVaapiVideoBufferPoolPrivate GstVaapiVideoBufferPoolPrivate;
+
+/**
+ * GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META:
+ *
+ * An option that can be activated on bufferpool to request vaapi
+ * video metadata on buffers from the pool.
+ */
+#define GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META \
+  "GstBufferPoolOptionVaapiVideoMeta"
+
+/**
+ * GstVaapiVideoBufferPoolOption:
+ * @GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META:
+ * @GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT:
+ * @GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD:
+ *
+ * Helper enum to handle the buffer pool options using bit operation.
+ **/
+typedef enum
+{
+  GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META = (1u << 0),
+  GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT = (1u << 1),
+  GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD = (1u << 2),
+} GstVaapiVideoBufferPoolOption;
+
+/**
+ * GstVaapiVideoBufferPoolAcquireParams:
+ * @proxy: the #GstVaapiSurfaceProxy associated to the dmabuf-base
+ * memory
+ *
+ * Parameters passed to the gst_buffer_pool_acquire_buffer() function
+ * on a #GstVaapiVideoBufferPool, to control the allocation of the
+ * buffer.
+ *
+ * This is an extension of #GstBufferPoolAcquireParams
+ */
+struct _GstVaapiVideoBufferPoolAcquireParams
+{
+  GstBufferPoolAcquireParams parent_instance;
+
+  GstVaapiSurfaceProxy *proxy;
+};
+
+/**
+ * GstVaapiVideoBufferPool:
+ *
+ * A VA video buffer pool object.
+ */
+struct _GstVaapiVideoBufferPool
+{
+  GstBufferPool parent_instance;
+
+  /*< private >*/
+  GstVaapiVideoBufferPoolPrivate *priv;
+};
+
+/**
+ * GstVaapiVideoBufferPoolClass:
+ *
+ * A VA video buffer pool class.
+ */
+struct _GstVaapiVideoBufferPoolClass
+{
+  GstBufferPoolClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType
+gst_vaapi_video_buffer_pool_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GstBufferPool *
+gst_vaapi_video_buffer_pool_new (GstVaapiDisplay * display);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_video_buffer_pool_copy_buffer (GstBufferPool * pool);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_VIDEO_BUFFER_POOL_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideocontext.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideocontext.c
new file mode 100644 (file)
index 0000000..e2bbfb6
--- /dev/null
@@ -0,0 +1,357 @@
+/*
+ *  gstvaapivideocontext.c - GStreamer/VA video context
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *  Copyright (C) 2013 Igalia
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstcompat.h"
+#include "gstvaapivideocontext.h"
+#if USE_GST_GL_HELPERS
+# include <gst/gl/gl.h>
+#endif
+#if GST_VAAPI_USE_X11
+#include <gst/vaapi/gstvaapidisplay_x11.h>
+#endif
+#if GST_VAAPI_USE_WAYLAND
+#include <gst/vaapi/gstvaapidisplay_wayland.h>
+#endif
+#if GST_VAAPI_USE_DRM
+#include <gst/vaapi/gstvaapidisplay_drm.h>
+#endif
+
+GST_DEBUG_CATEGORY_STATIC (GST_CAT_CONTEXT);
+
+static void
+_init_context_debug (void)
+{
+#ifndef GST_DISABLE_GST_DEBUG
+  static gsize _init = 0;
+
+  if (g_once_init_enter (&_init)) {
+    GST_DEBUG_CATEGORY_GET (GST_CAT_CONTEXT, "GST_CONTEXT");
+    g_once_init_leave (&_init, 1);
+  }
+#endif
+}
+
+void
+gst_vaapi_video_context_set_display (GstContext * context,
+    GstVaapiDisplay * display)
+{
+  GstStructure *structure;
+
+  g_return_if_fail (context != NULL);
+
+  structure = gst_context_writable_structure (context);
+  gst_structure_set (structure, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME,
+      GST_TYPE_VAAPI_DISPLAY, display, NULL);
+  /* The outside user may access it as a generic Gobject. */
+  gst_structure_set (structure, "gst.vaapi.Display.GObject",
+      GST_TYPE_OBJECT, display, NULL);
+}
+
+GstContext *
+gst_vaapi_video_context_new_with_display (GstVaapiDisplay * display,
+    gboolean persistent)
+{
+  GstContext *context;
+
+  context = gst_context_new (GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME, persistent);
+  gst_vaapi_video_context_set_display (context, display);
+  return context;
+}
+
+gboolean
+gst_vaapi_video_context_get_display (GstContext * context, gboolean app_context,
+    GstVaapiDisplay ** display_ptr)
+{
+  const GstStructure *structure;
+  const gchar *type;
+  GstVaapiDisplay *display = NULL;
+
+  g_return_val_if_fail (GST_IS_CONTEXT (context), FALSE);
+
+  type = gst_context_get_context_type (context);
+
+  if (!g_strcmp0 (type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME)) {
+    structure = gst_context_get_structure (context);
+    return gst_structure_get (structure, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME,
+        GST_TYPE_VAAPI_DISPLAY, display_ptr, NULL);
+  }
+
+  if (app_context && !g_strcmp0 (type, GST_VAAPI_DISPLAY_APP_CONTEXT_TYPE_NAME)) {
+    VADisplay va_display = NULL;
+    structure = gst_context_get_structure (context);
+
+    if (gst_structure_get (structure, "va-display", G_TYPE_POINTER, &va_display,
+            NULL)) {
+#if GST_VAAPI_USE_X11
+      Display *x11_display = NULL;
+      if (gst_structure_get (structure, "x11-display", G_TYPE_POINTER,
+              &x11_display, NULL)) {
+        display =
+            gst_vaapi_display_x11_new_with_va_display (va_display, x11_display);
+      }
+#endif
+#if GST_VAAPI_USE_WAYLAND
+      if (!display) {
+        struct wl_display *wl_display = NULL;
+        if (gst_structure_get (structure, "wl-display", G_TYPE_POINTER,
+                &wl_display, NULL)) {
+          display =
+              gst_vaapi_display_wayland_new_with_va_display (va_display,
+              wl_display);
+        }
+      }
+#endif
+#if GST_VAAPI_USE_DRM
+      if (!display) {
+        gint fd = -1;
+        if (gst_structure_get (structure, "drm-device-fd", G_TYPE_INT, &fd,
+                NULL)) {
+          display = gst_vaapi_display_drm_new_with_va_display (va_display, fd);
+        }
+      }
+#endif
+
+      _init_context_debug ();
+
+      if (!display) {
+        GST_CAT_WARNING (GST_CAT_CONTEXT,
+            "Cannot create GstVaapiDisplay if only VADisplay is provided");
+        return FALSE;
+      }
+      GST_CAT_INFO (GST_CAT_CONTEXT,
+          "new display with context %" GST_PTR_FORMAT, display);
+      *display_ptr = display;
+      return TRUE;
+    }
+  }
+
+  return FALSE;
+}
+
+static gboolean
+context_pad_query (const GValue * item, GValue * value, gpointer user_data)
+{
+  GstPad *const pad = g_value_get_object (item);
+  GstQuery *const query = user_data;
+
+  if (gst_pad_peer_query (pad, query)) {
+    g_value_set_boolean (value, TRUE);
+    return FALSE;
+  }
+
+  _init_context_debug ();
+  GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, pad, "context pad peer query failed");
+  return TRUE;
+}
+
+static gboolean
+_gst_context_run_query (GstElement * element, GstQuery * query,
+    GstPadDirection direction)
+{
+  GstIteratorFoldFunction const func = context_pad_query;
+  GstIterator *it;
+  GValue res = { 0 };
+
+  g_value_init (&res, G_TYPE_BOOLEAN);
+  g_value_set_boolean (&res, FALSE);
+
+  /* Ask neighbour */
+  if (direction == GST_PAD_SRC)
+    it = gst_element_iterate_src_pads (element);
+  else
+    it = gst_element_iterate_sink_pads (element);
+
+  while (gst_iterator_fold (it, func, &res, query) == GST_ITERATOR_RESYNC)
+    gst_iterator_resync (it);
+  gst_iterator_free (it);
+
+  return g_value_get_boolean (&res);
+}
+
+static gboolean
+_gst_context_get_from_query (GstElement * element, GstQuery * query,
+    GstPadDirection direction)
+{
+  GstContext *ctxt;
+
+  if (!_gst_context_run_query (element, query, direction))
+    return FALSE;
+
+  gst_query_parse_context (query, &ctxt);
+  if (!ctxt)
+    return FALSE;
+
+  GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
+      "found context (%" GST_PTR_FORMAT ") in %s query", ctxt,
+      direction == GST_PAD_SRC ? "downstream" : "upstream");
+  gst_element_set_context (element, ctxt);
+  return TRUE;
+}
+
+static void
+_gst_context_query (GstElement * element, const gchar * context_type)
+{
+  GstQuery *query;
+  GstMessage *msg;
+
+  _init_context_debug ();
+
+  /* 2) Query downstream with GST_QUERY_CONTEXT for the context and
+     check if downstream already has a context of the specific
+     type */
+  /* 3) Query upstream with GST_QUERY_CONTEXT for the context and
+     check if upstream already has a context of the specific
+     type */
+  query = gst_query_new_context (context_type);
+  if (_gst_context_get_from_query (element, query, GST_PAD_SRC))
+    goto found;
+  if (_gst_context_get_from_query (element, query, GST_PAD_SINK))
+    goto found;
+
+  /* 4) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
+     the required context types and afterwards check if an
+     usable context was set now as in 1). The message could
+     be handled by the parent bins of the element and the
+     application. */
+  GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
+      "posting `need-context' message");
+  msg = gst_message_new_need_context (GST_OBJECT_CAST (element), context_type);
+  if (!gst_element_post_message (element, msg))
+    GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached");
+
+  /*
+   * Whomever responds to the need-context message performs a
+   * GstElement::set_context() with the required context in which the
+   * element is required to update the display_ptr
+   */
+
+found:
+  gst_query_unref (query);
+}
+
+static gboolean
+_gst_vaapi_sink_find_context (GstElement * element)
+{
+  GstQuery *query;
+  GstMessage *msg;
+  gboolean found;
+
+  /* 1. Query upstream for an already created GstVaapiDisplay */
+  query = gst_query_new_context (GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME);
+  found = _gst_context_get_from_query (element, query, GST_PAD_SINK);
+  gst_query_unref (query);
+  if (found)
+    return TRUE;
+
+  /* 2. Post a GST_MESSAGE_NEED_CONTEXT message on the bus with a
+   * gst.vaapi.app.Display context from the application */
+  msg = gst_message_new_need_context (GST_OBJECT_CAST (element),
+      GST_VAAPI_DISPLAY_APP_CONTEXT_TYPE_NAME);
+  if (!gst_element_post_message (element, msg)) {
+    _init_context_debug ();
+    GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached");
+  }
+
+  return FALSE;
+}
+
+gboolean
+gst_vaapi_video_context_prepare (GstElement * element,
+    GstVaapiDisplay ** display_ptr)
+{
+  g_return_val_if_fail (element != NULL, FALSE);
+  g_return_val_if_fail (display_ptr != NULL, FALSE);
+
+  /*  1) Check if the element already has a context of the specific
+   *     type.
+   */
+  if (*display_ptr) {
+    GST_LOG_OBJECT (element, "already have a display %" GST_PTR_FORMAT,
+        *display_ptr);
+    return TRUE;
+  }
+
+  if (GST_IS_VIDEO_SINK (element)) {
+    if (!_gst_vaapi_sink_find_context (element) && *display_ptr) {
+      /* Propagate if display was created from application */
+      gst_vaapi_video_context_propagate (element, *display_ptr);
+    }
+  } else {
+    _gst_context_query (element, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME);
+  }
+
+  if (*display_ptr) {
+    GST_LOG_OBJECT (element, "found a display %" GST_PTR_FORMAT, *display_ptr);
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/* 5) Create a context by itself and post a GST_MESSAGE_HAVE_CONTEXT message
+      on the bus. */
+void
+gst_vaapi_video_context_propagate (GstElement * element,
+    GstVaapiDisplay * display)
+{
+  GstContext *context;
+  GstMessage *msg;
+
+  context = gst_vaapi_video_context_new_with_display (display, FALSE);
+  gst_element_set_context (element, context);
+
+  _init_context_debug ();
+  GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element,
+      "posting `have-context' (%p) message with display %" GST_PTR_FORMAT,
+      context, display);
+  msg = gst_message_new_have_context (GST_OBJECT_CAST (element), context);
+  if (!gst_element_post_message (element, msg))
+    GST_CAT_INFO_OBJECT (GST_CAT_CONTEXT, element, "No bus attached");
+}
+
+/**
+ * gst_vaapi_find_gl_local_context:
+ * @element: the #GstElement where the search begins
+ * @gl_context_ptr: the pointer where the GstGL context is going to be
+ * stored
+ *
+ * Query the pipeline, downstream and upstream for a GstGL context
+ *
+ * Returns: %TRUE if found; otherwise %FALSE
+ **/
+gboolean
+gst_vaapi_find_gl_local_context (GstElement * element,
+    GstObject ** gl_context_ptr)
+{
+#if USE_GST_GL_HELPERS
+  GstGLContext **context_ptr = (GstGLContext **) gl_context_ptr;
+
+  if (gst_gl_query_local_gl_context (element, GST_PAD_SRC, context_ptr))
+    return TRUE;
+  if (gst_gl_query_local_gl_context (element, GST_PAD_SINK, context_ptr))
+    return TRUE;
+#endif
+  return FALSE;
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideocontext.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideocontext.h
new file mode 100644 (file)
index 0000000..8577ca4
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ *  gstvaapivideocontext.h - GStreamer/VA video context
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *  Copyright (C) 2013 Igalia
+ *    Author: Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VIDEO_CONTEXT_H
+#define GST_VAAPI_VIDEO_CONTEXT_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+
+#define GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME "gst.vaapi.Display"
+#define GST_VAAPI_DISPLAY_APP_CONTEXT_TYPE_NAME "gst.vaapi.app.Display"
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_context_set_display (GstContext * context,
+    GstVaapiDisplay * display);
+
+G_GNUC_INTERNAL
+GstContext *
+gst_vaapi_video_context_new_with_display (GstVaapiDisplay * display,
+    gboolean persistent);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_video_context_get_display (GstContext * context, gboolean app_context,
+    GstVaapiDisplay ** display_ptr);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_video_context_prepare (GstElement * element,
+    GstVaapiDisplay ** display_ptr);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_context_propagate (GstElement * element,
+    GstVaapiDisplay * display);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_find_gl_local_context (GstElement * element,
+    GstObject ** gl_context_ptr);
+
+#endif /* GST_VAAPI_VIDEO_CONTEXT_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideomemory.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideomemory.c
new file mode 100644 (file)
index 0000000..8c1f588
--- /dev/null
@@ -0,0 +1,1475 @@
+/*
+ *  gstvaapivideomemory.c - Gstreamer/VA video memory
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstcompat.h"
+#include <unistd.h>
+#include <gst/vaapi/gstvaapisurface_drm.h>
+#include <gst/vaapi/gstvaapisurfacepool.h>
+#include <gst/vaapi/gstvaapiimagepool.h>
+#include "gstvaapivideomemory.h"
+#include "gstvaapipluginutil.h"
+
+GST_DEBUG_CATEGORY_STATIC (CAT_PERFORMANCE);
+GST_DEBUG_CATEGORY_STATIC (gst_debug_vaapivideomemory);
+#define GST_CAT_DEFAULT gst_debug_vaapivideomemory
+
+#ifndef GST_VIDEO_INFO_FORMAT_STRING
+#define GST_VIDEO_INFO_FORMAT_STRING(vip) \
+  gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (vip))
+#endif
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVaapiVideoMemory                                              --- */
+/* ------------------------------------------------------------------------ */
+
+static void gst_vaapi_video_memory_reset_image (GstVaapiVideoMemory * mem);
+
+static void
+_init_performance_debug (void)
+{
+#ifndef GST_DISABLE_GST_DEBUG
+  static gsize _init = 0;
+
+  if (g_once_init_enter (&_init)) {
+    GST_DEBUG_CATEGORY_GET (CAT_PERFORMANCE, "GST_PERFORMANCE");
+    g_once_init_leave (&_init, 1);
+  }
+#endif
+}
+
+static void
+_init_vaapi_video_memory_debug (void)
+{
+#ifndef GST_DISABLE_GST_DEBUG
+  static gsize _init = 0;
+
+  if (g_once_init_enter (&_init)) {
+    GST_DEBUG_CATEGORY_INIT (gst_debug_vaapivideomemory, "vaapivideomemory", 0,
+        "VA-API video memory allocator");
+    g_once_init_leave (&_init, 1);
+  }
+#endif
+}
+
+static inline void
+reset_image_usage (GstVaapiImageUsageFlags * flag)
+{
+  _init_performance_debug ();
+  GST_CAT_INFO (CAT_PERFORMANCE, "derive image failed, fallbacking to copy");
+  *flag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
+}
+
+static inline gboolean
+use_native_formats (GstVaapiImageUsageFlags flag)
+{
+  return flag == GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
+}
+
+static inline gboolean
+use_direct_rendering (GstVaapiImageUsageFlags flag)
+{
+  return flag == GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER;
+}
+
+static inline gboolean
+use_direct_uploading (GstVaapiImageUsageFlags flag)
+{
+  return flag == GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD;
+}
+
+static guchar *
+get_image_data (GstVaapiImage * image)
+{
+  guchar *data;
+  VAImage va_image;
+
+  data = gst_vaapi_image_get_plane (image, 0);
+  if (!data || !gst_vaapi_image_get_image (image, &va_image))
+    return NULL;
+
+  data -= va_image.offsets[0];
+  return data;
+}
+
+static GstVaapiImage *
+new_image (GstVaapiDisplay * display, const GstVideoInfo * vip)
+{
+  if (!GST_VIDEO_INFO_WIDTH (vip) || !GST_VIDEO_INFO_HEIGHT (vip))
+    return NULL;
+  return gst_vaapi_image_new (display, GST_VIDEO_INFO_FORMAT (vip),
+      GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip));
+}
+
+static gboolean
+ensure_image (GstVaapiVideoMemory * mem)
+{
+  if (!mem->image && !use_native_formats (mem->usage_flag)) {
+    mem->image = gst_vaapi_surface_derive_image (mem->surface);
+    if (!mem->image) {
+      reset_image_usage (&mem->usage_flag);
+    } else if (gst_vaapi_surface_get_format (mem->surface) !=
+        GST_VIDEO_INFO_FORMAT (mem->image_info)) {
+      gst_mini_object_replace ((GstMiniObject **) & mem->image, NULL);
+      reset_image_usage (&mem->usage_flag);
+    }
+  }
+
+  if (!mem->image) {
+    GstVaapiVideoAllocator *const allocator =
+        GST_VAAPI_VIDEO_ALLOCATOR_CAST (GST_MEMORY_CAST (mem)->allocator);
+
+    mem->image = gst_vaapi_video_pool_get_object (allocator->image_pool);
+    if (!mem->image)
+      return FALSE;
+  }
+  gst_vaapi_video_meta_set_image (mem->meta, mem->image);
+  return TRUE;
+}
+
+static gboolean
+ensure_image_is_current (GstVaapiVideoMemory * mem)
+{
+  if (!use_native_formats (mem->usage_flag))
+    return TRUE;
+
+  if (!GST_VAAPI_VIDEO_MEMORY_FLAG_IS_SET (mem,
+          GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT)) {
+    if (!gst_vaapi_surface_get_image (mem->surface, mem->image))
+      return FALSE;
+
+    GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem,
+        GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT);
+  }
+  return TRUE;
+}
+
+static GstVaapiSurfaceProxy *
+new_surface_proxy (GstVaapiVideoMemory * mem)
+{
+  GstVaapiVideoAllocator *const allocator =
+      GST_VAAPI_VIDEO_ALLOCATOR_CAST (GST_MEMORY_CAST (mem)->allocator);
+
+  return
+      gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL
+      (allocator->surface_pool));
+}
+
+static gboolean
+ensure_surface (GstVaapiVideoMemory * mem)
+{
+  if (!mem->proxy) {
+    gst_vaapi_surface_proxy_replace (&mem->proxy,
+        gst_vaapi_video_meta_get_surface_proxy (mem->meta));
+
+    if (!mem->proxy) {
+      mem->proxy = new_surface_proxy (mem);
+      if (!mem->proxy)
+        return FALSE;
+      gst_vaapi_video_meta_set_surface_proxy (mem->meta, mem->proxy);
+    }
+  }
+  mem->surface = GST_VAAPI_SURFACE_PROXY_SURFACE (mem->proxy);
+  return mem->surface != NULL;
+}
+
+static gboolean
+ensure_surface_is_current (GstVaapiVideoMemory * mem)
+{
+  if (!use_native_formats (mem->usage_flag))
+    return TRUE;
+
+  if (!GST_VAAPI_VIDEO_MEMORY_FLAG_IS_SET (mem,
+          GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT)) {
+    if (GST_VAAPI_VIDEO_MEMORY_FLAG_IS_SET (mem,
+            GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT)
+        && !gst_vaapi_surface_put_image (mem->surface, mem->image))
+      return FALSE;
+
+    GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem,
+        GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT);
+  }
+  return TRUE;
+}
+
+static inline gboolean
+map_vaapi_memory (GstVaapiVideoMemory * mem, GstMapFlags flags)
+{
+  if (!ensure_surface (mem))
+    goto error_no_surface;
+  if (!ensure_image (mem))
+    goto error_no_image;
+
+  /* Load VA image from surface only for read flag since it returns
+   * raw pixels */
+  if ((flags & GST_MAP_READ) && !ensure_image_is_current (mem))
+    goto error_no_current_image;
+
+  if (!gst_vaapi_image_map (mem->image))
+    goto error_map_image;
+
+  /* Mark surface as dirty and expect updates from image */
+  if (flags & GST_MAP_WRITE)
+    GST_VAAPI_VIDEO_MEMORY_FLAG_UNSET (mem,
+        GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT);
+
+  return TRUE;
+
+error_no_surface:
+  {
+    const GstVideoInfo *const vip = mem->surface_info;
+    GST_ERROR ("failed to extract VA surface of size %ux%u and format %s",
+        GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip),
+        GST_VIDEO_INFO_FORMAT_STRING (vip));
+    return FALSE;
+  }
+error_no_image:
+  {
+    const GstVideoInfo *const vip = mem->image_info;
+    GST_ERROR ("failed to extract VA image of size %ux%u and format %s",
+        GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip),
+        GST_VIDEO_INFO_FORMAT_STRING (vip));
+    return FALSE;
+  }
+error_no_current_image:
+  {
+    GST_ERROR ("failed to make image current");
+    return FALSE;
+  }
+error_map_image:
+  {
+    GST_ERROR ("failed to map image %" GST_VAAPI_ID_FORMAT,
+        GST_VAAPI_ID_ARGS (gst_vaapi_image_get_id (mem->image)));
+    return FALSE;
+  }
+}
+
+static inline void
+unmap_vaapi_memory (GstVaapiVideoMemory * mem, GstMapFlags flags)
+{
+  gst_vaapi_image_unmap (mem->image);
+
+  if (flags & GST_MAP_WRITE) {
+    GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem,
+        GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT);
+  }
+
+  if (!use_native_formats (mem->usage_flag)) {
+    gst_vaapi_video_meta_set_image (mem->meta, NULL);
+    gst_vaapi_video_memory_reset_image (mem);
+  }
+}
+
+gboolean
+gst_video_meta_map_vaapi_memory (GstVideoMeta * meta, guint plane,
+    GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags)
+{
+  gboolean ret = FALSE;
+  GstAllocator *allocator;
+  GstVaapiVideoMemory *const mem =
+      GST_VAAPI_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
+
+  g_return_val_if_fail (mem, FALSE);
+  g_return_val_if_fail (mem->meta, FALSE);
+
+  allocator = GST_MEMORY_CAST (mem)->allocator;
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), FALSE);
+
+  g_mutex_lock (&mem->lock);
+  if (mem->map_type && mem->map_type != GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR)
+    goto error_incompatible_map;
+
+  /* Map for writing */
+  if (mem->map_count == 0) {
+    if (!map_vaapi_memory (mem, flags))
+      goto out;
+    mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR;
+  }
+  mem->map_count++;
+
+  *data = gst_vaapi_image_get_plane (mem->image, plane);
+  *stride = gst_vaapi_image_get_pitch (mem->image, plane);
+  info->flags = flags;
+  ret = (*data != NULL);
+
+out:
+  g_mutex_unlock (&mem->lock);
+  return ret;
+
+  /* ERRORS */
+error_incompatible_map:
+  {
+    GST_ERROR ("incompatible map type (%d)", mem->map_type);
+    goto out;
+  }
+}
+
+gboolean
+gst_video_meta_unmap_vaapi_memory (GstVideoMeta * meta, guint plane,
+    GstMapInfo * info)
+{
+  GstAllocator *allocator;
+  GstVaapiVideoMemory *const mem =
+      GST_VAAPI_VIDEO_MEMORY_CAST (gst_buffer_peek_memory (meta->buffer, 0));
+
+  g_return_val_if_fail (mem, FALSE);
+  g_return_val_if_fail (mem->meta, FALSE);
+  g_return_val_if_fail (mem->surface, FALSE);
+  g_return_val_if_fail (mem->image, FALSE);
+
+  allocator = GST_MEMORY_CAST (mem)->allocator;
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), FALSE);
+
+  g_mutex_lock (&mem->lock);
+  if (--mem->map_count == 0) {
+    mem->map_type = 0;
+
+    /* Unmap VA image used for read/writes */
+    if (info->flags & GST_MAP_READWRITE)
+      unmap_vaapi_memory (mem, info->flags);
+  }
+  g_mutex_unlock (&mem->lock);
+  return TRUE;
+}
+
+GstMemory *
+gst_vaapi_video_memory_new (GstAllocator * base_allocator,
+    GstVaapiVideoMeta * meta)
+{
+  GstVaapiVideoAllocator *const allocator =
+      GST_VAAPI_VIDEO_ALLOCATOR_CAST (base_allocator);
+  const GstVideoInfo *vip;
+  GstVaapiVideoMemory *mem;
+
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), NULL);
+
+  mem = g_slice_new (GstVaapiVideoMemory);
+  if (!mem)
+    return NULL;
+
+  vip = &allocator->image_info;
+  gst_memory_init (&mem->parent_instance, GST_MEMORY_FLAG_NO_SHARE,
+      base_allocator, NULL, GST_VIDEO_INFO_SIZE (vip), 0,
+      0, GST_VIDEO_INFO_SIZE (vip));
+
+  mem->proxy = NULL;
+  mem->surface_info = &allocator->surface_info;
+  mem->surface = NULL;
+  mem->image_info = &allocator->image_info;
+  mem->image = NULL;
+  mem->meta = meta ? gst_vaapi_video_meta_ref (meta) : NULL;
+  mem->map_type = 0;
+  mem->map_count = 0;
+  mem->map_surface_id = VA_INVALID_ID;
+  mem->usage_flag = allocator->usage_flag;
+  g_mutex_init (&mem->lock);
+
+  GST_VAAPI_VIDEO_MEMORY_FLAG_SET (mem,
+      GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT);
+  return GST_MEMORY_CAST (mem);
+}
+
+void
+gst_vaapi_video_memory_reset_image (GstVaapiVideoMemory * mem)
+{
+  GstVaapiVideoAllocator *const allocator =
+      GST_VAAPI_VIDEO_ALLOCATOR_CAST (GST_MEMORY_CAST (mem)->allocator);
+
+  if (!use_native_formats (mem->usage_flag))
+    gst_mini_object_replace ((GstMiniObject **) & mem->image, NULL);
+  else if (mem->image) {
+    gst_vaapi_video_pool_put_object (allocator->image_pool, mem->image);
+    mem->image = NULL;
+  }
+
+  /* Don't synchronize to surface, this shall have happened during
+   * unmaps */
+  GST_VAAPI_VIDEO_MEMORY_FLAG_UNSET (mem,
+      GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT);
+}
+
+void
+gst_vaapi_video_memory_reset_surface (GstVaapiVideoMemory * mem)
+{
+  mem->surface = NULL;
+  gst_vaapi_video_memory_reset_image (mem);
+  gst_vaapi_surface_proxy_replace (&mem->proxy, NULL);
+  if (mem->meta)
+    gst_vaapi_video_meta_set_surface_proxy (mem->meta, NULL);
+
+  GST_VAAPI_VIDEO_MEMORY_FLAG_UNSET (mem,
+      GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT);
+}
+
+gboolean
+gst_vaapi_video_memory_sync (GstVaapiVideoMemory * mem)
+{
+  g_return_val_if_fail (mem, FALSE);
+
+  return ensure_surface_is_current (mem);
+}
+
+static gpointer
+gst_vaapi_video_memory_map (GstMemory * base_mem, gsize maxsize, guint flags)
+{
+  gpointer data = NULL;
+  GstVaapiVideoMemory *const mem = GST_VAAPI_VIDEO_MEMORY_CAST (base_mem);
+
+  g_return_val_if_fail (mem, NULL);
+  g_return_val_if_fail (mem->meta, NULL);
+
+  g_mutex_lock (&mem->lock);
+  if (mem->map_count == 0) {
+    switch (flags & (GST_MAP_READWRITE | GST_MAP_VAAPI)) {
+      case 0:
+      case GST_MAP_VAAPI:
+        // No flags set: return a GstVaapiSurfaceProxy
+        gst_vaapi_surface_proxy_replace (&mem->proxy,
+            gst_vaapi_video_meta_get_surface_proxy (mem->meta));
+        if (!mem->proxy)
+          goto error_no_surface_proxy;
+        if (!ensure_surface_is_current (mem))
+          goto error_no_current_surface;
+        mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE;
+        break;
+      case GST_MAP_READ:
+        if (!map_vaapi_memory (mem, flags))
+          goto out;
+        mem->map_type = GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR;
+        break;
+      default:
+        goto error_unsupported_map;
+    }
+  }
+
+  switch (mem->map_type) {
+    case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE:
+      if (!mem->proxy)
+        goto error_no_surface_proxy;
+
+      if (flags == GST_MAP_VAAPI) {
+        mem->map_surface_id = GST_VAAPI_SURFACE_PROXY_SURFACE_ID (mem->proxy);
+        if (mem->map_surface_id == VA_INVALID_ID)
+          goto error_no_current_surface;
+
+        data = &mem->map_surface_id;
+      } else {
+        data = mem->proxy;
+      }
+      break;
+    case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR:
+      if (!mem->image)
+        goto error_no_image;
+      data = get_image_data (mem->image);
+      break;
+    default:
+      goto error_unsupported_map_type;
+  }
+  mem->map_count++;
+
+out:
+  g_mutex_unlock (&mem->lock);
+  return data;
+
+  /* ERRORS */
+error_unsupported_map:
+  {
+    GST_ERROR ("unsupported map flags (0x%x)", flags);
+    goto out;
+  }
+error_unsupported_map_type:
+  {
+    GST_ERROR ("unsupported map type (%d)", mem->map_type);
+    goto out;
+  }
+error_no_surface_proxy:
+  {
+    GST_ERROR ("failed to extract GstVaapiSurfaceProxy from video meta");
+    goto out;
+  }
+error_no_current_surface:
+  {
+    GST_ERROR ("failed to make surface current");
+    goto out;
+  }
+error_no_image:
+  {
+    GST_ERROR ("failed to extract VA image from video buffer");
+    goto out;
+  }
+}
+
+static void
+gst_vaapi_video_memory_unmap_full (GstMemory * base_mem, GstMapInfo * info)
+{
+  GstVaapiVideoMemory *const mem = GST_VAAPI_VIDEO_MEMORY_CAST (base_mem);
+
+  g_mutex_lock (&mem->lock);
+  if (mem->map_count == 1) {
+    switch (mem->map_type) {
+      case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE:
+        mem->map_surface_id = VA_INVALID_ID;
+        gst_vaapi_surface_proxy_replace (&mem->proxy, NULL);
+        break;
+      case GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR:
+        unmap_vaapi_memory (mem, info->flags);
+        break;
+      default:
+        goto error_incompatible_map;
+    }
+    mem->map_type = 0;
+  }
+  mem->map_count--;
+
+out:
+  g_mutex_unlock (&mem->lock);
+  return;
+
+  /* ERRORS */
+error_incompatible_map:
+  {
+    GST_ERROR ("incompatible map type (%d)", mem->map_type);
+    goto out;
+  }
+}
+
+static GstMemory *
+gst_vaapi_video_memory_copy (GstMemory * base_mem, gssize offset, gssize size)
+{
+  GstVaapiVideoMemory *const mem = GST_VAAPI_VIDEO_MEMORY_CAST (base_mem);
+  GstVaapiVideoMeta *meta;
+  GstAllocator *allocator;
+  GstMemory *out_mem;
+  gsize maxsize;
+
+  g_return_val_if_fail (mem, NULL);
+  g_return_val_if_fail (mem->meta, NULL);
+
+  allocator = base_mem->allocator;
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_ALLOCATOR (allocator), FALSE);
+
+  /* XXX: this implements a soft-copy, i.e. underlying VA surfaces
+     are not copied */
+  (void) gst_memory_get_sizes (base_mem, NULL, &maxsize);
+  if (offset != 0 || (size != -1 && (gsize) size != maxsize))
+    goto error_unsupported;
+
+  if (!ensure_surface_is_current (mem))
+    goto error_no_current_surface;
+
+  meta = gst_vaapi_video_meta_copy (mem->meta);
+  if (!meta)
+    goto error_allocate_memory;
+
+  out_mem = gst_vaapi_video_memory_new (allocator, meta);
+  gst_vaapi_video_meta_unref (meta);
+  if (!out_mem)
+    goto error_allocate_memory;
+  return out_mem;
+
+  /* ERRORS */
+error_no_current_surface:
+  {
+    GST_ERROR ("failed to make surface current");
+    return NULL;
+  }
+error_unsupported:
+  {
+    GST_ERROR ("failed to copy partial memory (unsupported operation)");
+    return NULL;
+  }
+error_allocate_memory:
+  {
+    GST_ERROR ("failed to allocate GstVaapiVideoMemory copy");
+    return NULL;
+  }
+}
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVaapiVideoAllocator                                           --- */
+/* ------------------------------------------------------------------------ */
+
+G_DEFINE_TYPE (GstVaapiVideoAllocator, gst_vaapi_video_allocator,
+    GST_TYPE_ALLOCATOR);
+
+static void
+gst_vaapi_video_allocator_free (GstAllocator * allocator, GstMemory * base_mem)
+{
+  GstVaapiVideoMemory *const mem = GST_VAAPI_VIDEO_MEMORY_CAST (base_mem);
+
+  mem->surface = NULL;
+  gst_vaapi_video_memory_reset_image (mem);
+  gst_vaapi_surface_proxy_replace (&mem->proxy, NULL);
+  gst_vaapi_video_meta_replace (&mem->meta, NULL);
+  g_mutex_clear (&mem->lock);
+  g_slice_free (GstVaapiVideoMemory, mem);
+}
+
+static void
+gst_vaapi_video_allocator_finalize (GObject * object)
+{
+  GstVaapiVideoAllocator *const allocator =
+      GST_VAAPI_VIDEO_ALLOCATOR_CAST (object);
+
+  gst_vaapi_video_pool_replace (&allocator->surface_pool, NULL);
+  gst_vaapi_video_pool_replace (&allocator->image_pool, NULL);
+
+  G_OBJECT_CLASS (gst_vaapi_video_allocator_parent_class)->finalize (object);
+}
+
+static void
+gst_vaapi_video_allocator_class_init (GstVaapiVideoAllocatorClass * klass)
+{
+  GObjectClass *const object_class = G_OBJECT_CLASS (klass);
+  GstAllocatorClass *const allocator_class = GST_ALLOCATOR_CLASS (klass);
+
+  _init_vaapi_video_memory_debug ();
+
+  object_class->finalize = gst_vaapi_video_allocator_finalize;
+  allocator_class->free = gst_vaapi_video_allocator_free;
+}
+
+static void
+gst_vaapi_video_allocator_init (GstVaapiVideoAllocator * allocator)
+{
+  GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
+
+  base_allocator->mem_type = GST_VAAPI_VIDEO_MEMORY_NAME;
+  base_allocator->mem_map = gst_vaapi_video_memory_map;
+  base_allocator->mem_unmap_full = gst_vaapi_video_memory_unmap_full;
+  base_allocator->mem_copy = gst_vaapi_video_memory_copy;
+
+  GST_OBJECT_FLAG_SET (allocator, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+}
+
+static gboolean
+gst_video_info_update_from_image (GstVideoInfo * vip, GstVaapiImage * image)
+{
+  GstVideoFormat format;
+  const guchar *data;
+  guint i, num_planes, data_size, width, height;
+
+  /* Reset format from image */
+  format = gst_vaapi_image_get_format (image);
+  gst_vaapi_image_get_size (image, &width, &height);
+  gst_video_info_set_format (vip, format, width, height);
+
+  num_planes = gst_vaapi_image_get_plane_count (image);
+  g_return_val_if_fail (num_planes == GST_VIDEO_INFO_N_PLANES (vip), FALSE);
+
+  /* Determine the base data pointer */
+  data = get_image_data (image);
+  g_return_val_if_fail (data != NULL, FALSE);
+  data_size = gst_vaapi_image_get_data_size (image);
+
+  /* Check that we don't have disjoint planes */
+  for (i = 0; i < num_planes; i++) {
+    const guchar *const plane = gst_vaapi_image_get_plane (image, i);
+    if (plane - data > data_size)
+      return FALSE;
+  }
+
+  /* Update GstVideoInfo structure */
+  for (i = 0; i < num_planes; i++) {
+    const guchar *const plane = gst_vaapi_image_get_plane (image, i);
+    GST_VIDEO_INFO_PLANE_OFFSET (vip, i) = plane - data;
+    GST_VIDEO_INFO_PLANE_STRIDE (vip, i) = gst_vaapi_image_get_pitch (image, i);
+  }
+  GST_VIDEO_INFO_SIZE (vip) = data_size;
+  return TRUE;
+}
+
+static gboolean
+gst_video_info_update_from_surface (GstVideoInfo * vip,
+    GstVaapiSurface * surface)
+{
+  GstVaapiImage *image;
+  gboolean ret;
+
+  ret = FALSE;
+  image = gst_vaapi_surface_derive_image (surface);
+  if (!image)
+    goto error_no_derive_image;
+  if (!gst_vaapi_image_map (image))
+    goto error_cannot_map;
+  ret = gst_video_info_update_from_image (vip, image);
+  gst_vaapi_image_unmap (image);
+
+bail:
+  gst_vaapi_image_unref (image);
+  return ret;
+
+  /* ERRORS */
+error_no_derive_image:
+  {
+    GST_INFO ("Cannot create a VA derived image from surface %p", surface);
+    return FALSE;
+  }
+error_cannot_map:
+  {
+    GST_ERROR ("Cannot map VA derived image %p", image);
+    goto bail;
+  }
+}
+
+#ifndef GST_DISABLE_GST_DEBUG
+static const gchar *
+gst_vaapi_image_usage_flags_to_string (GstVaapiImageUsageFlags usage_flag)
+{
+  switch (usage_flag) {
+    case GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS:
+      return "native uploading";
+    case GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER:
+      return "direct rendering";
+    case GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD:
+      return "direct uploading";
+    default:
+      return "unknown";
+  }
+}
+#endif
+
+static inline gboolean
+allocator_configure_surface_try_specified_format (GstVaapiDisplay * display,
+    const GstVideoInfo * allocation_info, GstVaapiImageUsageFlags usage_flag,
+    guint surface_alloc_flag, GstVideoInfo * ret_surface_info,
+    GstVaapiImageUsageFlags * ret_usage_flag)
+{
+  GstVaapiImageUsageFlags rflag;
+  GstVaapiSurface *surface;
+  GstVideoInfo sinfo, rinfo;
+
+  /* Try to create a surface with the given allocation info */
+  surface =
+      gst_vaapi_surface_new_full (display, allocation_info, surface_alloc_flag);
+  if (!surface)
+    return FALSE;
+
+  /* surface created and just native format usage was requested */
+  if (use_native_formats (usage_flag)) {
+    rflag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
+    rinfo = *allocation_info;
+    goto out;
+  }
+
+  /* Further checks whether that surface can support direct
+   * upload/render */
+  if (gst_video_info_update_from_surface (&sinfo, surface)) {
+    if (GST_VIDEO_INFO_FORMAT (&sinfo) ==
+        GST_VIDEO_INFO_FORMAT (allocation_info)) {
+      /* Set the correct flag */
+      if (use_direct_rendering (usage_flag)
+          && !use_direct_uploading (usage_flag)) {
+        rflag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER;
+      } else if (!use_direct_rendering (usage_flag)
+          && use_direct_uploading (usage_flag)) {
+        rflag = GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD;
+      } else {
+        g_assert_not_reached ();
+      }
+    } else {
+      /* It shouldn't happen, but still it's possible. Just use
+       * native. */
+      GST_FIXME ("Got a derive image with different format!");
+      rflag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
+    }
+
+    rinfo = sinfo;
+    goto out;
+  }
+
+  /* Can not derive image or not the same format, don't use derived
+     images, just fallback to use native */
+  rflag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
+  rinfo = *allocation_info;
+
+out:
+  gst_vaapi_surface_unref (surface);
+
+  *ret_surface_info = rinfo;
+  *ret_usage_flag = rflag;
+  return TRUE;
+}
+
+static inline gboolean
+allocator_configure_surface_try_other_format (GstVaapiDisplay * display,
+    const GstVideoInfo * allocation_info, GstVideoInfo * ret_surface_info)
+{
+  GstVaapiSurface *surface;
+  GstVideoFormat fmt;
+  GstVideoInfo sinfo;
+
+  /* Find a best native surface format if possible */
+  fmt = gst_vaapi_video_format_get_best_native
+      (GST_VIDEO_INFO_FORMAT (allocation_info));
+  if (fmt == GST_VIDEO_FORMAT_UNKNOWN
+      || fmt == GST_VIDEO_INFO_FORMAT (allocation_info))
+    goto error_invalid_format;
+
+  /* create a info with "best native" format */
+  gst_video_info_set_format (&sinfo, fmt,
+      GST_VIDEO_INFO_WIDTH (allocation_info),
+      GST_VIDEO_INFO_HEIGHT (allocation_info));
+
+  /* try it */
+  surface = gst_vaapi_surface_new_full (display, &sinfo, 0);
+  if (!surface)
+    goto error_no_surface;
+  gst_vaapi_surface_unref (surface);
+
+  *ret_surface_info = sinfo;
+  return TRUE;
+
+  /* ERRORS */
+error_invalid_format:
+  {
+    GST_ERROR ("Cannot handle format %s",
+        GST_VIDEO_INFO_FORMAT_STRING (allocation_info));
+    return FALSE;
+  }
+error_no_surface:
+  {
+    GST_ERROR ("Cannot create a VA Surface");
+    return FALSE;
+  }
+}
+
+static inline gboolean
+allocator_configure_surface_info (GstVaapiDisplay * display,
+    GstVaapiVideoAllocator * allocator, GstVaapiImageUsageFlags req_usage_flag,
+    guint surface_alloc_flags)
+{
+  GstVaapiImageUsageFlags usage_flag;
+  GstVideoInfo allocation_info, surface_info;
+
+  /* get rid of possible encoded format and assume NV12 */
+  allocation_info = allocator->allocation_info;
+  gst_video_info_force_nv12_if_encoded (&allocation_info);
+
+  /* Step1: Try the specified format and flag. May fallback to native if
+     direct upload/rendering is unavailable. */
+  if (allocator_configure_surface_try_specified_format (display,
+          &allocation_info, req_usage_flag, surface_alloc_flags,
+          &surface_info, &usage_flag)) {
+    allocator->usage_flag = usage_flag;
+    allocator->surface_info = surface_info;
+    goto success;
+  }
+
+  /* Step2: Try other surface format. Because format is different,
+     direct upload/rendering is unavailable, always use native */
+  if (allocator_configure_surface_try_other_format (display, &allocation_info,
+          &surface_info)) {
+    allocator->usage_flag = GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS;
+    allocator->surface_info = surface_info;
+    goto success;
+  }
+
+  GST_INFO_OBJECT (allocator, "Failed to configure the video format: %s"
+      " with usage flag: %s",
+      GST_VIDEO_INFO_FORMAT_STRING (&allocator->allocation_info),
+      gst_vaapi_image_usage_flags_to_string (req_usage_flag));
+  return FALSE;
+
+success:
+  GST_DEBUG_OBJECT (allocator, "success to set the surface format %s"
+      " for video format %s with %s",
+      GST_VIDEO_INFO_FORMAT_STRING (&allocator->surface_info),
+      GST_VIDEO_INFO_FORMAT_STRING (&allocator->allocation_info),
+      gst_vaapi_image_usage_flags_to_string (allocator->usage_flag));
+  return TRUE;
+}
+
+static inline gboolean
+allocator_configure_image_info (GstVaapiDisplay * display,
+    GstVaapiVideoAllocator * allocator)
+{
+  GstVaapiImage *image = NULL;
+  const GstVideoInfo *vinfo;
+  gboolean ret = FALSE;
+
+  if (!use_native_formats (allocator->usage_flag)) {
+    allocator->image_info = allocator->surface_info;
+    return TRUE;
+  }
+
+  vinfo = &allocator->allocation_info;
+  allocator->image_info = *vinfo;
+  gst_video_info_force_nv12_if_encoded (&allocator->image_info);
+
+  image = new_image (display, &allocator->image_info);
+  if (!image)
+    goto error_no_image;
+  if (!gst_vaapi_image_map (image))
+    goto error_cannot_map;
+
+  gst_video_info_update_from_image (&allocator->image_info, image);
+  gst_vaapi_image_unmap (image);
+  ret = TRUE;
+
+bail:
+  if (image)
+    gst_vaapi_image_unref (image);
+  return ret;
+
+  /* ERRORS */
+error_no_image:
+  {
+    GST_ERROR ("Cannot create VA image");
+    return ret;
+  }
+error_cannot_map:
+  {
+    GST_ERROR ("Failed to map VA image %p", image);
+    goto bail;
+  }
+}
+
+static inline gboolean
+allocator_params_init (GstVaapiVideoAllocator * allocator,
+    GstVaapiDisplay * display, const GstVideoInfo * alloc_info,
+    guint surface_alloc_flags, GstVaapiImageUsageFlags req_usage_flag)
+{
+  allocator->allocation_info = *alloc_info;
+
+  if (!allocator_configure_surface_info (display, allocator, req_usage_flag,
+          surface_alloc_flags))
+    return FALSE;
+  allocator->surface_pool = gst_vaapi_surface_pool_new_full (display,
+      &allocator->surface_info, surface_alloc_flags);
+  if (!allocator->surface_pool)
+    goto error_create_surface_pool;
+
+  if (!allocator_configure_image_info (display, allocator))
+    return FALSE;
+  allocator->image_pool = gst_vaapi_image_pool_new (display,
+      &allocator->image_info);
+  if (!allocator->image_pool)
+    goto error_create_image_pool;
+
+  gst_allocator_set_vaapi_video_info (GST_ALLOCATOR_CAST (allocator),
+      &allocator->image_info, surface_alloc_flags);
+
+  return TRUE;
+
+  /* ERRORS */
+error_create_surface_pool:
+  {
+    GST_ERROR ("failed to allocate VA surface pool");
+    return FALSE;
+  }
+error_create_image_pool:
+  {
+    GST_ERROR ("failed to allocate VA image pool");
+    return FALSE;
+  }
+}
+
+GstAllocator *
+gst_vaapi_video_allocator_new (GstVaapiDisplay * display,
+    const GstVideoInfo * alloc_info, guint surface_alloc_flags,
+    GstVaapiImageUsageFlags req_usage_flag)
+{
+  GstVaapiVideoAllocator *allocator;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (alloc_info != NULL, NULL);
+
+  allocator = g_object_new (GST_VAAPI_TYPE_VIDEO_ALLOCATOR, NULL);
+  if (!allocator)
+    return NULL;
+
+  if (!allocator_params_init (allocator, display, alloc_info,
+          surface_alloc_flags, req_usage_flag)) {
+    g_object_unref (allocator);
+    return NULL;
+  }
+
+  return GST_ALLOCATOR_CAST (allocator);
+}
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVaapiDmaBufMemory                                             --- */
+/* ------------------------------------------------------------------------ */
+
+#define GST_VAAPI_BUFFER_PROXY_QUARK gst_vaapi_buffer_proxy_quark_get ()
+static GQuark
+gst_vaapi_buffer_proxy_quark_get (void)
+{
+  static gsize g_quark;
+
+  if (g_once_init_enter (&g_quark)) {
+    gsize quark = (gsize) g_quark_from_static_string ("GstVaapiBufferProxy");
+    g_once_init_leave (&g_quark, quark);
+  }
+  return g_quark;
+}
+
+/* Whether @mem holds an internal VA surface proxy created at
+ * gst_vaapi_dmabuf_memory_new(). */
+gboolean
+gst_vaapi_dmabuf_memory_holds_surface (GstMemory * mem)
+{
+  g_return_val_if_fail (mem != NULL, FALSE);
+
+  return
+      GPOINTER_TO_INT (gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (mem),
+          GST_VAAPI_BUFFER_PROXY_QUARK)) == TRUE;
+}
+
+GstMemory *
+gst_vaapi_dmabuf_memory_new (GstAllocator * base_allocator,
+    GstVaapiVideoMeta * meta)
+{
+  GstMemory *mem;
+  GstVaapiDisplay *display;
+  GstVaapiSurface *surface;
+  GstVaapiSurfaceProxy *proxy;
+  GstVaapiBufferProxy *dmabuf_proxy;
+  gint dmabuf_fd;
+  const GstVideoInfo *surface_info;
+  guint surface_alloc_flags;
+  gboolean needs_surface;
+  GstVaapiDmaBufAllocator *const allocator =
+      GST_VAAPI_DMABUF_ALLOCATOR_CAST (base_allocator);
+
+  g_return_val_if_fail (allocator != NULL, NULL);
+  g_return_val_if_fail (meta != NULL, NULL);
+
+  surface_info = gst_allocator_get_vaapi_video_info (base_allocator,
+      &surface_alloc_flags);
+  if (!surface_info)
+    return NULL;
+
+  display = gst_vaapi_video_meta_get_display (meta);
+  if (!display)
+    return NULL;
+
+  proxy = gst_vaapi_video_meta_get_surface_proxy (meta);
+  needs_surface = (proxy == NULL);
+
+  if (needs_surface) {
+    /* When exporting output VPP surfaces, or when exporting input
+     * surfaces to be filled/imported by an upstream element, such as
+     * v4l2src, we have to instantiate a VA surface to store it. */
+    surface = gst_vaapi_surface_new_full (display, surface_info,
+        surface_alloc_flags);
+    if (!surface)
+      goto error_create_surface;
+    proxy = gst_vaapi_surface_proxy_new (surface);
+    if (!proxy)
+      goto error_create_surface_proxy;
+    /* The proxy has incremented the surface ref count. */
+    gst_vaapi_surface_unref (surface);
+  } else {
+    /* When exporting existing surfaces that come from decoder's
+     * context. */
+    surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
+  }
+
+  dmabuf_proxy = gst_vaapi_surface_peek_dma_buf_handle (surface);
+  if (!dmabuf_proxy)
+    goto error_create_dmabuf_proxy;
+
+  if (needs_surface) {
+    gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
+    /* meta holds the proxy's reference */
+    gst_vaapi_surface_proxy_unref (proxy);
+  }
+
+  /* Need dup because GstDmabufMemory creates the GstFdMemory with flag
+   * GST_FD_MEMORY_FLAG_NONE. So when being freed it calls close on the fd
+   * because GST_FD_MEMORY_FLAG_DONT_CLOSE is not set. */
+  dmabuf_fd = gst_vaapi_buffer_proxy_get_handle (dmabuf_proxy);
+  if (dmabuf_fd < 0 || (dmabuf_fd = dup (dmabuf_fd)) < 0)
+    goto error_create_dmabuf_handle;
+
+  mem = gst_dmabuf_allocator_alloc (base_allocator, dmabuf_fd,
+      gst_vaapi_buffer_proxy_get_size (dmabuf_proxy));
+  if (!mem)
+    goto error_create_dmabuf_memory;
+
+  if (needs_surface) {
+    /* qdata express that memory has an associated surface. */
+    gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (mem),
+        GST_VAAPI_BUFFER_PROXY_QUARK, GINT_TO_POINTER (TRUE), NULL);
+  }
+
+  /* When a VA surface is going to be filled by a VAAPI element
+   * (decoder or VPP), it has _not_ be marked as busy in the driver.
+   * Releasing the surface's derived image, held by the buffer proxy,
+   * the surface will be unmarked as busy. */
+  if (allocator->direction == GST_PAD_SRC)
+    gst_vaapi_buffer_proxy_release_data (dmabuf_proxy);
+
+  return mem;
+
+  /* ERRORS */
+error_create_surface:
+  {
+    GST_ERROR ("failed to create VA surface (format:%s size:%ux%u)",
+        GST_VIDEO_INFO_FORMAT_STRING (surface_info),
+        GST_VIDEO_INFO_WIDTH (surface_info),
+        GST_VIDEO_INFO_HEIGHT (surface_info));
+    return NULL;
+  }
+error_create_surface_proxy:
+  {
+    GST_ERROR ("failed to create VA surface proxy");
+    gst_vaapi_surface_unref (surface);
+    return NULL;
+  }
+error_create_dmabuf_proxy:
+  {
+    GST_ERROR ("failed to export VA surface to DMABUF");
+    if (surface)
+      gst_vaapi_surface_unref (surface);
+    if (proxy)
+      gst_vaapi_surface_proxy_unref (proxy);
+    return NULL;
+  }
+error_create_dmabuf_handle:
+  {
+    GST_ERROR ("failed to duplicate DMABUF handle");
+    gst_vaapi_buffer_proxy_unref (dmabuf_proxy);
+    return NULL;
+  }
+error_create_dmabuf_memory:
+  {
+    GST_ERROR ("failed to create DMABUF memory");
+    close (dmabuf_fd);
+    gst_vaapi_buffer_proxy_unref (dmabuf_proxy);
+    return NULL;
+  }
+}
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVaapiDmaBufAllocator                                          --- */
+/* ------------------------------------------------------------------------ */
+
+G_DEFINE_TYPE (GstVaapiDmaBufAllocator,
+    gst_vaapi_dmabuf_allocator, GST_TYPE_DMABUF_ALLOCATOR);
+
+static void
+gst_vaapi_dmabuf_allocator_class_init (GstVaapiDmaBufAllocatorClass * klass)
+{
+  _init_vaapi_video_memory_debug ();
+}
+
+static void
+gst_vaapi_dmabuf_allocator_init (GstVaapiDmaBufAllocator * allocator)
+{
+  GstAllocator *const base_allocator = GST_ALLOCATOR_CAST (allocator);
+
+  base_allocator->mem_type = GST_VAAPI_DMABUF_ALLOCATOR_NAME;
+  allocator->direction = GST_PAD_SINK;
+}
+
+GstAllocator *
+gst_vaapi_dmabuf_allocator_new (GstVaapiDisplay * display,
+    const GstVideoInfo * alloc_info, guint surface_alloc_flags,
+    GstPadDirection direction)
+{
+  GstVaapiDmaBufAllocator *allocator = NULL;
+  GstVaapiSurface *surface = NULL;
+  GstVideoInfo surface_info;
+  GstAllocator *base_allocator;
+
+  g_return_val_if_fail (display != NULL, NULL);
+  g_return_val_if_fail (alloc_info != NULL, NULL);
+
+  allocator = g_object_new (GST_VAAPI_TYPE_DMABUF_ALLOCATOR, NULL);
+  if (!allocator)
+    goto error_no_allocator;
+
+  base_allocator = GST_ALLOCATOR_CAST (allocator);
+
+  gst_video_info_set_format (&surface_info, GST_VIDEO_INFO_FORMAT (alloc_info),
+      GST_VIDEO_INFO_WIDTH (alloc_info), GST_VIDEO_INFO_HEIGHT (alloc_info));
+  surface = gst_vaapi_surface_new_full (display, alloc_info,
+      surface_alloc_flags);
+  if (!surface)
+    goto error_no_surface;
+  if (!gst_video_info_update_from_surface (&surface_info, surface))
+    goto fail;
+  gst_mini_object_replace ((GstMiniObject **) & surface, NULL);
+
+  gst_allocator_set_vaapi_video_info (base_allocator, &surface_info,
+      surface_alloc_flags);
+
+  allocator->direction = direction;
+
+  return base_allocator;
+
+  /* ERRORS */
+fail:
+  {
+    gst_mini_object_replace ((GstMiniObject **) & surface, NULL);
+    gst_object_replace ((GstObject **) & base_allocator, NULL);
+    return NULL;
+  }
+error_no_allocator:
+  {
+    GST_ERROR ("failed to create a new dmabuf allocator");
+    return NULL;
+  }
+error_no_surface:
+  {
+    GST_ERROR ("failed to create a new surface");
+    goto fail;
+  }
+}
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVaapiVideoInfo = { GstVideoInfo, flags }                      --- */
+/* ------------------------------------------------------------------------ */
+
+#define GST_VAAPI_VIDEO_INFO_QUARK gst_vaapi_video_info_quark_get ()
+static GQuark
+gst_vaapi_video_info_quark_get (void)
+{
+  static gsize g_quark;
+
+  if (g_once_init_enter (&g_quark)) {
+    gsize quark = (gsize) g_quark_from_static_string ("GstVaapiVideoInfo");
+    g_once_init_leave (&g_quark, quark);
+  }
+  return g_quark;
+}
+
+#define ALLOCATION_VINFO_QUARK allocation_vinfo_quark_get ()
+static GQuark
+allocation_vinfo_quark_get (void)
+{
+  static gsize g_quark;
+
+  if (g_once_init_enter (&g_quark)) {
+    gsize quark = (gsize) g_quark_from_static_string ("allocation-vinfo");
+    g_once_init_leave (&g_quark, quark);
+  }
+  return g_quark;
+}
+
+#define SURFACE_ALLOC_FLAGS_QUARK surface_alloc_flags_quark_get ()
+static GQuark
+surface_alloc_flags_quark_get (void)
+{
+  static gsize g_quark;
+
+  if (g_once_init_enter (&g_quark)) {
+    gsize quark = (gsize) g_quark_from_static_string ("surface-alloc-flags");
+    g_once_init_leave (&g_quark, quark);
+  }
+  return g_quark;
+}
+
+#define NEGOTIATED_VINFO_QUARK negotiated_vinfo_quark_get ()
+static GQuark
+negotiated_vinfo_quark_get (void)
+{
+  static gsize g_quark;
+
+  if (g_once_init_enter (&g_quark)) {
+    gsize quark = (gsize) g_quark_from_static_string ("negotiated-vinfo");
+    g_once_init_leave (&g_quark, quark);
+  }
+  return g_quark;
+}
+
+/**
+ * gst_allocator_get_vaapi_video_info:
+ * @allocator: a #GstAllocator
+ * @out_flags_ptr: (out): the stored surface allocation flags
+ *
+ * Will get the @allocator qdata to fetch the flags and the
+ * allocation's #GstVideoInfo stored in it.
+ *
+ * The allocation video info, is the image video info in the case of
+ * the #GstVaapiVideoAllocator; and the allocation video info in the
+ * case of #GstVaapiDmaBufAllocator.
+ *
+ * Returns: the stored #GstVideoInfo
+ **/
+const GstVideoInfo *
+gst_allocator_get_vaapi_video_info (GstAllocator * allocator,
+    guint * out_flags_ptr)
+{
+  const GstStructure *structure;
+  const GValue *value;
+
+  g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), NULL);
+
+  structure =
+      g_object_get_qdata (G_OBJECT (allocator), GST_VAAPI_VIDEO_INFO_QUARK);
+  if (!structure)
+    return NULL;
+
+  if (out_flags_ptr) {
+    value = gst_structure_id_get_value (structure, SURFACE_ALLOC_FLAGS_QUARK);
+    if (!value)
+      return NULL;
+    *out_flags_ptr = g_value_get_uint (value);
+  }
+
+  value = gst_structure_id_get_value (structure, ALLOCATION_VINFO_QUARK);
+  if (!value)
+    return NULL;
+  return g_value_get_boxed (value);
+}
+
+/**
+ * gst_allocator_set_vaapi_video_info:
+ * @allocator: a #GstAllocator
+ * @alloc_info: the allocation #GstVideoInfo to store
+ * @surface_alloc_flags: the flags to store
+ *
+ * Stores as GObject's qdata the @alloc_info and the
+ * @surface_alloc_flags in the allocator. This will "decorate" the
+ * allocator as a GstVaapi one.
+ *
+ * Returns: always %TRUE
+ **/
+gboolean
+gst_allocator_set_vaapi_video_info (GstAllocator * allocator,
+    const GstVideoInfo * alloc_info, guint surface_alloc_flags)
+{
+  g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), FALSE);
+  g_return_val_if_fail (alloc_info != NULL, FALSE);
+
+  g_object_set_qdata_full (G_OBJECT (allocator), GST_VAAPI_VIDEO_INFO_QUARK,
+      gst_structure_new_id (GST_VAAPI_VIDEO_INFO_QUARK,
+          ALLOCATION_VINFO_QUARK, GST_TYPE_VIDEO_INFO, alloc_info,
+          SURFACE_ALLOC_FLAGS_QUARK, G_TYPE_UINT, surface_alloc_flags, NULL),
+      (GDestroyNotify) gst_structure_free);
+
+  return TRUE;
+}
+
+/**
+ * gst_allocator_set_vaapi_negotiated_video_info:
+ * @allocator: a #GstAllocator
+ * @negotiated_vinfo: the negotiated #GstVideoInfo to store.  If NULL, then
+ * removes any previously set value.
+ *
+ * Stores as GObject's qdata the @negotiated_vinfo in the allocator
+ * instance.
+ *
+ * The @negotiated_vinfo is different of the @alloc_info from
+ * gst_allocator_set_vaapi_video_info(), and might not be set.
+ **/
+void
+gst_allocator_set_vaapi_negotiated_video_info (GstAllocator * allocator,
+    const GstVideoInfo * negotiated_vinfo)
+{
+  g_return_if_fail (allocator && GST_IS_ALLOCATOR (allocator));
+
+  if (negotiated_vinfo)
+    g_object_set_qdata_full (G_OBJECT (allocator), NEGOTIATED_VINFO_QUARK,
+        gst_video_info_copy (negotiated_vinfo),
+        (GDestroyNotify) gst_video_info_free);
+  else
+    g_object_set_qdata (G_OBJECT (allocator), NEGOTIATED_VINFO_QUARK, NULL);
+}
+
+/**
+ * gst_allocator_get_vaapi_negotiated_video_info:
+ * @allocator: a #GstAllocator
+ *
+ * Returns: the stored negotiation #GstVideoInfo, if it was stored
+ * previously. Otherwise, %NULL
+ **/
+GstVideoInfo *
+gst_allocator_get_vaapi_negotiated_video_info (GstAllocator * allocator)
+{
+  g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), NULL);
+
+  return g_object_get_qdata (G_OBJECT (allocator), NEGOTIATED_VINFO_QUARK);
+}
+
+/**
+ * gst_vaapi_is_dmabuf_allocator:
+ * @allocator: an #GstAllocator
+ *
+ * Checks if the allocator is DMABuf allocator with the GstVaapi
+ * decorator.
+ *
+ * Returns: %TRUE if @allocator is a DMABuf allocator type with
+ * GstVaapi decorator.
+ **/
+gboolean
+gst_vaapi_is_dmabuf_allocator (GstAllocator * allocator)
+{
+  GstStructure *st;
+
+  g_return_val_if_fail (GST_IS_ALLOCATOR (allocator), FALSE);
+
+  if (g_strcmp0 (allocator->mem_type, GST_VAAPI_DMABUF_ALLOCATOR_NAME) != 0)
+    return FALSE;
+  st = g_object_get_qdata (G_OBJECT (allocator), GST_VAAPI_VIDEO_INFO_QUARK);
+  return (st != NULL);
+}
+
+/**
+ * gst_vaapi_dmabuf_can_map:
+ * @display: a #GstVaapiDisplay
+ * @allocator: a #GstAllocator
+ *
+ * It will create a dmabuf-based buffer using @allocator, and it will
+ * try to map it using gst_memory_map().
+ *
+ * Returns: %TRUE if the internal dummy buffer can be
+ * mapped. Otherwise %FALSE.
+ **/
+gboolean
+gst_vaapi_dmabuf_can_map (GstVaapiDisplay * display, GstAllocator * allocator)
+{
+  GstVaapiVideoMeta *meta;
+  GstMemory *mem;
+  GstMapInfo info;
+  gboolean ret;
+
+  g_return_val_if_fail (display != NULL, FALSE);
+
+  ret = FALSE;
+  mem = NULL;
+  meta = NULL;
+  if (!gst_vaapi_is_dmabuf_allocator (allocator))
+    return FALSE;
+  meta = gst_vaapi_video_meta_new (display);
+  if (!meta)
+    return FALSE;
+  mem = gst_vaapi_dmabuf_memory_new (allocator, meta);
+  if (!mem)
+    goto bail;
+
+  if (!gst_memory_map (mem, &info, GST_MAP_READWRITE) || info.size == 0)
+    goto bail;
+
+  gst_memory_unmap (mem, &info);
+  ret = TRUE;
+
+bail:
+  if (mem)
+    gst_memory_unref (mem);
+  if (meta)
+    gst_vaapi_video_meta_unref (meta);
+  return ret;
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideomemory.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideomemory.h
new file mode 100644 (file)
index 0000000..23d68ad
--- /dev/null
@@ -0,0 +1,304 @@
+/*
+ *  gstvaapivideomemory.h - Gstreamer/VA video memory
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VIDEO_MEMORY_H
+#define GST_VAAPI_VIDEO_MEMORY_H
+
+#include <gst/gstallocator.h>
+#include <gst/video/video-info.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapivideopool.h>
+#include "gstvaapivideometa.h"
+#include <gst/allocators/allocators.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiVideoMemory GstVaapiVideoMemory;
+typedef struct _GstVaapiVideoAllocator GstVaapiVideoAllocator;
+typedef struct _GstVaapiVideoAllocatorClass GstVaapiVideoAllocatorClass;
+typedef struct _GstVaapiDmaBufAllocator GstVaapiDmaBufAllocator;
+typedef struct _GstVaapiDmaBufAllocatorClass GstVaapiDmaBufAllocatorClass;
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVaapiVideoMemory                                              --- */
+/* ------------------------------------------------------------------------ */
+
+#define GST_VAAPI_VIDEO_MEMORY_CAST(mem) \
+  ((GstVaapiVideoMemory *) (mem))
+
+#define GST_VAAPI_IS_VIDEO_MEMORY(mem) \
+  ((mem) && (mem)->allocator && GST_VAAPI_IS_VIDEO_ALLOCATOR((mem)->allocator))
+
+#define GST_VAAPI_VIDEO_MEMORY_NAME             "GstVaapiVideoMemory"
+
+#define GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE   "memory:VASurface"
+
+#define GST_VAAPI_VIDEO_MEMORY_FLAG_IS_SET(mem, flag) \
+  GST_MEMORY_FLAG_IS_SET (mem, flag)
+#define GST_VAAPI_VIDEO_MEMORY_FLAG_SET(mem, flag) \
+  GST_MINI_OBJECT_FLAG_SET (mem, flag)
+#define GST_VAAPI_VIDEO_MEMORY_FLAG_UNSET(mem, flag) \
+  GST_MEMORY_FLAG_UNSET (mem, flag)
+
+/**
+ * GstVaapiVideoMemoryMapType:
+ * @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE: map with gst_buffer_map()
+ *   and flags = 0x00 to return a #GstVaapiSurfaceProxy
+ * @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR: map individual plane with
+ *   gst_video_frame_map()
+ * @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR: map with gst_buffer_map()
+ *   and flags = GST_MAP_READ to return the raw pixels of the whole image
+ *
+ * The set of all #GstVaapiVideoMemory map types.
+ */
+typedef enum
+{
+  GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE = 1,
+  GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_PLANAR,
+  GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_LINEAR
+} GstVaapiVideoMemoryMapType;
+
+/**
+ * GstVaapiVideoMemoryFlags:
+ * @GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT: The embedded
+ *   #GstVaapiSurface has the up-to-date video frame contents.
+ * @GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT: The embedded
+ *   #GstVaapiImage has the up-to-date video frame contents.
+ *
+ * The set of extended #GstMemory flags.
+ */
+typedef enum
+{
+  GST_VAAPI_VIDEO_MEMORY_FLAG_SURFACE_IS_CURRENT = GST_MEMORY_FLAG_LAST << 0,
+  GST_VAAPI_VIDEO_MEMORY_FLAG_IMAGE_IS_CURRENT = GST_MEMORY_FLAG_LAST << 1,
+} GstVaapiVideoMemoryFlags;
+
+/**
+ * GstVaapiImageUsageFlags:
+ * @GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS: will use vaCreateImage +
+ * va{Put,Get}Image when writing or reading onto the system memory.
+ * @GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD: will try to use
+ * vaDeriveImage when writing data from the system memory.
+ * @GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER: will try to use
+ * vaDeriveImage with reading data onto the system memory.
+ *
+ * Set the usage of GstVaapiImage in GstVaapiVideoMemory.
+ **/
+typedef enum {
+  GST_VAAPI_IMAGE_USAGE_FLAG_NATIVE_FORMATS,
+  GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_UPLOAD,
+  GST_VAAPI_IMAGE_USAGE_FLAG_DIRECT_RENDER,
+} GstVaapiImageUsageFlags;
+
+/**
+ * GstVaapiVideoMemory:
+ *
+ * A VA video memory object holder, including VA surfaces, images and
+ * proxies.
+ */
+struct _GstVaapiVideoMemory
+{
+  GstMemory parent_instance;
+
+  /*< private >*/
+  GstVaapiSurfaceProxy *proxy;
+  const GstVideoInfo *surface_info;
+  GstVaapiSurface *surface;
+  const GstVideoInfo *image_info;
+  GstVaapiImage *image;
+  GstVaapiVideoMeta *meta;
+  guint map_type;
+  gint map_count;
+  VASurfaceID map_surface_id;
+  GstVaapiImageUsageFlags usage_flag;
+  GMutex lock;
+};
+
+G_GNUC_INTERNAL
+GstMemory *
+gst_vaapi_video_memory_new (GstAllocator * allocator, GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+gboolean
+gst_video_meta_map_vaapi_memory (GstVideoMeta * meta, guint plane,
+    GstMapInfo * info, gpointer * data, gint * stride, GstMapFlags flags);
+
+G_GNUC_INTERNAL
+gboolean
+gst_video_meta_unmap_vaapi_memory (GstVideoMeta * meta, guint plane,
+    GstMapInfo * info);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_memory_reset_surface (GstVaapiVideoMemory * mem);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_video_memory_sync (GstVaapiVideoMemory * mem);
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVaapiVideoAllocator                                           --- */
+/* ------------------------------------------------------------------------ */
+#define GST_MAP_VAAPI (GST_MAP_FLAG_LAST << 1)
+
+#define GST_VAAPI_VIDEO_ALLOCATOR_CAST(allocator) \
+  ((GstVaapiVideoAllocator *) (allocator))
+
+#define GST_VAAPI_TYPE_VIDEO_ALLOCATOR \
+  (gst_vaapi_video_allocator_get_type ())
+#define GST_VAAPI_VIDEO_ALLOCATOR(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_VAAPI_TYPE_VIDEO_ALLOCATOR, \
+      GstVaapiVideoAllocator))
+#define GST_VAAPI_IS_VIDEO_ALLOCATOR(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_VAAPI_TYPE_VIDEO_ALLOCATOR))
+
+/**
+ * GstVaapiVideoAllocator:
+ *
+ * A VA video memory allocator object.
+ */
+struct _GstVaapiVideoAllocator
+{
+  GstAllocator parent_instance;
+
+  /*< private >*/
+  GstVideoInfo allocation_info;
+  GstVideoInfo surface_info;
+  GstVaapiVideoPool *surface_pool;
+  GstVideoInfo image_info;
+  GstVaapiVideoPool *image_pool;
+  GstVaapiImageUsageFlags usage_flag;
+};
+
+/**
+ * GstVaapiVideoAllocatorClass:
+ *
+ * A VA video memory allocator class.
+ */
+struct _GstVaapiVideoAllocatorClass
+{
+  GstAllocatorClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType
+gst_vaapi_video_allocator_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GstAllocator *
+gst_vaapi_video_allocator_new (GstVaapiDisplay * display,
+    const GstVideoInfo * alloc_info, guint surface_alloc_flags,
+    GstVaapiImageUsageFlags req_usage_flag);
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVaapiDmaBufMemory                                             --- */
+/* ------------------------------------------------------------------------ */
+
+G_GNUC_INTERNAL
+GstMemory *
+gst_vaapi_dmabuf_memory_new (GstAllocator * allocator,
+    GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_dmabuf_memory_holds_surface (GstMemory * mem);
+
+/* ------------------------------------------------------------------------ */
+/* --- GstVaapiDmaBufAllocator                                          --- */
+/* ------------------------------------------------------------------------ */
+
+#define GST_VAAPI_DMABUF_ALLOCATOR_CAST(allocator) \
+  ((GstVaapiDmaBufAllocator *) (allocator))
+
+#define GST_VAAPI_TYPE_DMABUF_ALLOCATOR \
+  (gst_vaapi_dmabuf_allocator_get_type ())
+#define GST_VAAPI_DMABUF_ALLOCATOR(obj) \
+  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_VAAPI_TYPE_DMABUF_ALLOCATOR, \
+      GstVaapiDmaBufAllocator))
+#define GST_VAAPI_IS_DMABUF_ALLOCATOR(obj) \
+  (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_VAAPI_TYPE_DMABUF_ALLOCATOR))
+
+#define GST_VAAPI_DMABUF_ALLOCATOR_NAME          "GstVaapiDmaBufAllocator"
+
+/**
+ * GstVaapiDmaBufAllocator:
+ *
+ * A VA dmabuf memory allocator object.
+ */
+struct _GstVaapiDmaBufAllocator
+{
+  GstDmaBufAllocator parent_instance;
+
+  /*< private >*/
+  GstPadDirection direction;
+};
+
+/**
+ * GstVaapiDmaBufoAllocatorClass:
+ *
+ * A VA dmabuf memory allocator class.
+ */
+struct _GstVaapiDmaBufAllocatorClass
+{
+  GstDmaBufAllocatorClass parent_class;
+};
+
+G_GNUC_INTERNAL
+GType
+gst_vaapi_dmabuf_allocator_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GstAllocator *
+gst_vaapi_dmabuf_allocator_new (GstVaapiDisplay * display,
+    const GstVideoInfo * alloc_info, guint surface_alloc_flags,
+    GstPadDirection direction);
+
+G_GNUC_INTERNAL
+const GstVideoInfo *
+gst_allocator_get_vaapi_video_info (GstAllocator * allocator,
+    guint * out_flags_ptr);
+
+G_GNUC_INTERNAL
+gboolean
+gst_allocator_set_vaapi_video_info (GstAllocator * allocator,
+    const GstVideoInfo * alloc_info, guint surface_alloc_flags);
+
+G_GNUC_INTERNAL
+void
+gst_allocator_set_vaapi_negotiated_video_info (GstAllocator * allocator,
+    const GstVideoInfo * negotiated_vinfo);
+
+G_GNUC_INTERNAL
+GstVideoInfo *
+gst_allocator_get_vaapi_negotiated_video_info (GstAllocator * allocator);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_is_dmabuf_allocator (GstAllocator * allocator);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_dmabuf_can_map (GstVaapiDisplay * display, GstAllocator * allocator);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_VIDEO_MEMORY_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa.c
new file mode 100644 (file)
index 0000000..53a48dd
--- /dev/null
@@ -0,0 +1,764 @@
+/*
+ *  gstvaapivideometa.c - Gst VA video meta
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/**
+ * SECTION:gstvaapivideometa
+ * @short_description: VA video meta for GStreamer
+ *
+ * Describes a #GstMeta for VA-base video buffers.
+ */
+
+#include "gstcompat.h"
+#include <gst/vaapi/gstvaapiimagepool.h>
+#include <gst/vaapi/gstvaapisurfacepool.h>
+#include "gstvaapivideometa.h"
+#include "gstvaapivideomemory.h"
+
+#define GST_VAAPI_VIDEO_META(obj) \
+  ((GstVaapiVideoMeta *) (obj))
+#define GST_VAAPI_IS_VIDEO_META(obj) \
+  (GST_VAAPI_VIDEO_META (obj) != NULL)
+
+struct _GstVaapiVideoMeta
+{
+  GstBuffer *buffer;
+  gint ref_count;
+  GstVaapiDisplay *display;
+  GstVaapiVideoPool *image_pool;
+  GstVaapiImage *image;
+  GstVaapiSurfaceProxy *proxy;
+  GFunc converter;
+  guint render_flags;
+  GstVaapiRectangle render_rect;
+  guint has_render_rect:1;
+};
+
+static gboolean
+ensure_surface_proxy (GstVaapiVideoMeta * meta)
+{
+  if (!meta->proxy)
+    return FALSE;
+
+  if (meta->buffer) {
+    GstMemory *const mem = gst_buffer_peek_memory (meta->buffer, 0);
+
+    if (GST_VAAPI_IS_VIDEO_MEMORY (mem))
+      return gst_vaapi_video_memory_sync (GST_VAAPI_VIDEO_MEMORY_CAST (mem));
+  }
+  return TRUE;
+}
+
+static inline void
+set_display (GstVaapiVideoMeta * meta, GstVaapiDisplay * display)
+{
+  gst_vaapi_display_replace (&meta->display, display);
+}
+
+static inline void
+set_image (GstVaapiVideoMeta * meta, GstVaapiImage * image)
+{
+  meta->image =
+      (GstVaapiImage *) gst_mini_object_ref (GST_MINI_OBJECT_CAST (image));
+  set_display (meta, gst_vaapi_image_get_display (image));
+}
+
+static gboolean
+set_image_from_pool (GstVaapiVideoMeta * meta, GstVaapiVideoPool * pool)
+{
+  GstVaapiImage *image;
+
+  image = gst_vaapi_video_pool_get_object (pool);
+  if (!image)
+    return FALSE;
+
+  set_image (meta, image);
+  meta->image_pool = gst_vaapi_video_pool_ref (pool);
+  return TRUE;
+}
+
+static gboolean
+set_surface_proxy (GstVaapiVideoMeta * meta, GstVaapiSurfaceProxy * proxy)
+{
+  GstVaapiSurface *surface;
+
+  surface = GST_VAAPI_SURFACE_PROXY_SURFACE (proxy);
+  if (!surface)
+    return FALSE;
+
+  meta->proxy = gst_vaapi_surface_proxy_ref (proxy);
+  set_display (meta, gst_vaapi_surface_get_display (surface));
+  return TRUE;
+}
+
+static gboolean
+set_surface_proxy_from_pool (GstVaapiVideoMeta * meta, GstVaapiVideoPool * pool)
+{
+  GstVaapiSurfaceProxy *proxy;
+  gboolean success;
+
+  proxy = gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL (pool));
+  if (!proxy)
+    return FALSE;
+
+  success = set_surface_proxy (meta, proxy);
+  gst_vaapi_surface_proxy_unref (proxy);
+  return success;
+}
+
+static void
+gst_vaapi_video_meta_destroy_image (GstVaapiVideoMeta * meta)
+{
+  if (meta->image) {
+    if (meta->image_pool)
+      gst_vaapi_video_pool_put_object (meta->image_pool, meta->image);
+    gst_vaapi_image_unref (meta->image);
+    meta->image = NULL;
+  }
+  gst_vaapi_video_pool_replace (&meta->image_pool, NULL);
+}
+
+static inline void
+gst_vaapi_video_meta_destroy_proxy (GstVaapiVideoMeta * meta)
+{
+  gst_vaapi_surface_proxy_replace (&meta->proxy, NULL);
+}
+
+static void
+gst_vaapi_video_meta_finalize (GstVaapiVideoMeta * meta)
+{
+  gst_vaapi_video_meta_destroy_image (meta);
+  gst_vaapi_video_meta_destroy_proxy (meta);
+  gst_vaapi_display_replace (&meta->display, NULL);
+}
+
+static void
+gst_vaapi_video_meta_init (GstVaapiVideoMeta * meta)
+{
+  meta->buffer = NULL;
+  meta->ref_count = 1;
+  meta->display = NULL;
+  meta->image_pool = NULL;
+  meta->image = NULL;
+  meta->proxy = NULL;
+  meta->converter = NULL;
+  meta->render_flags = 0;
+  meta->has_render_rect = FALSE;
+}
+
+static inline GstVaapiVideoMeta *
+_gst_vaapi_video_meta_create (void)
+{
+  return g_slice_new (GstVaapiVideoMeta);
+}
+
+static inline void
+_gst_vaapi_video_meta_destroy (GstVaapiVideoMeta * meta)
+{
+  g_slice_free1 (sizeof (*meta), meta);
+}
+
+static inline GstVaapiVideoMeta *
+_gst_vaapi_video_meta_new (void)
+{
+  GstVaapiVideoMeta *meta;
+
+  meta = _gst_vaapi_video_meta_create ();
+  if (!meta)
+    return NULL;
+  gst_vaapi_video_meta_init (meta);
+  return meta;
+}
+
+static inline void
+_gst_vaapi_video_meta_free (GstVaapiVideoMeta * meta)
+{
+  g_atomic_int_inc (&meta->ref_count);
+
+  gst_vaapi_video_meta_finalize (meta);
+
+  if (G_LIKELY (g_atomic_int_dec_and_test (&meta->ref_count)))
+    _gst_vaapi_video_meta_destroy (meta);
+}
+
+/**
+ * gst_vaapi_video_meta_copy:
+ * @meta: a #GstVaapiVideoMeta
+ *
+ * Creates a copy of #GstVaapiVideoMeta object @meta. The original
+ * @meta object shall not contain any VA objects created from a
+ * #GstVaapiVideoPool.
+ *
+ * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL on error
+ */
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_copy (GstVaapiVideoMeta * meta)
+{
+  GstVaapiVideoMeta *copy;
+
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL);
+
+  if (meta->image_pool)
+    return NULL;
+
+  copy = _gst_vaapi_video_meta_create ();
+  if (!copy)
+    return NULL;
+
+  copy->buffer = NULL;
+  copy->ref_count = 1;
+  copy->display = gst_object_ref (meta->display);
+  copy->image_pool = NULL;
+  copy->image = meta->image ? (GstVaapiImage *)
+      gst_mini_object_ref (GST_MINI_OBJECT_CAST (meta->image)) : NULL;
+  copy->proxy = meta->proxy ? gst_vaapi_surface_proxy_copy (meta->proxy) : NULL;
+  copy->converter = meta->converter;
+  copy->render_flags = meta->render_flags;
+
+  copy->has_render_rect = meta->has_render_rect;
+  if (copy->has_render_rect)
+    copy->render_rect = meta->render_rect;
+  return copy;
+}
+
+/**
+ * gst_vaapi_video_meta_new:
+ * @display: a #GstVaapiDisplay
+ *
+ * Creates an empty #GstVaapiVideoMeta. The caller is responsible for completing
+ * the initialization of the meta with the gst_vaapi_video_meta_set_*()
+ * functions.
+ *
+ * This function shall only be called from within gstreamer-vaapi
+ * plugin elements.
+ *
+ * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL or error
+ */
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_new (GstVaapiDisplay * display)
+{
+  GstVaapiVideoMeta *meta;
+
+  g_return_val_if_fail (display != NULL, NULL);
+
+  meta = _gst_vaapi_video_meta_new ();
+  if (G_UNLIKELY (!meta))
+    return NULL;
+
+  set_display (meta, display);
+  return meta;
+}
+
+/**
+ * gst_vaapi_video_meta_new_from_pool:
+ * @pool: a #GstVaapiVideoPool
+ *
+ * Creates a #GstVaapiVideoMeta with a video object allocated from a @pool.
+ * Only #GstVaapiSurfacePool and #GstVaapiImagePool pools are supported.
+ *
+ * The meta object is destroyed through the last call to
+ * gst_vaapi_video_meta_unref() and the video objects are pushed back
+ * to their respective pools.
+ *
+ * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL on error
+ */
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_new_from_pool (GstVaapiVideoPool * pool)
+{
+  GstVaapiVideoMeta *meta;
+  GstVaapiVideoPoolObjectType object_type;
+
+  g_return_val_if_fail (pool != NULL, NULL);
+
+  meta = _gst_vaapi_video_meta_new ();
+  if (G_UNLIKELY (!meta))
+    return NULL;
+
+  object_type = gst_vaapi_video_pool_get_object_type (pool);
+  switch (object_type) {
+    case GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE:
+      if (!set_image_from_pool (meta, pool))
+        goto error;
+      break;
+    case GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_SURFACE:
+      if (!set_surface_proxy_from_pool (meta, pool))
+        goto error;
+      break;
+    default:
+      GST_ERROR ("unsupported video buffer pool of type %d", object_type);
+      goto error;
+  }
+  set_display (meta, gst_vaapi_video_pool_get_display (pool));
+  return meta;
+
+  /* ERRORS */
+error:
+  {
+    gst_vaapi_video_meta_unref (meta);
+    return NULL;
+  }
+}
+
+/**
+ * gst_vaapi_video_meta_new_with_image:
+ * @image: a #GstVaapiImage
+ *
+ * Creates a #GstVaapiVideoMeta with the specified @image. The resulting
+ * meta holds an additional reference to the @image.
+ *
+ * This function shall only be called from within gstreamer-vaapi
+ * plugin elements.
+ *
+ * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL on error
+ */
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_new_with_image (GstVaapiImage * image)
+{
+  GstVaapiVideoMeta *meta;
+
+  g_return_val_if_fail (image != NULL, NULL);
+
+  meta = _gst_vaapi_video_meta_new ();
+  if (G_UNLIKELY (!meta))
+    return NULL;
+
+  gst_vaapi_video_meta_set_image (meta, image);
+  return meta;
+}
+
+/**
+ * gst_vaapi_video_meta_new_with_surface_proxy:
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Creates a #GstVaapiVideoMeta with the specified surface @proxy. The
+ * resulting meta holds an additional reference to the @proxy.
+ *
+ * This function shall only be called from within gstreamer-vaapi
+ * plugin elements.
+ *
+ * Return value: the newly allocated #GstVaapiVideoMeta, or %NULL on error
+ */
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_new_with_surface_proxy (GstVaapiSurfaceProxy * proxy)
+{
+  GstVaapiVideoMeta *meta;
+
+  g_return_val_if_fail (proxy != NULL, NULL);
+
+  meta = _gst_vaapi_video_meta_new ();
+  if (G_UNLIKELY (!meta))
+    return NULL;
+
+  gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
+  return meta;
+}
+
+/**
+ * gst_vaapi_video_meta_ref:
+ * @meta: a #GstVaapiVideoMeta
+ *
+ * Atomically increases the reference count of the given @meta by one.
+ *
+ * Returns: The same @meta argument
+ */
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_ref (GstVaapiVideoMeta * meta)
+{
+  g_return_val_if_fail (meta != NULL, NULL);
+
+  g_atomic_int_inc (&meta->ref_count);
+  return meta;
+}
+
+/**
+ * gst_vaapi_video_meta_unref:
+ * @meta: a #GstVaapiVideoMeta
+ *
+ * Atomically decreases the reference count of the @meta by one. If
+ * the reference count reaches zero, the object will be free'd.
+ */
+void
+gst_vaapi_video_meta_unref (GstVaapiVideoMeta * meta)
+{
+  g_return_if_fail (meta != NULL);
+  g_return_if_fail (meta->ref_count > 0);
+
+  if (g_atomic_int_dec_and_test (&meta->ref_count))
+    _gst_vaapi_video_meta_free (meta);
+}
+
+/**
+ * gst_vaapi_video_meta_replace:
+ * @old_meta_ptr: a pointer to a #GstVaapiVideoMeta
+ * @new_meta: a #GstVaapiVideoMeta
+ *
+ * @new_meta. This means that @old_meta_ptr shall reference a valid
+ * Atomically replaces the meta object held in @old_meta_ptr with
+ * object. However, @new_meta can be NULL.
+ */
+void
+gst_vaapi_video_meta_replace (GstVaapiVideoMeta ** old_meta_ptr,
+    GstVaapiVideoMeta * new_meta)
+{
+  GstVaapiVideoMeta *old_meta;
+
+  g_return_if_fail (old_meta_ptr != NULL);
+
+  old_meta = g_atomic_pointer_get ((gpointer *) old_meta_ptr);
+
+  if (old_meta == new_meta)
+    return;
+
+  if (new_meta)
+    gst_vaapi_video_meta_ref (new_meta);
+
+  while (!g_atomic_pointer_compare_and_exchange (old_meta_ptr, old_meta,
+          new_meta))
+    old_meta = g_atomic_pointer_get ((gpointer *) old_meta_ptr);
+
+  if (old_meta)
+    gst_vaapi_video_meta_unref (old_meta);
+}
+
+/**
+ * gst_vaapi_video_meta_get_display:
+ * @meta: a #GstVaapiVideoMeta
+ *
+ * Retrieves the #GstVaapiDisplay the @meta is bound to. The @meta
+ * owns the returned #GstVaapiDisplay object so the caller is
+ * responsible for calling g_object_ref() when needed.
+ *
+ * Return value: the #GstVaapiDisplay the @meta is bound to
+ */
+GstVaapiDisplay *
+gst_vaapi_video_meta_get_display (GstVaapiVideoMeta * meta)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL);
+
+  return meta->display;
+}
+
+/**
+ * gst_vaapi_video_meta_get_image:
+ * @meta: a #GstVaapiVideoMeta
+ *
+ * Retrieves the #GstVaapiImage bound to the @meta. The @meta owns
+ * the #GstVaapiImage so the caller is responsible for calling
+ * gst_mini_object_ref() when needed.
+ *
+ * Return value: the #GstVaapiImage bound to the @meta, or %NULL if
+ *   there is none
+ */
+GstVaapiImage *
+gst_vaapi_video_meta_get_image (GstVaapiVideoMeta * meta)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL);
+
+  return meta->image;
+}
+
+/**
+ * gst_vaapi_video_meta_set_image:
+ * @meta: a #GstVaapiVideoMeta
+ * @image: a #GstVaapiImage
+ *
+ * Binds @image to the @meta. If the @meta contains another image
+ * previously allocated from a pool, it's pushed back to its parent
+ * pool and the pool is also released.
+ */
+void
+gst_vaapi_video_meta_set_image (GstVaapiVideoMeta * meta, GstVaapiImage * image)
+{
+  g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta));
+
+  gst_vaapi_video_meta_destroy_image (meta);
+
+  if (image)
+    set_image (meta, image);
+}
+
+/**
+ * gst_vaapi_video_meta_set_image_from_pool
+ * @meta: a #GstVaapiVideoMeta
+ * @pool: a #GstVaapiVideoPool
+ *
+ * Binds a newly allocated video object from the @pool. The @pool
+ * shall be of type #GstVaapiImagePool. Previously allocated objects
+ * are released and returned to their parent pools, if any.
+ *
+ * Return value: %TRUE on success
+ */
+gboolean
+gst_vaapi_video_meta_set_image_from_pool (GstVaapiVideoMeta * meta,
+    GstVaapiVideoPool * pool)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), FALSE);
+  g_return_val_if_fail (pool != NULL, FALSE);
+  g_return_val_if_fail (gst_vaapi_video_pool_get_object_type (pool) ==
+      GST_VAAPI_VIDEO_POOL_OBJECT_TYPE_IMAGE, FALSE);
+
+  gst_vaapi_video_meta_destroy_image (meta);
+
+  return set_image_from_pool (meta, pool);
+}
+
+/**
+ * gst_vaapi_video_meta_get_surface:
+ * @meta: a #GstVaapiVideoMeta
+ *
+ * Retrieves the #GstVaapiSurface bound to the @meta. The @meta
+ * owns the #GstVaapiSurface so the caller is responsible for calling
+ * gst_mini_object_ref() when needed.
+ *
+ * Return value: the #GstVaapiSurface bound to the @meta, or %NULL if
+ *   there is none
+ */
+GstVaapiSurface *
+gst_vaapi_video_meta_get_surface (GstVaapiVideoMeta * meta)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL);
+
+  return ensure_surface_proxy (meta) ?
+      GST_VAAPI_SURFACE_PROXY_SURFACE (meta->proxy) : NULL;
+}
+
+/**
+ * gst_vaapi_video_meta_get_surface_proxy:
+ * @meta: a #GstVaapiVideoMeta
+ *
+ * Retrieves the #GstVaapiSurfaceProxy bound to the @meta. The @meta
+ * owns the #GstVaapiSurfaceProxy so the caller is responsible for calling
+ * gst_surface_proxy_ref() when needed.
+ *
+ * Return value: the #GstVaapiSurfaceProxy bound to the @meta, or
+ *   %NULL if there is none
+ */
+GstVaapiSurfaceProxy *
+gst_vaapi_video_meta_get_surface_proxy (GstVaapiVideoMeta * meta)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL);
+
+  return ensure_surface_proxy (meta) ? meta->proxy : NULL;
+}
+
+/**
+ * gst_vaapi_video_meta_set_surface_proxy:
+ * @meta: a #GstVaapiVideoMeta
+ * @proxy: a #GstVaapiSurfaceProxy
+ *
+ * Binds surface @proxy to the @meta. If the @meta contains another
+ * surface previously allocated from a pool, it's pushed back to its
+ * parent pool and the pool is also released.
+ */
+void
+gst_vaapi_video_meta_set_surface_proxy (GstVaapiVideoMeta * meta,
+    GstVaapiSurfaceProxy * proxy)
+{
+  const GstVaapiRectangle *crop_rect;
+
+  g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta));
+
+  gst_vaapi_video_meta_destroy_proxy (meta);
+
+  if (proxy) {
+    if (!set_surface_proxy (meta, proxy))
+      return;
+
+    crop_rect = gst_vaapi_surface_proxy_get_crop_rect (proxy);
+    if (crop_rect)
+      gst_vaapi_video_meta_set_render_rect (meta, crop_rect);
+  }
+}
+
+/**
+ * gst_vaapi_video_meta_get_render_flags:
+ * @meta: a #GstVaapiVideoMeta
+ *
+ * Retrieves the surface render flags bound to the @meta.
+ *
+ * Return value: a combination for #GstVaapiSurfaceRenderFlags
+ */
+guint
+gst_vaapi_video_meta_get_render_flags (GstVaapiVideoMeta * meta)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), 0);
+  g_return_val_if_fail (meta->proxy != NULL, 0);
+
+  return meta->render_flags;
+}
+
+/**
+ * gst_vaapi_video_meta_set_render_flags:
+ * @meta: a #GstVaapiVideoMeta
+ * @flags: a set of surface render flags
+ *
+ * Sets #GstVaapiSurfaceRenderFlags to the @meta.
+ */
+void
+gst_vaapi_video_meta_set_render_flags (GstVaapiVideoMeta * meta, guint flags)
+{
+  g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta));
+  g_return_if_fail (meta->proxy != NULL);
+
+  meta->render_flags = flags;
+}
+
+/**
+ * gst_vaapi_video_meta_get_render_rect:
+ * @meta: a #GstVaapiVideoMeta
+ *
+ * Retrieves the render rectangle bound to the @meta
+ *
+ * Return value: render rectangle associated with the video meta.
+ */
+const GstVaapiRectangle *
+gst_vaapi_video_meta_get_render_rect (GstVaapiVideoMeta * meta)
+{
+  g_return_val_if_fail (GST_VAAPI_IS_VIDEO_META (meta), NULL);
+
+  if (!meta->has_render_rect)
+    return NULL;
+  return &meta->render_rect;
+}
+
+/**
+ * gst_vaapi_video_meta_set_render_rect:
+ * @meta: a #GstVaapiVideoMeta
+ * @rect: a #GstVaapiRectangle
+ *
+ * Sets the render rectangle @rect to the @meta.
+ */
+void
+gst_vaapi_video_meta_set_render_rect (GstVaapiVideoMeta * meta,
+    const GstVaapiRectangle * rect)
+{
+  g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta));
+
+  meta->has_render_rect = rect != NULL;
+  if (meta->has_render_rect)
+    meta->render_rect = *rect;
+}
+
+#define GST_VAAPI_VIDEO_META_HOLDER(meta) \
+  ((GstVaapiVideoMetaHolder *) (meta))
+
+typedef struct _GstVaapiVideoMetaHolder GstVaapiVideoMetaHolder;
+struct _GstVaapiVideoMetaHolder
+{
+  GstMeta base;
+  GstVaapiVideoMeta *meta;
+};
+
+static gboolean
+gst_vaapi_video_meta_holder_init (GstVaapiVideoMetaHolder * meta,
+    gpointer params, GstBuffer * buffer)
+{
+  meta->meta = NULL;
+  return TRUE;
+}
+
+static void
+gst_vaapi_video_meta_holder_free (GstVaapiVideoMetaHolder * meta,
+    GstBuffer * buffer)
+{
+  if (meta->meta)
+    gst_vaapi_video_meta_unref (meta->meta);
+}
+
+static gboolean
+gst_vaapi_video_meta_holder_transform (GstBuffer * dst_buffer, GstMeta * meta,
+    GstBuffer * src_buffer, GQuark type, gpointer data)
+{
+  GstVaapiVideoMetaHolder *const src_meta = GST_VAAPI_VIDEO_META_HOLDER (meta);
+
+  if (GST_META_TRANSFORM_IS_COPY (type)) {
+    GstVaapiVideoMeta *const dst_meta =
+        gst_vaapi_video_meta_copy (src_meta->meta);
+    gst_buffer_set_vaapi_video_meta (dst_buffer, dst_meta);
+    gst_vaapi_video_meta_unref (dst_meta);
+    return TRUE;
+  }
+  return FALSE;
+}
+
+GType
+gst_vaapi_video_meta_api_get_type (void)
+{
+  static gsize g_type;
+  static const gchar *tags[] = { "memory", NULL };
+
+  if (g_once_init_enter (&g_type)) {
+    GType type = gst_meta_api_type_register ("GstVaapiVideoMetaAPI", tags);
+    g_once_init_leave (&g_type, type);
+  }
+  return g_type;
+}
+
+#define GST_VAAPI_VIDEO_META_INFO gst_vaapi_video_meta_info_get ()
+static const GstMetaInfo *
+gst_vaapi_video_meta_info_get (void)
+{
+  static gsize g_meta_info;
+
+  if (g_once_init_enter (&g_meta_info)) {
+    gsize meta_info =
+        GPOINTER_TO_SIZE (gst_meta_register (GST_VAAPI_VIDEO_META_API_TYPE,
+            "GstVaapiVideoMeta", sizeof (GstVaapiVideoMetaHolder),
+            (GstMetaInitFunction) gst_vaapi_video_meta_holder_init,
+            (GstMetaFreeFunction) gst_vaapi_video_meta_holder_free,
+            (GstMetaTransformFunction) gst_vaapi_video_meta_holder_transform));
+    g_once_init_leave (&g_meta_info, meta_info);
+  }
+  return GSIZE_TO_POINTER (g_meta_info);
+}
+
+GstVaapiVideoMeta *
+gst_buffer_get_vaapi_video_meta (GstBuffer * buffer)
+{
+  GstVaapiVideoMeta *meta;
+  GstMeta *m;
+
+  g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
+
+  m = gst_buffer_get_meta (buffer, GST_VAAPI_VIDEO_META_API_TYPE);
+  if (!m)
+    return NULL;
+
+  meta = GST_VAAPI_VIDEO_META_HOLDER (m)->meta;
+  if (meta)
+    meta->buffer = buffer;
+  return meta;
+}
+
+void
+gst_buffer_set_vaapi_video_meta (GstBuffer * buffer, GstVaapiVideoMeta * meta)
+{
+  GstMeta *m;
+
+  g_return_if_fail (GST_IS_BUFFER (buffer));
+  g_return_if_fail (GST_VAAPI_IS_VIDEO_META (meta));
+
+  m = gst_buffer_add_meta (buffer, GST_VAAPI_VIDEO_META_INFO, NULL);
+  if (m)
+    GST_VAAPI_VIDEO_META_HOLDER (m)->meta = gst_vaapi_video_meta_ref (meta);
+}
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa.h
new file mode 100644 (file)
index 0000000..c88abfd
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *  gstvaapivideometa.h - Gstreamer/VA video meta
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VIDEO_META_H
+#define GST_VAAPI_VIDEO_META_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiimage.h>
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapisurfaceproxy.h>
+#include <gst/vaapi/gstvaapivideopool.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiVideoMeta GstVaapiVideoMeta;
+
+#define GST_VAAPI_VIDEO_META_API_TYPE \
+  gst_vaapi_video_meta_api_get_type ()
+
+G_GNUC_INTERNAL
+GType
+gst_vaapi_video_meta_api_get_type (void) G_GNUC_CONST;
+
+G_GNUC_INTERNAL
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_copy (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_new (GstVaapiDisplay * display);
+
+G_GNUC_INTERNAL
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_new_from_pool (GstVaapiVideoPool * pool);
+
+G_GNUC_INTERNAL
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_new_with_image (GstVaapiImage * image);
+
+G_GNUC_INTERNAL
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_new_with_surface_proxy (GstVaapiSurfaceProxy * proxy);
+
+G_GNUC_INTERNAL
+GstVaapiVideoMeta *
+gst_vaapi_video_meta_ref (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_meta_unref (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_meta_replace (GstVaapiVideoMeta ** old_meta_ptr,
+    GstVaapiVideoMeta * new_meta);
+
+G_GNUC_INTERNAL
+GstVaapiDisplay *
+gst_vaapi_video_meta_get_display (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+GstVaapiImage *
+gst_vaapi_video_meta_get_image (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_meta_set_image (GstVaapiVideoMeta * meta,
+    GstVaapiImage * image);
+
+G_GNUC_INTERNAL
+gboolean
+gst_vaapi_video_meta_set_image_from_pool (GstVaapiVideoMeta * meta,
+    GstVaapiVideoPool * pool);
+
+G_GNUC_INTERNAL
+GstVaapiSurface *
+gst_vaapi_video_meta_get_surface (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+GstVaapiSurfaceProxy *
+gst_vaapi_video_meta_get_surface_proxy (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_meta_set_surface_proxy (GstVaapiVideoMeta * meta,
+    GstVaapiSurfaceProxy * proxy);
+
+G_GNUC_INTERNAL
+guint
+gst_vaapi_video_meta_get_render_flags (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_meta_set_render_flags (GstVaapiVideoMeta * meta, guint flags);
+
+G_GNUC_INTERNAL
+const GstVaapiRectangle *
+gst_vaapi_video_meta_get_render_rect (GstVaapiVideoMeta * meta);
+
+G_GNUC_INTERNAL
+void
+gst_vaapi_video_meta_set_render_rect (GstVaapiVideoMeta * meta,
+    const GstVaapiRectangle * rect);
+
+G_GNUC_INTERNAL
+GstVaapiVideoMeta *
+gst_buffer_get_vaapi_video_meta (GstBuffer * buffer);
+
+G_GNUC_INTERNAL
+void
+gst_buffer_set_vaapi_video_meta (GstBuffer * buffer, GstVaapiVideoMeta * meta);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_VIDEO_META_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa_texture.c b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa_texture.c
new file mode 100644 (file)
index 0000000..79863cb
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ *  gstvaapivideometa_texture.c - GStreamer/VA video meta (GLTextureUpload)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *  Copyright (C) 2013 Igalia
+ *    Author: Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gstcompat.h"
+#include "gst/vaapi/ogl_compat.h"
+#include "gstvaapivideometa.h"
+#include "gstvaapivideometa_texture.h"
+#include "gstvaapipluginutil.h"
+
+#if GST_VAAPI_USE_GLX
+#include <gst/vaapi/gstvaapitexture_glx.h>
+#endif
+
+#define DEFAULT_FORMAT GST_VIDEO_FORMAT_RGBA
+
+#if (GST_VAAPI_USE_GLX || GST_VAAPI_USE_EGL)
+struct _GstVaapiVideoMetaTexture
+{
+  GstVaapiTexture *texture;
+  GstVideoGLTextureType texture_type[4];
+  guint gl_format;
+  guint width;
+  guint height;
+};
+
+static guint
+get_texture_orientation_flags (GstVideoGLTextureOrientation orientation)
+{
+  guint flags;
+
+  switch (orientation) {
+    case GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_FLIP:
+      flags = GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED;
+      break;
+    case GST_VIDEO_GL_TEXTURE_ORIENTATION_X_FLIP_Y_NORMAL:
+      flags = GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED;
+      break;
+    case GST_VIDEO_GL_TEXTURE_ORIENTATION_X_FLIP_Y_FLIP:
+      flags = GST_VAAPI_TEXTURE_ORIENTATION_FLAG_X_INVERTED |
+          GST_VAAPI_TEXTURE_ORIENTATION_FLAG_Y_INVERTED;
+      break;
+    default:
+      flags = 0;
+      break;
+  }
+  return flags;
+}
+
+static gboolean
+meta_texture_ensure_format (GstVaapiVideoMetaTexture * meta,
+    GstVideoFormat format)
+{
+  memset (meta->texture_type, 0, sizeof (meta->texture_type));
+
+  switch (format) {
+    case GST_VIDEO_FORMAT_RGBA:
+      meta->gl_format = GL_RGBA;
+      meta->texture_type[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
+      break;
+    case GST_VIDEO_FORMAT_BGRA:
+      meta->gl_format = GL_BGRA_EXT;
+      /* FIXME: add GST_VIDEO_GL_TEXTURE_TYPE_BGRA extension */
+      meta->texture_type[0] = GST_VIDEO_GL_TEXTURE_TYPE_RGBA;
+      break;
+    default:
+      goto error_unsupported_format;
+  }
+  return TRUE;
+
+  /* ERRORS */
+error_unsupported_format:
+  GST_ERROR ("unsupported texture format %s",
+      gst_video_format_to_string (format));
+  return FALSE;
+}
+
+static gboolean
+meta_texture_ensure_info_from_buffer (GstVaapiVideoMetaTexture * meta,
+    GstBuffer * buffer)
+{
+  GstVideoMeta *vmeta;
+  GstVideoFormat format;
+
+  if (!buffer || !(vmeta = gst_buffer_get_video_meta (buffer))) {
+    format = DEFAULT_FORMAT;
+    meta->width = 0;
+    meta->height = 0;
+  } else {
+    const GstVideoFormatInfo *const fmt_info =
+        gst_video_format_get_info (vmeta->format);
+    format = (fmt_info && GST_VIDEO_FORMAT_INFO_IS_RGB (fmt_info)) ?
+        vmeta->format : DEFAULT_FORMAT;
+    meta->width = vmeta->width;
+    meta->height = vmeta->height;
+  }
+  return meta_texture_ensure_format (meta, format);
+}
+
+static void
+meta_texture_free (GstVaapiVideoMetaTexture * meta)
+{
+  if (G_UNLIKELY (!meta))
+    return;
+
+  gst_mini_object_replace ((GstMiniObject **) & meta->texture, NULL);
+  g_slice_free (GstVaapiVideoMetaTexture, meta);
+}
+
+static GstVaapiVideoMetaTexture *
+meta_texture_new (void)
+{
+  GstVaapiVideoMetaTexture *meta;
+
+  meta = g_slice_new (GstVaapiVideoMetaTexture);
+  if (!meta)
+    return NULL;
+
+  meta->texture = NULL;
+  if (!meta_texture_ensure_info_from_buffer (meta, NULL))
+    goto error;
+  return meta;
+
+  /* ERRORS */
+error:
+  {
+    meta_texture_free (meta);
+    return NULL;
+  }
+}
+
+static GstVaapiVideoMetaTexture *
+meta_texture_copy (GstVaapiVideoMetaTexture * meta)
+{
+  GstVaapiVideoMetaTexture *copy;
+
+  copy = meta_texture_new ();
+  if (!copy)
+    return NULL;
+
+  memcpy (copy->texture_type, meta->texture_type, sizeof (meta->texture_type));
+  copy->gl_format = meta->gl_format;
+  copy->width = meta->width;
+  copy->height = meta->height;
+
+  gst_mini_object_replace ((GstMiniObject **) & copy->texture,
+      (GstMiniObject *) meta->texture);
+  return copy;
+}
+
+static gboolean
+gst_vaapi_texture_upload (GstVideoGLTextureUploadMeta * meta,
+    guint texture_id[4])
+{
+  GstVaapiVideoMeta *const vmeta =
+      gst_buffer_get_vaapi_video_meta (meta->buffer);
+  GstVaapiVideoMetaTexture *const meta_texture = meta->user_data;
+  GstVaapiSurfaceProxy *const proxy =
+      gst_vaapi_video_meta_get_surface_proxy (vmeta);
+  GstVaapiSurface *const surface = gst_vaapi_surface_proxy_get_surface (proxy);
+  GstVaapiDisplay *const dpy = gst_vaapi_surface_get_display (surface);
+  GstVaapiTexture *texture = NULL;
+
+  if (!gst_vaapi_display_has_opengl (dpy))
+    return FALSE;
+
+  if (meta_texture->texture
+      /* Check whether VA display changed */
+      && GST_VAAPI_TEXTURE_DISPLAY (meta_texture->texture) == dpy
+      /* Check whether texture id changed */
+      && (gst_vaapi_texture_get_id (meta_texture->texture) == texture_id[0])) {
+    texture = meta_texture->texture;
+  }
+
+  if (!texture) {
+    /* FIXME: should we assume target? */
+    texture =
+        gst_vaapi_texture_new_wrapped (dpy, texture_id[0],
+        GL_TEXTURE_2D, meta_texture->gl_format, meta_texture->width,
+        meta_texture->height);
+  }
+
+  if (meta_texture->texture != texture) {
+    gst_mini_object_replace ((GstMiniObject **) & meta_texture->texture,
+        (GstMiniObject *) texture);
+  }
+
+  if (!texture)
+    return FALSE;
+
+  gst_vaapi_texture_set_orientation_flags (meta_texture->texture,
+      get_texture_orientation_flags (meta->texture_orientation));
+
+  return gst_vaapi_texture_put_surface (meta_texture->texture, surface,
+      gst_vaapi_surface_proxy_get_crop_rect (proxy),
+      gst_vaapi_video_meta_get_render_flags (vmeta));
+}
+
+GstMeta *
+gst_buffer_add_texture_upload_meta (GstBuffer * buffer)
+{
+  GstVaapiVideoMetaTexture *meta_texture;
+
+  if (!buffer)
+    return FALSE;
+
+  meta_texture = meta_texture_new ();
+  if (!meta_texture)
+    return FALSE;
+
+  if (!meta_texture_ensure_info_from_buffer (meta_texture, buffer))
+    goto error;
+
+  return (GstMeta *) gst_buffer_add_video_gl_texture_upload_meta (buffer,
+      GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL, 1,
+      meta_texture->texture_type, gst_vaapi_texture_upload, meta_texture,
+      (GBoxedCopyFunc) meta_texture_copy, (GBoxedFreeFunc) meta_texture_free);
+
+  /* ERRORS */
+error:
+  {
+    meta_texture_free (meta_texture);
+    return NULL;
+  }
+}
+
+gboolean
+gst_buffer_ensure_texture_upload_meta (GstBuffer * buffer)
+{
+  GstVideoGLTextureUploadMeta *const meta =
+      gst_buffer_get_video_gl_texture_upload_meta (buffer);
+
+  return meta ?
+      meta_texture_ensure_info_from_buffer (meta->user_data, buffer) :
+      (gst_buffer_add_texture_upload_meta (buffer) != NULL);
+}
+#endif
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa_texture.h b/subprojects/gstreamer-vaapi/gst/vaapi/gstvaapivideometa_texture.h
new file mode 100644 (file)
index 0000000..bf369ba
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ *  gstvaapivideometa_texture.h - GStreamer/VA video meta (GLTextureUpload)
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *  Copyright (C) 2013 Igalia
+ *    Author: Víctor Manuel Jáquez Leal <vjaquez@igalia.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef GST_VAAPI_VIDEO_META_TEXTURE_H
+#define GST_VAAPI_VIDEO_META_TEXTURE_H
+
+#include <gst/vaapi/gstvaapitexture.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstVaapiVideoMetaTexture GstVaapiVideoMetaTexture;
+
+G_GNUC_INTERNAL
+GstMeta *
+gst_buffer_add_texture_upload_meta (GstBuffer * buffer);
+
+G_GNUC_INTERNAL
+gboolean
+gst_buffer_ensure_texture_upload_meta (GstBuffer * buffer);
+
+G_END_DECLS
+
+#endif /* GST_VAAPI_VIDEO_META_TEXTURE_H */
diff --git a/subprojects/gstreamer-vaapi/gst/vaapi/meson.build b/subprojects/gstreamer-vaapi/gst/vaapi/meson.build
new file mode 100644 (file)
index 0000000..4265759
--- /dev/null
@@ -0,0 +1,47 @@
+vaapi_sources = [
+  'gstvaapi.c',
+  'gstvaapidecode.c',
+  'gstvaapidecodedoc.c',
+  'gstvaapioverlay.c',
+  'gstvaapipluginbase.c',
+  'gstvaapipluginutil.c',
+  'gstvaapipostproc.c',
+  'gstvaapipostprocutil.c',
+  'gstvaapisink.c',
+  'gstvaapivideobuffer.c',
+  'gstvaapivideocontext.c',
+  'gstvaapivideometa.c',
+  'gstvaapidecodebin.c',
+  'gstvaapivideobufferpool.c',
+  'gstvaapivideomemory.c',
+  'gstvaapivideometa_texture.c',
+  'gstvaapidecode_props.c',
+]
+
+if USE_ENCODERS
+  vaapi_sources += [
+      'gstvaapiencode.c',
+      'gstvaapiencode_h264.c',
+      'gstvaapiencode_h265.c',
+      'gstvaapiencode_jpeg.c',
+      'gstvaapiencode_mpeg2.c',
+      'gstvaapiencode_vp8.c',
+    ]
+endif
+
+if USE_VP9_ENCODER
+  vaapi_sources += 'gstvaapiencode_vp9.c'
+endif
+
+gstvaapi = library('gstvaapi',
+  vaapi_sources,
+  c_args : gstreamer_vaapi_args + ['-DGST_USE_UNSTABLE_API'],
+  include_directories : [configinc, libsinc],
+  dependencies : [gstbase_dep, gstvideo_dep, gstallocators_dep, gstpbutils_dep,
+    libva_dep, gstlibvaapi_dep, gstgl_dep, gstglproto_dep, gstglx11_dep, gstglegl_dep,
+    gstglwayland_dep, libm],
+  install : true,
+  install_dir : plugins_install_dir,
+)
+
+plugins = [gstvaapi]
diff --git a/subprojects/gstreamer-vaapi/gstreamer-vaapi.doap b/subprojects/gstreamer-vaapi/gstreamer-vaapi.doap
new file mode 100644 (file)
index 0000000..63205bf
--- /dev/null
@@ -0,0 +1,501 @@
+<Project
+    xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+    xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#"
+    xmlns="http://usefulinc.com/ns/doap#"
+    xmlns:foaf="http://xmlns.com/foaf/0.1/"
+    xmlns:admin="http://webns.net/mvcb/">
+
+  <name>GStreamer VA-API</name>
+  <shortname>gstreamer-vaapi</shortname>
+  <shortdesc xml:lang="en">a set of VA-API based elements for GStreamer</shortdesc>
+  <description xml:lang="en">
+    GStreamer VA-API is a collection of VA-API based plugin with video
+    processing elements for GStreamer.
+  </description>
+  <homepage rdf:resource="http://gstreamer.freedesktop.org/modules/gstreamer-vaapi.html"/>
+  <download-page rdf:resource="http://gstreamer.freedesktop.org/download/"/>
+  <bug-database rdf:resource="https://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi/issues/"/>
+  <programming-language>C</programming-language>
+  <license rdf:resource="http://usefulinc.com/doap/licenses/lgpl"/>
+
+  <repository>
+    <GitRepository>
+      <location rdf:resource="git://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi"/>
+      <browse rdf:resource="http://gitlab.freedesktop.org/gstreamer/gstreamer-vaapi"/>
+    </GitRepository>
+  </repository>
+
+ <release>
+  <Version>
+   <revision>1.22.8</revision>
+   <branch>1.22</branch>
+   <name></name>
+   <created>2023-12-18</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.22.8.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.22.7</revision>
+   <branch>1.22</branch>
+   <name></name>
+   <created>2023-11-13</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.22.7.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.22.6</revision>
+   <branch>1.22</branch>
+   <name></name>
+   <created>2023-09-20</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.22.6.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.22.5</revision>
+   <branch>1.22</branch>
+   <name></name>
+   <created>2023-07-20</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.22.5.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.22.4</revision>
+   <branch>1.22</branch>
+   <name></name>
+   <created>2023-06-20</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.22.4.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.22.3</revision>
+   <branch>1.22</branch>
+   <name></name>
+   <created>2023-05-19</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.22.3.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.22.2</revision>
+   <branch>1.22</branch>
+   <name></name>
+   <created>2023-04-11</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.22.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.22.1</revision>
+   <branch>1.22</branch>
+   <name></name>
+   <created>2023-03-04</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.22.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.22.0</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2023-01-23</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.22.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.21.90</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2023-01-13</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.21.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.21.3</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2022-12-05</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.21.3.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.21.2</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2022-11-07</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.21.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.21.1</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2022-10-04</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.21.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.20.0</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2022-02-03</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.20.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.19.90</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2022-01-28</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.19.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.19.3</revision>
+   <branch>main</branch>
+   <name></name>
+   <created>2021-11-03</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.19.3.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.19.2</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2021-09-23</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.19.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.19.1</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2021-06-01</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.19.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.18.0</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2020-09-08</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.18.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.17.90</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2020-08-20</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.17.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.17.2</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2020-07-03</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.17.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.17.1</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2020-06-19</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.17.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.16.0</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2019-04-19</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.16.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.15.90</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2019-04-11</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.15.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.15.2</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2019-02-26</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.15.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.15.1</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2019-01-17</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.15.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.14.0</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2018-03-19</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.14.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.13.91</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2018-03-13</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.13.91.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.13.90</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2018-03-03</created>
+   <file-release rdf:resource="https://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.13.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.13.1</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2018-02-15</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.13.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.12.4</revision>
+   <branch>1.12</branch>
+   <name></name>
+   <created>2017-12-07</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.12.4.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.12.3</revision>
+   <branch>1.12</branch>
+   <name></name>
+   <created>2017-09-18</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.12.3.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.12.2</revision>
+   <branch>1.12</branch>
+   <name></name>
+   <created>2017-07-14</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.12.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.12.1</revision>
+   <branch>1.12</branch>
+   <name></name>
+   <created>2017-06-20</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.12.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.12.0</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-05-04</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.12.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.11.91</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-04-27</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.11.91.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.11.90</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-04-07</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.11.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.11.2</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-02-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.11.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.11.1</revision>
+   <branch>master</branch>
+   <name></name>
+   <created>2017-01-12</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.11.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.10.0</revision>
+   <branch>master</branch>
+   <created>2016-11-01</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.10.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.9.90</revision>
+   <branch>master</branch>
+   <created>2016-09-30</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.9.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.9.2</revision>
+   <branch>master</branch>
+   <created>2016-09-01</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.9.2.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.9.1</revision>
+   <branch>master</branch>
+   <created>2016-06-06</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.9.1.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.8.0</revision>
+   <branch>master</branch>
+   <created>2016-03-24</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.8.0.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.7.91</revision>
+   <branch>master</branch>
+   <created>2016-03-15</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.7.91.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.7.90</revision>
+   <branch>master</branch>
+   <created>2016-03-01</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.7.90.tar.xz" />
+  </Version>
+ </release>
+
+ <release>
+  <Version>
+   <revision>1.6.0</revision>
+   <branch>master</branch>
+   <created>2016-02-14</created>
+   <file-release rdf:resource="http://gstreamer.freedesktop.org/src/gstreamer-vaapi/gstreamer-vaapi-1.6.0.tar.xz" />
+  </Version>
+ </release>
+
+  <maintainer>
+    <foaf:Person>
+      <foaf:name>Sreerenj Balachandran</foaf:name>
+    </foaf:Person>
+  </maintainer>
+  <maintainer>
+    <foaf:Person>
+      <foaf:name>Victor Jaquez</foaf:name>
+    </foaf:Person>
+  </maintainer>>
+
+</Project>
diff --git a/subprojects/gstreamer-vaapi/meson.build b/subprojects/gstreamer-vaapi/meson.build
new file mode 100644 (file)
index 0000000..2849f89
--- /dev/null
@@ -0,0 +1,265 @@
+project('gstreamer-vaapi', 'c',
+  version : '1.22.8',
+  meson_version : '>= 0.62',
+  default_options : [ 'warning_level=1',
+                      'buildtype=debugoptimized' ])
+
+if get_option('default_library') == 'static'
+  error('GStreamer-VAAPI plugin not supported with `static` builds yet.')
+endif
+
+gst_version = meson.project_version()
+version_arr = gst_version.split('.')
+gst_version_major = version_arr[0].to_int()
+gst_version_minor = version_arr[1].to_int()
+gst_version_micro = version_arr[2].to_int()
+
+if version_arr.length() == 4
+  gst_version_nano = version_arr[3].to_int()
+else
+  gst_version_nano = 0
+endif
+
+libva_req = ['>= 0.39.0', '!= 0.99.0']
+libwayland_req = '>= 1.11.0'
+libdrm_req = '>= 2.4.98'
+gst_req = '>= @0@.@1@.0'.format(gst_version_major, gst_version_minor)
+
+cc = meson.get_compiler('c')
+static_build = get_option('default_library') == 'static'
+
+if cc.has_link_argument('-Wl,-Bsymbolic-functions')
+  add_project_link_arguments('-Wl,-Bsymbolic-functions', language : 'c')
+endif
+
+# Symbol visibility
+if cc.has_argument('-fvisibility=hidden')
+  add_project_arguments('-fvisibility=hidden', language: 'c')
+endif
+
+# Disable strict aliasing
+if cc.has_argument('-fno-strict-aliasing')
+  add_project_arguments('-fno-strict-aliasing', language: 'c')
+endif
+
+# Mandatory GST deps
+libm = cc.find_library('m', required : false)
+gst_dep = dependency('gstreamer-1.0', version : gst_req,
+  fallback : ['gstreamer', 'gst_dep'])
+gstbase_dep = dependency('gstreamer-base-1.0', version : gst_req,
+  fallback : ['gstreamer', 'gst_base_dep'])
+gstpbutils_dep = dependency('gstreamer-pbutils-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'pbutils_dep'])
+gstallocators_dep = dependency('gstreamer-allocators-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'allocators_dep'])
+gstvideo_dep = dependency('gstreamer-video-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'video_dep'])
+gstcodecparsers_dep = dependency('gstreamer-codecparsers-1.0', version : gst_req,
+    fallback : ['gst-plugins-bad', 'gstcodecparsers_dep'])
+gstgl_dep = dependency('gstreamer-gl-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'gstgl_dep'], required: false)
+gstglproto_dep = dependency('', required : false)
+gstglx11_dep = dependency('', required : false)
+gstglwayland_dep = dependency('', required : false)
+gstglegl_dep = dependency('', required : false)
+
+# Disable compiler warnings for unused variables and args if gst debug system is disabled
+if gst_dep.type_name() == 'internal'
+  gst_debug_disabled = not subproject('gstreamer').get_variable('gst_debug')
+else
+  # We can't check that in the case of subprojects as we won't
+  # be able to build against an internal dependency (which is not built yet)
+  gst_debug_disabled = cc.has_header_symbol('gst/gstconfig.h', 'GST_DISABLE_GST_DEBUG', dependencies: gst_dep)
+endif
+
+if gst_debug_disabled
+  message('GStreamer debug system is disabled')
+  add_project_arguments(cc.get_supported_arguments(['-Wno-unused']), language: 'c')
+else
+  message('GStreamer debug system is enabled')
+endif
+
+libva_dep = dependency('libva', version: libva_req,
+  fallback : ['libva', 'libva_dep'])
+libva_drm_dep = dependency('libva-drm', version: libva_req,
+  required: get_option('drm'), fallback : ['libva', 'libva_drm_dep'])
+libva_wayland_dep = dependency('libva-wayland', version: libva_req,
+  required: get_option('wayland'), fallback : ['libva', 'libva_wayland_dep'])
+libva_x11_dep = dependency('libva-x11', version: libva_req,
+  required: get_option('x11'), fallback : ['libva', 'libva_x11_dep'])
+
+libdrm_dep = dependency('libdrm', version: libdrm_req,
+  required: get_option('drm'), fallback: ['libdrm', 'ext_libdrm'])
+libudev_dep = dependency('libudev', required: get_option('drm'))
+
+x11_dep = dependency('x11', required: get_option('x11'))
+xrandr_dep = dependency('xrandr', required: get_option('x11'))
+
+gmodule_dep = dependency('gmodule-no-export-2.0')
+egl_dep = dependency('egl', required: get_option('egl'))
+glesv2_dep = dependency('glesv2', required: false)
+
+glx_option = get_option('glx').require(libva_x11_dep.found() and x11_dep.found(),
+    error_message: 'glx requires libva-x11 and x11 dependency')
+gl_dep = dependency('gl', required: glx_option)
+libdl_dep = cc.find_library('dl', required: glx_option)
+
+wayland_option = get_option('wayland').require(libdrm_dep.found(),
+    error_message: 'wayland requires libdrm dependency')
+wayland_client_dep = dependency('wayland-client', version: libwayland_req,
+  required: wayland_option)
+wayland_protocols_dep = dependency('wayland-protocols', version: '>= 1.15',
+  required: wayland_option)
+wayland_scanner_bin = find_program('wayland-scanner', required: wayland_option)
+
+gstcheck_dep = dependency('gstreamer-check-1.0', version : gst_req,
+  required : get_option('tests'),
+  fallback : ['gstreamer', 'gst_check_dep'])
+
+# some of the examples can use GTK+-3
+gtk_dep = dependency('gtk+-3.0', version : '>= 3.10', required : get_option('examples'))
+
+GLES_VERSION_MASK = gl_dep.found() ? 1 : 0
+if glesv2_dep.found()
+  if (cc.has_header('GLES2/gl2.h', dependencies: glesv2_dep) and
+      cc.has_header('GLES2/gl2ext.h', dependencies: glesv2_dep))
+    GLES_VERSION_MASK += 4
+  endif
+  if (cc.has_header('GLES3/gl3.h', dependencies: glesv2_dep) and
+      cc.has_header('GLES3/gl3ext.h', dependencies: glesv2_dep) and
+      cc.has_header('GLES2/gl2ext.h', dependencies: glesv2_dep))
+    GLES_VERSION_MASK += 8
+  endif
+endif
+
+USE_ENCODERS = get_option('encoders').allowed()
+USE_VP9_ENCODER = USE_ENCODERS and libva_dep.version().version_compare('>= 0.40.0')
+USE_AV1_DECODER = libva_dep.version().version_compare('>= 1.10')
+
+USE_DRM = (libva_drm_dep.found()
+    and libdrm_dep.found()
+    and libudev_dep.found())
+USE_EGL = (egl_dep.found()
+    and GLES_VERSION_MASK != 0)
+USE_WAYLAND = (libva_wayland_dep.found()
+    and wayland_client_dep.found()
+    and wayland_protocols_dep.found()
+    and wayland_scanner_bin.found()
+    and libdrm_dep.found())
+USE_X11 = (libva_x11_dep.found() and x11_dep.found())
+USE_GLX = (USE_X11 and gl_dep.found() and libdl_dep.found())
+
+if not (USE_DRM or USE_X11 or USE_WAYLAND)
+  error('No renderer API found (it is requried either DRM, X11 and/or WAYLAND)')
+endif
+
+if gstgl_dep.found()
+  gstglproto_dep = dependency('gstreamer-gl-prototypes-1.0', version : gst_req,
+    fallback : ['gst-plugins-base', 'gstglproto_dep'], required: true)
+  # Behind specific checks because meson fails at optional dependencies with a
+  # fallback to the same subproject.  On the first failure, meson will never
+  # check the system again even if the fallback never existed.
+  # Last checked with meson 0.54.3
+  if USE_X11
+    gstglx11_dep = dependency('gstreamer-gl-x11-1.0', version : gst_req,
+       fallback : ['gst-plugins-base', 'gstglx11_dep'], required: true)
+  endif
+  if USE_WAYLAND
+    gstglwayland_dep = dependency('gstreamer-gl-wayland-1.0', version : gst_req,
+        fallback : ['gst-plugins-base', 'gstglwayland_dep'], required: true)
+  endif
+  if USE_EGL
+    gstglegl_dep = dependency('gstreamer-gl-egl-1.0', version : gst_req,
+        fallback : ['gst-plugins-base', 'gstglegl_dep'], required: true)
+  endif
+endif
+
+driverdir = libva_dep.get_variable('driverdir', default_value: '')
+if driverdir == ''
+  driverdir = join_paths(get_option('prefix'), get_option('libdir'), 'dri')
+endif
+
+cdata = configuration_data()
+cdata.set_quoted('GST_API_VERSION_S', '@0@.@1@'.format(gst_version_major, gst_version_minor))
+cdata.set_quoted('PACKAGE', 'gstreamer-vaapi')
+cdata.set_quoted('VERSION', '@0@'.format(gst_version))
+cdata.set_quoted('PACKAGE_VERSION', '@0@'.format(gst_version))
+cdata.set_quoted('PACKAGE_NAME', 'GStreamer VA-API Plug-ins')
+cdata.set_quoted('PACKAGE_STRING', 'GStreamer VA-API Plug-ins @0@'.format(gst_version))
+cdata.set_quoted('PACKAGE_BUGREPORT', get_option('package-origin'))
+cdata.set_quoted('VA_DRIVERS_PATH', '@0@'.format(driverdir))
+cdata.set10('GST_VAAPI_USE_DRM', USE_DRM)
+cdata.set10('GST_VAAPI_USE_EGL', USE_EGL)
+cdata.set10('GST_VAAPI_USE_ENCODERS', USE_ENCODERS)
+cdata.set10('GST_VAAPI_USE_GLX', USE_GLX)
+cdata.set10('GST_VAAPI_USE_VP9_ENCODER', USE_VP9_ENCODER)
+cdata.set10('GST_VAAPI_USE_AV1_DECODER', USE_AV1_DECODER)
+cdata.set10('GST_VAAPI_USE_WAYLAND', USE_WAYLAND)
+cdata.set10('GST_VAAPI_USE_X11', USE_X11)
+cdata.set10('HAVE_XKBLIB', cc.has_header('X11/XKBlib.h', dependencies: x11_dep))
+cdata.set10('HAVE_XRANDR', xrandr_dep.found())
+cdata.set10('USE_GST_GL_HELPERS', gstgl_dep.found())
+cdata.set('USE_GLES_VERSION_MASK', GLES_VERSION_MASK)
+
+api_version = '1.0'
+soversion = 0
+# maintaining compatibility with the previous libtool versioning
+# current = minor * 100 + micro
+curversion = gst_version_minor * 100 + gst_version_micro
+libversion = '@0@.@1@.0'.format(soversion, curversion)
+osxversion = curversion + 1
+
+plugins_install_dir = '@0@/gstreamer-1.0'.format(get_option('libdir'))
+
+gstreamer_vaapi_args = ['-DHAVE_CONFIG_H']
+configinc = include_directories('.')
+libsinc = include_directories('gst-libs')
+
+plugins = []
+
+subdir('gst-libs')
+subdir('gst')
+subdir('tests')
+subdir('docs')
+
+# Set release date
+if gst_version_nano == 0
+  extract_release_date = find_program('scripts/extract-release-date-from-doap-file.py')
+  run_result = run_command(extract_release_date, gst_version, files('gstreamer-vaapi.doap'), check: true)
+  release_date = run_result.stdout().strip()
+  cdata.set_quoted('GST_PACKAGE_RELEASE_DATETIME', release_date)
+  message('Package release date: ' + release_date)
+endif
+
+if gmodule_dep.version().version_compare('< 2.67.4')
+  cdata.set('g_memdup2(ptr,sz)', '(G_LIKELY(((guint64)(sz)) < G_MAXUINT)) ? g_memdup(ptr,sz) : (g_abort(),NULL)')
+endif
+
+configure_file(output: 'config.h', configuration: cdata)
+
+meson.add_dist_script('scripts/gen-changelog.py', meson.project_name(), '1.20.0', meson.project_version())
+
+pkgconfig = import('pkgconfig')
+plugins_pkgconfig_install_dir = join_paths(plugins_install_dir, 'pkgconfig')
+if get_option('default_library') == 'shared'
+  # If we don't build static plugins there is no need to generate pc files
+  plugins_pkgconfig_install_dir = disabler()
+endif
+
+plugin_names = []
+gst_plugins = []
+foreach plugin: plugins
+  pkgconfig.generate(plugin, install_dir: plugins_pkgconfig_install_dir)
+  dep = declare_dependency(link_with: plugin, variables: {'full_path': plugin.full_path()})
+  meson.override_dependency(plugin.name(), dep)
+  gst_plugins += [dep]
+  if plugin.name().startswith('gst')
+    plugin_names += [plugin.name().substring(3)]
+  else
+    plugin_names += [plugin.name()]
+  endif
+endforeach
+
+summary({
+    'Plugins': plugin_names,
+}, list_sep: ', ')
diff --git a/subprojects/gstreamer-vaapi/meson_options.txt b/subprojects/gstreamer-vaapi/meson_options.txt
new file mode 100644 (file)
index 0000000..daa9b10
--- /dev/null
@@ -0,0 +1,15 @@
+option('encoders', type : 'feature', value : 'auto')
+option('drm', type : 'feature', value : 'auto')
+option('x11', type : 'feature', value : 'auto')
+option('glx', type : 'feature', value : 'auto')
+option('wayland', type : 'feature', value : 'auto')
+option('egl', type : 'feature', value : 'auto')
+
+# Common feature options
+option('examples', type : 'feature', value : 'auto', yield : true)
+option('tests', type : 'feature', value : 'auto', yield : true)
+option('doc', type : 'feature', value : 'auto', yield: true,
+       description: 'Enable documentation.')
+option('package-origin', type : 'string',
+       value : 'Unknown package origin',
+       yield : true, description : 'package origin URL to use in plugins')
diff --git a/subprojects/gstreamer-vaapi/scripts/extract-release-date-from-doap-file.py b/subprojects/gstreamer-vaapi/scripts/extract-release-date-from-doap-file.py
new file mode 100644 (file)
index 0000000..f09b60e
--- /dev/null
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+#
+# extract-release-date-from-doap-file.py VERSION DOAP-FILE
+#
+# Extract release date for the given release version from a DOAP file
+#
+# Copyright (C) 2020 Tim-Philipp Müller <tim centricular com>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Library General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# Library General Public License for more details.
+#
+# You should have received a copy of the GNU Library General Public
+# License along with this library; if not, write to the
+# Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+# Boston, MA 02110-1301, USA.
+
+import sys
+import xml.etree.ElementTree as ET
+
+if len(sys.argv) != 3:
+  sys.exit('Usage: {} VERSION DOAP-FILE'.format(sys.argv[0]))
+
+release_version = sys.argv[1]
+doap_fn = sys.argv[2]
+
+tree = ET.parse(doap_fn)
+root = tree.getroot()
+
+namespaces = {'doap': 'http://usefulinc.com/ns/doap#'}
+
+for v in root.findall('doap:release/doap:Version', namespaces=namespaces):
+  if v.findtext('doap:revision', namespaces=namespaces) == release_version:
+    release_date = v.findtext('doap:created', namespaces=namespaces)
+    if release_date:
+      print(release_date)
+      sys.exit(0)
+
+sys.exit('Could not find a release with version {} in {}'.format(release_version, doap_fn))
diff --git a/subprojects/gstreamer-vaapi/scripts/gen-changelog.py b/subprojects/gstreamer-vaapi/scripts/gen-changelog.py
new file mode 100644 (file)
index 0000000..3924e6e
--- /dev/null
@@ -0,0 +1,240 @@
+#!/usr/bin/env python3
+#
+# Makes a GNU-Style ChangeLog from a git repository
+import os
+import sys
+import subprocess
+import re
+
+meson_source_root = os.environ.get('MESON_SOURCE_ROOT')
+
+meson_dist_root = os.environ.get('MESON_DIST_ROOT')
+if meson_dist_root:
+    output_fn = os.path.join(meson_dist_root, 'ChangeLog')
+else:
+    output_fn = sys.stdout.fileno()
+
+# commit hash => release version tag string
+release_refs = {}
+
+# These are the pre-monorepo module beginnings
+changelog_starts = {
+    'gstreamer': '70521179a75db0c7230cc47c6d7f9d63cf73d351',
+    'gst-plugins-base': '68746a38d5e48e6f7c220663dcc2f175ff55cb3c',
+    'gst-plugins-good': '81f63142d65b62b0971c19ceb79956c49ffc2f06',
+    'gst-plugins-ugly': '7d7c3e478e32b7b66c44cc4442d571fbab534740',
+    'gst-plugins-bad': 'ea6821e2934fe8d356ea89d5610f0630b3446877',
+    'gst-libav': '3c440154c60d1ec0a54186f0fad4aebfd2ecc3ea',
+    'gst-rtsp-server': '5029c85a46a8c366c4bf272d503e22bbcd624ece',
+    'gst-editing-services': 'ee8bf88ebf131cf7c7161356540efc20bf411e14',
+    'gst-python': 'b3e564eff577e2f577d795051bbcca85d47c89dc',
+    'gstreamer-vaapi': 'c89e9afc5d43837c498a55f8f13ddf235442b83b',
+    'gst-omx': 'd2463b017f222e678978582544a9c9a80edfd330',
+    'gst-devtools': 'da962d096af9460502843e41b7d25fdece7ff1c2',
+    'gstreamer-sharp': 'b94528f8e7979df49fedf137dfa228d8fe475e1b',
+}
+
+
+def print_help():
+    print('', file=sys.stderr)
+    print('gen-changelog: generate GNU-style changelog from git history',
+          file=sys.stderr)
+    print('', file=sys.stderr)
+    print('Usage: {} [OPTIONS] GSTREAMER-MODULE [START-TAG] [HEAD-TAG]'.format(
+        sys.argv[0]), file=sys.stderr)
+    print('', file=sys.stderr)
+    sys.exit(1)
+
+
+if len(sys.argv) < 2 or len(sys.argv) > 4 or '--help' in sys.argv:
+    print_help()
+
+module = sys.argv[1]
+
+if len(sys.argv) > 2:
+    start_tag = sys.argv[2]
+else:
+    start_tag = None
+
+if len(sys.argv) > 3:
+    head_tag = sys.argv[3]
+else:
+    head_tag = None
+
+if module not in changelog_starts:
+    print(f'Unknown module {module}', file=sys.stderr)
+    print_help()
+
+
+def process_commit(lines, files, subtree_path=None):
+    # DATE NAME
+    # BLANK LINE
+    # Subject
+    # BLANK LINE
+    # ...
+    # FILES
+    fileincommit = False
+    lines = [x.strip() for x in lines if x.strip()
+             and not x.startswith('git-svn-id')]
+    files = [x.strip() for x in files if x.strip()]
+    for line in lines:
+        if line.startswith('* ') and ':' in line:
+            fileincommit = True
+            break
+
+    top_line = lines[0]
+    print(top_line.strip())
+    print()
+    if not fileincommit:
+        for f in files:
+            if subtree_path and f.startswith(subtree_path):
+                # requires Python 3.9
+                print('\t* %s:' % f.removeprefix(subtree_path))
+            else:
+                print('\t* %s:' % f)
+    for line in lines[1:]:
+        print('\t ', line)
+    print()
+
+
+def output_commits(module, start_tag, end_tag, subtree_path=None):
+    # retrieve commit date for start tag so we can filter the log for commits
+    # after that date. That way we don't include commits from merged-in
+    # plugin-move branches that go back to the beginning of time.
+    start_date = get_commit_date_for_ref(start_tag)
+
+    cmd = ['git', 'log',
+           '--pretty=format:--START-COMMIT--%H%n%ai  %an <%ae>%n%n%s%n%b%n--END-COMMIT--',
+           '--date=short',
+           '--name-only',
+           f'--since={start_date}',
+           f'{start_tag}..{end_tag}',
+           ]
+
+    if subtree_path:
+        cmd += ['--', '.']
+
+    p = subprocess.Popen(args=cmd, shell=False,
+                         stdout=subprocess.PIPE, cwd=meson_source_root)
+    buf = []
+    files = []
+    filemode = False
+    for lin in [x.decode('utf8', errors='replace') for x in p.stdout.readlines()]:
+        if lin.startswith("--START-COMMIT--"):
+            commit_hash = lin[16:].strip()
+            if buf != []:
+                process_commit(buf, files, subtree_path)
+
+            if commit_hash in release_refs:
+                version_str = release_refs[commit_hash]
+                print(f'=== release {version_str} ===\n')
+
+            buf = []
+            files = []
+            filemode = False
+        elif lin.startswith("--END-COMMIT--"):
+            filemode = True
+        elif filemode is True:
+            files.append(lin)
+        else:
+            buf.append(lin)
+    if buf != []:
+        process_commit(buf, files, subtree_path)
+
+
+def get_commit_date_for_ref(ref):
+    cmd = ['git', 'log', '--pretty=format:%cI', '-1', ref]
+    r = subprocess.run(cmd, capture_output=True, text=True,
+                       check=True, cwd=meson_source_root)
+    commit_date = r.stdout.strip()
+    return commit_date
+
+
+def populate_release_tags_for_premonorepo_module(module_tag_prefix):
+    if module_tag_prefix != '':
+        cmd = ['git', 'tag', '--list', f'{module_tag_prefix}*']
+    else:
+        cmd = ['git', 'tag', '--list', '1.*', 'RELEASE-*']
+
+    p = subprocess.Popen(args=cmd, shell=False,
+                         stdout=subprocess.PIPE, cwd=meson_source_root)
+    for line in [x.decode('utf8') for x in p.stdout.readlines()]:
+        git_tag = line.strip()
+        version_str = git_tag.removeprefix(module_tag_prefix).removeprefix('RELEASE-').split('-')[0].replace('_', '.')
+        # might have been populated with post-monorepo tags already for gstreamer core
+        if version_str not in release_refs:
+            # find last commit before tag in module subdirectory
+            cmd = ['git', 'log', '--pretty=format:%H', '-1', git_tag]
+            r = subprocess.run(cmd, capture_output=True,
+                               text=True, check=True, cwd=meson_source_root)
+            commit_hash = r.stdout.strip()
+            release_refs[commit_hash] = version_str
+
+            # print(f'{git_tag} => {version_str} => {commit_hash}')
+
+
+def populate_release_tags_for_monorepo_subproject():
+    cmd = ['git', 'tag', '--list', '1.*']
+    p = subprocess.Popen(args=cmd, shell=False,
+                         stdout=subprocess.PIPE, cwd=meson_source_root)
+    for line in [x.decode('utf8') for x in p.stdout.readlines()]:
+        version_str = line.strip()
+        version_arr = version_str.split('.')
+        major = int(version_arr[0])
+        minor = int(version_arr[1])
+        micro = int(version_arr[2])
+        # ignore pre-monorepo versions
+        if major < 1:
+            continue
+        if major == 1 and minor < 19:
+            continue
+        if major == 1 and minor == 19 and micro < 2:
+            continue
+        # find last commit before tag in module subdirectory
+        cmd = ['git', 'log', '--pretty=format:%H',
+               '-1', version_str, '--', '.']
+        r = subprocess.run(cmd, capture_output=True, text=True,
+                           check=True, cwd=meson_source_root)
+        commit_hash = r.stdout.strip()
+        release_refs[commit_hash] = version_str
+
+
+if __name__ == '__main__':
+    module_tag_prefix = '' if module == 'gstreamer' else f'{module}-'
+
+    populate_release_tags_for_monorepo_subproject()
+
+    with open(output_fn, 'w') as f:
+        sys.stdout = f
+
+        # Force writing of head tag
+        if head_tag and head_tag not in release_refs.values():
+            print(f'=== release {head_tag} ===\n')
+
+        # Output all commits from start_tag onwards, otherwise output full history.
+        # (We assume the start_tag is after the monorepo merge if it's specified.)
+        if start_tag and start_tag != 'start':
+            output_commits(module, start_tag, 'HEAD', f'subprojects/{module}/')
+        else:
+            # First output all post-monorepo commits or commits from start_tag if specified
+            output_commits(module, 'monorepo-start',
+                           'HEAD', f'subprojects/{module}/')
+
+            populate_release_tags_for_premonorepo_module(module_tag_prefix)
+
+            # Next output all pre-monorepo commits (modules have their own root)
+            if not start_tag:
+                module_start = f'{module_tag_prefix}1.0.0'
+            elif start_tag == 'start':
+                module_start = changelog_starts[module]
+            else:
+                module_start = f'{module_tag_prefix}{start_tag}'
+
+            output_commits(module, module_start,
+                           f'{module_tag_prefix}1.19.2', None)
+
+        # Write start tag at end for clarity
+        if not start_tag:
+            print(f'=== release 1.0.0 ===\n')
+        elif start_tag != 'start':
+            print(f'=== release {start_tag} ===\n')
diff --git a/subprojects/gstreamer-vaapi/tests/check/elements/vaapioverlay.c b/subprojects/gstreamer-vaapi/tests/check/elements/vaapioverlay.c
new file mode 100644 (file)
index 0000000..8cc87dc
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ *  vaapioverlay.c - GStreamer unit test for the vaapioverlay element
+ *
+ *  Copyright (C) 2019 Intel Corporation
+ *    Author: U. Artie Eoff <ullysses.a.eoff@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+
+static GMainLoop *main_loop;
+
+static void
+message_received (GstBus * bus, GstMessage * message, GstPipeline * bin)
+{
+  GST_INFO ("bus message from \"%" GST_PTR_FORMAT "\": %" GST_PTR_FORMAT,
+      GST_MESSAGE_SRC (message), message);
+
+  switch (message->type) {
+    case GST_MESSAGE_EOS:
+      g_main_loop_quit (main_loop);
+      break;
+    case GST_MESSAGE_WARNING:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_warning (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      break;
+    }
+    case GST_MESSAGE_ERROR:{
+      GError *gerror;
+      gchar *debug;
+
+      gst_message_parse_error (message, &gerror, &debug);
+      gst_object_default_error (GST_MESSAGE_SRC (message), gerror, debug);
+      g_error_free (gerror);
+      g_free (debug);
+      g_main_loop_quit (main_loop);
+      break;
+    }
+    default:
+      break;
+  }
+}
+
+static GstBuffer *handoff_buffer = NULL;
+static void
+on_handoff (GstElement * element, GstBuffer * buffer, GstPad * pad,
+    gpointer data)
+{
+  gst_buffer_replace (&handoff_buffer, buffer);
+}
+
+#define TEST_PATTERN_RED 4
+#define TEST_PATTERN_GREEN 5
+
+GST_START_TEST (test_overlay_position)
+{
+  GstElement *bin, *src1, *filter1, *src2, *filter2, *overlay, *sink;
+  GstBus *bus;
+  GstPad *pad, *srcpad, *sinkpad;
+  GstCaps *caps;
+  GstVideoFrame frame;
+  GstVideoInfo vinfo;
+
+  /* Check if vaapioverlay is available, since it is only available
+   * for iHD vaapi driver */
+  overlay = gst_element_factory_make ("vaapioverlay", "overlay");
+  if (!overlay)
+    return;
+
+  /* build pipeline */
+  bin = gst_pipeline_new ("pipeline");
+  bus = gst_element_get_bus (bin);
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+
+  src1 = gst_element_factory_make ("videotestsrc", "src1");
+  g_object_set (src1, "num-buffers", 1, NULL);
+  g_object_set (src1, "pattern", TEST_PATTERN_GREEN, NULL);
+  filter1 = gst_element_factory_make ("capsfilter", "filter1");
+  caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "NV12",
+      "width", G_TYPE_INT, 320, "height", G_TYPE_INT, 240, NULL);
+  g_object_set (filter1, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  src2 = gst_element_factory_make ("videotestsrc", "src2");
+  g_object_set (src2, "num-buffers", 1, NULL);
+  g_object_set (src2, "pattern", TEST_PATTERN_RED, NULL);
+  filter2 = gst_element_factory_make ("capsfilter", "filter2");
+  caps = gst_caps_new_simple ("video/x-raw", "format", G_TYPE_STRING, "NV12",
+      "width", G_TYPE_INT, 20, "height", G_TYPE_INT, 20, NULL);
+  g_object_set (filter2, "caps", caps, NULL);
+  gst_caps_unref (caps);
+
+  sink = gst_element_factory_make ("vaapisink", "sink");
+  g_object_set (sink, "display", 4, "signal-handoffs", TRUE, NULL);
+  g_signal_connect (sink, "handoff", G_CALLBACK (on_handoff), NULL);
+
+  gst_bin_add_many (GST_BIN (bin), src1, filter1, src2, filter2, overlay,
+      sink, NULL);
+  gst_element_link (src1, filter1);
+  gst_element_link (src2, filter2);
+  gst_element_link (overlay, sink);
+
+  srcpad = gst_element_get_static_pad (filter1, "src");
+  sinkpad = gst_element_request_pad_simple (overlay, "sink_0");
+  g_object_set (sinkpad, "xpos", 0, "ypos", 0, "alpha", 1.0, NULL);
+  gst_pad_link (srcpad, sinkpad);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+
+  srcpad = gst_element_get_static_pad (filter2, "src");
+  sinkpad = gst_element_request_pad_simple (overlay, "sink_1");
+  g_object_set (sinkpad, "xpos", 10, "ypos", 10, "alpha", 1.0, NULL);
+  gst_pad_link (srcpad, sinkpad);
+  gst_object_unref (sinkpad);
+  gst_object_unref (srcpad);
+
+  /* setup and run the main loop */
+  main_loop = g_main_loop_new (NULL, FALSE);
+  g_signal_connect (bus, "message::error", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::warning", (GCallback) message_received, bin);
+  g_signal_connect (bus, "message::eos", (GCallback) message_received, bin);
+  gst_element_set_state (bin, GST_STATE_PAUSED);
+  gst_element_get_state (bin, NULL, NULL, GST_CLOCK_TIME_NONE);
+  gst_element_set_state (bin, GST_STATE_PLAYING);
+  g_main_loop_run (main_loop);
+
+  /* validate output buffer */
+  fail_unless (handoff_buffer != NULL);
+  pad = gst_element_get_static_pad (sink, "sink");
+  caps = gst_pad_get_current_caps (pad);
+  gst_video_info_from_caps (&vinfo, caps);
+  gst_caps_unref (caps);
+  gst_object_unref (pad);
+
+  gst_video_frame_map (&frame, &vinfo, handoff_buffer, GST_MAP_READ);
+  {
+    guint i, j, n_planes, plane;
+    n_planes = GST_VIDEO_FRAME_N_PLANES (&frame);
+
+    for (plane = 0; plane < n_planes; plane++) {
+      gpointer pd = GST_VIDEO_FRAME_PLANE_DATA (&frame, plane);
+      gint w = GST_VIDEO_FRAME_COMP_WIDTH (&frame, plane)
+          * GST_VIDEO_FRAME_COMP_PSTRIDE (&frame, plane);
+      gint h = GST_VIDEO_FRAME_COMP_HEIGHT (&frame, plane);
+      gint ps = GST_VIDEO_FRAME_PLANE_STRIDE (&frame, plane);
+
+      for (j = 0; j < h; ++j) {
+        for (i = 0; i < w; ++i) {
+          guint8 actual = GST_READ_UINT8 (pd + i);
+          guint8 expect = 0xff;
+          if (plane == 0) {
+            if (i >= 10 && i < 30 && j >= 10 && j < 30)
+              expect = 0x51;
+            else
+              expect = 0x91;
+          } else {
+            if (i >= 10 && i < 30 && j >= 5 && j < 15)
+              expect = (i % 2) ? 0xf0 : 0x5a;
+            else
+              expect = (i % 2) ? 0x22 : 0x36;
+          }
+          fail_unless (actual == expect,
+              "Expected 0x%02x but got 0x%02x at (%u,%u,%u)", expect, actual,
+              plane, i, j);
+        }
+        pd += ps;
+      }
+    }
+  }
+  gst_video_frame_unmap (&frame);
+
+  /* cleanup */
+  gst_buffer_replace (&handoff_buffer, NULL);
+  gst_element_set_state (bin, GST_STATE_NULL);
+  g_main_loop_unref (main_loop);
+  gst_bus_remove_signal_watch (bus);
+  gst_object_unref (bus);
+  gst_object_unref (bin);
+}
+
+GST_END_TEST;
+
+static Suite *
+vaapioverlay_suite (void)
+{
+  Suite *s = suite_create ("vaapioverlay");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_overlay_position);
+
+  return s;
+}
+
+GST_CHECK_MAIN (vaapioverlay);
diff --git a/subprojects/gstreamer-vaapi/tests/check/elements/vaapipostproc.c b/subprojects/gstreamer-vaapi/tests/check/elements/vaapipostproc.c
new file mode 100644 (file)
index 0000000..d4bf6ca
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ *  vaapipostproc.c - GStreamer unit test for the vaapipostproc element
+ *
+ *  Copyright (C) 2019 Intel Corporation
+ *    Author: U. Artie Eoff <ullysses.a.eoff@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <gst/check/gstcheck.h>
+#include <gst/video/video.h>
+#include <gst/video/navigation.h>
+
+typedef struct
+{
+  GstElement *pipeline;
+  GstElement *source;
+  GstElement *filter;
+  GstElement *vpp;
+  GstElement *sink;
+} VppTestContext;
+
+typedef struct
+{
+  gdouble x;
+  gdouble y;
+} VppTestCoordinate;
+
+typedef struct
+{
+  VppTestCoordinate send;
+  VppTestCoordinate expect;
+} VppTestCoordinateParams;
+
+GST_START_TEST (test_make)
+{
+  GstElement *vaapipostproc;
+
+  vaapipostproc = gst_element_factory_make ("vaapipostproc", "vaapipostproc");
+  fail_unless (vaapipostproc != NULL, "Failed to create vaapipostproc element");
+
+  gst_object_unref (vaapipostproc);
+}
+
+GST_END_TEST;
+
+static void
+vpp_test_init_context (VppTestContext * ctx)
+{
+  GST_INFO ("initing context");
+
+  ctx->pipeline = gst_pipeline_new ("pipeline");
+  fail_unless (ctx->pipeline != NULL);
+
+  ctx->source = gst_element_factory_make ("videotestsrc", "src");
+  fail_unless (ctx->source != NULL, "Failed to create videotestsrc element");
+
+  ctx->filter = gst_element_factory_make ("capsfilter", "filter");
+  fail_unless (ctx->filter != NULL, "Failed to create caps filter element");
+
+  ctx->vpp = gst_element_factory_make ("vaapipostproc", "vpp");
+  fail_unless (ctx->vpp != NULL, "Failed to create vaapipostproc element");
+
+  ctx->sink = gst_element_factory_make ("fakesink", "sink");
+  fail_unless (ctx->sink != NULL, "Failed to create fakesink element");
+
+  gst_bin_add_many (GST_BIN (ctx->pipeline), ctx->source, ctx->filter, ctx->vpp,
+      ctx->sink, NULL);
+  gst_element_link_many (ctx->source, ctx->filter, ctx->vpp, ctx->sink, NULL);
+}
+
+static void
+vpp_test_deinit_context (VppTestContext * ctx)
+{
+  GST_INFO ("deiniting context");
+
+  gst_element_set_state (ctx->pipeline, GST_STATE_NULL);
+  gst_object_unref (ctx->pipeline);
+  memset (ctx, 0x00, sizeof (VppTestContext));
+}
+
+static void
+vpp_test_set_crop (VppTestContext * ctx, gint l, gint r, gint t, gint b)
+{
+  GST_LOG ("%d %d %d %0d", l, r, t, b);
+  g_object_set (ctx->vpp, "crop-left", l, "crop-right", r,
+      "crop-top", t, "crop-bottom", b, NULL);
+}
+
+static void
+vpp_test_set_orientation (VppTestContext * ctx, GstVideoOrientationMethod m)
+{
+  GST_LOG ("%u", m);
+  g_object_set (ctx->vpp, "video-direction", m, NULL);
+}
+
+static void
+vpp_test_set_dimensions (VppTestContext * ctx, gint w, gint h)
+{
+  GstCaps *caps = gst_caps_new_simple ("video/x-raw",
+      "width", G_TYPE_INT, w, "height", G_TYPE_INT, h, NULL);
+  GST_LOG ("%dx%d", w, h);
+  g_object_set (ctx->filter, "caps", caps, NULL);
+  gst_caps_unref (caps);
+}
+
+static GstPadProbeReturn
+cb_mouse_event (GstPad * pad, GstPadProbeInfo * info, gpointer data)
+{
+  VppTestCoordinate *coord = data;
+  gdouble x = 0, y = 0;
+  GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
+
+  if (GST_EVENT_TYPE (event) == GST_EVENT_NAVIGATION) {
+    switch (gst_navigation_event_get_type (event)) {
+      case GST_NAVIGATION_EVENT_MOUSE_MOVE:
+        if (gst_navigation_event_parse_mouse_move_event (event, &x, &y)) {
+          coord->x = x;
+          coord->y = y;
+        }
+        break;
+      case GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS:
+      case GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE:
+        if (gst_navigation_event_parse_mouse_button_event (event, NULL, &x, &y)) {
+          coord->x = x;
+          coord->y = y;
+        }
+        break;
+      default:
+        break;
+    }
+  }
+
+  return GST_PAD_PROBE_OK;
+}
+
+static void
+vpp_test_mouse_events (VppTestContext * ctx,
+    const VppTestCoordinateParams * const params, const size_t nparams)
+{
+  GstEvent *event = NULL;
+  VppTestCoordinate probed = { 0, };
+  guint i, j;
+
+  /* probe mouse events propagated up from vaapipostproc */
+  GstPad *pad = gst_element_get_static_pad (ctx->source, "src");
+  gulong id = gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
+      (GstPadProbeCallback) cb_mouse_event, &probed, NULL);
+
+  const char *mouse_events[] = {
+    "mouse-move",
+    "mouse-button-press",
+    "mouse-button-release",
+  };
+
+  fail_unless (gst_element_set_state (ctx->pipeline, GST_STATE_PAUSED)
+      != GST_STATE_CHANGE_FAILURE);
+  fail_unless (gst_element_get_state (ctx->pipeline, NULL, NULL, -1)
+      == GST_STATE_CHANGE_SUCCESS);
+
+  for (i = 0; i < nparams; ++i) {
+    for (j = 0; j < G_N_ELEMENTS (mouse_events); ++j) {
+      probed.x = probed.y = -1;
+
+      switch (j) {
+        case 0:
+          event = gst_navigation_event_new_mouse_move (params[i].send.x,
+              params[i].send.y, GST_NAVIGATION_MODIFIER_NONE);
+          break;
+        case 1:
+          event = gst_navigation_event_new_mouse_button_press (0,
+              params[i].send.x, params[i].send.y, GST_NAVIGATION_MODIFIER_NONE);
+          break;
+        case 2:
+          event = gst_navigation_event_new_mouse_button_release (0,
+              params[i].send.x, params[i].send.y, GST_NAVIGATION_MODIFIER_NONE);
+          break;
+      }
+
+      GST_LOG ("sending %s event %fx%f", mouse_events[j], params[i].send.x,
+          params[i].send.y);
+      gst_element_send_event (ctx->pipeline, event);
+
+      GST_LOG ("probed %s event %fx%f", mouse_events[j], probed.x, probed.y);
+      GST_LOG ("expect %s event %fx%f", mouse_events[j], params[i].expect.x,
+          params[i].expect.y);
+
+      fail_unless (params[i].expect.x == probed.x);
+      fail_unless (params[i].expect.y == probed.y);
+    }
+  }
+
+  gst_element_set_state (ctx->pipeline, GST_STATE_NULL);
+
+  gst_pad_remove_probe (pad, id);
+  gst_object_unref (pad);
+}
+
+static void
+vpp_test_crop_mouse_events (VppTestContext * ctx, gint w, gint h, gint l,
+    gint r, gint t, gint b)
+{
+  const gdouble xmin = 0.0;
+  const gdouble ymin = 0.0;
+  const gdouble xmax = w - (l + r) - 1;
+  const gdouble ymax = h - (t + b) - 1;
+  const gdouble xctr = xmax / 2;
+  const gdouble yctr = ymax / 2;
+  const gdouble xrand = g_random_double_range (xmin, xmax);
+  const gdouble yrand = g_random_double_range (ymin, ymax);
+
+  const gdouble e_xmin = xmin + l;
+  const gdouble e_ymin = ymin + t;
+  const gdouble e_xmax = xmax + l;
+  const gdouble e_ymax = ymax + t;
+  const gdouble e_xctr = xctr + l;
+  const gdouble e_yctr = yctr + t;
+  const gdouble e_xrand = xrand + l;
+  const gdouble e_yrand = yrand + t;
+
+  const VppTestCoordinateParams params[] = {
+    {{xmin, ymin}, {e_xmin, e_ymin}},   /* left-top */
+    {{xmin, yctr}, {e_xmin, e_yctr}},   /* left-center */
+    {{xmin, ymax}, {e_xmin, e_ymax}},   /* left-bottom */
+
+    {{xmax, ymin}, {e_xmax, e_ymin}},   /* right-top */
+    {{xmax, yctr}, {e_xmax, e_yctr}},   /* right-center */
+    {{xmax, ymax}, {e_xmax, e_ymax}},   /* right-bottom */
+
+    {{xctr, ymin}, {e_xctr, e_ymin}},   /* center-top */
+    {{xctr, yctr}, {e_xctr, e_yctr}},   /* center */
+    {{xctr, ymax}, {e_xctr, e_ymax}},   /* center-bottom */
+
+    {{xrand, yrand}, {e_xrand, e_yrand}},       /* random */
+  };
+
+  vpp_test_set_dimensions (ctx, w, h);
+  vpp_test_set_crop (ctx, l, r, t, b);
+  vpp_test_mouse_events (ctx, params, G_N_ELEMENTS (params));
+}
+
+GST_START_TEST (test_crop_mouse_events)
+{
+  VppTestContext ctx;
+
+  vpp_test_init_context (&ctx);
+
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 1, 0, 0, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 1, 0, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 1, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 1);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 63, 0, 0, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 63, 0, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 63, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 63);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 63, 0, 0, 1);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 63, 1, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 1, 63, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 1, 0, 0, 63);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 0, 0, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 32, 0, 0, 128);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 32, 128, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 0, 128, 32, 0);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 128, 0, 0, 32);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 1, 1, 1, 1);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 63, 63, 63, 63);
+  vpp_test_crop_mouse_events (&ctx, 160, 160, 64, 64, 64, 64);
+
+  vpp_test_deinit_context (&ctx);
+}
+
+GST_END_TEST;
+
+static void
+vpp_test_orientation_mouse_events (VppTestContext * ctx, gint w, gint h)
+{
+  size_t i;
+  const gdouble xmin = 0.0;
+  const gdouble ymin = 0.0;
+  const gdouble xmax = w - 1;
+  const gdouble ymax = h - 1;
+  const VppTestCoordinateParams params[8][4] = {
+    /* (0) identity */
+    {
+          {{xmin, ymin}, {xmin, ymin}},
+          {{xmax, ymin}, {xmax, ymin}},
+          {{xmin, ymax}, {xmin, ymax}},
+          {{xmax, ymax}, {xmax, ymax}},
+        },
+    /* (1) 90 Rotation */
+    {
+          {{ymin, xmin}, {xmin, ymax}},
+          {{ymax, xmin}, {xmin, ymin}},
+          {{ymin, xmax}, {xmax, ymax}},
+          {{ymax, xmax}, {xmax, ymin}},
+        },
+    /* (2) 180 Rotation */
+    {
+          {{xmin, ymin}, {xmax, ymax}},
+          {{xmax, ymin}, {xmin, ymax}},
+          {{xmin, ymax}, {xmax, ymin}},
+          {{xmax, ymax}, {xmin, ymin}},
+        },
+    /* (3) 270 Rotation */
+    {
+          {{ymin, xmin}, {xmax, ymin}},
+          {{ymax, xmin}, {xmax, ymax}},
+          {{ymin, xmax}, {xmin, ymin}},
+          {{ymax, xmax}, {xmin, ymax}},
+        },
+    /* (4) Horizontal Flip */
+    {
+          {{xmin, ymin}, {xmax, ymin}},
+          {{xmax, ymin}, {xmin, ymin}},
+          {{xmin, ymax}, {xmax, ymax}},
+          {{xmax, ymax}, {xmin, ymax}},
+        },
+    /* (5) Vertical Flip */
+    {
+          {{xmin, ymin}, {xmin, ymax}},
+          {{xmax, ymin}, {xmax, ymax}},
+          {{xmin, ymax}, {xmin, ymin}},
+          {{xmax, ymax}, {xmax, ymin}},
+        },
+    /* (6) Vertical Flip + 90 Rotation */
+    {
+          {{ymin, xmin}, {xmin, ymin}},
+          {{ymax, xmin}, {xmin, ymax}},
+          {{ymin, xmax}, {xmax, ymin}},
+          {{ymax, xmax}, {xmax, ymax}},
+        },
+    /* (7) Horizontal Flip + 90 Rotation */
+    {
+          {{ymin, xmin}, {xmax, ymax}},
+          {{ymax, xmin}, {xmax, ymin}},
+          {{ymin, xmax}, {xmin, ymax}},
+          {{ymax, xmax}, {xmin, ymin}},
+        },
+  };
+
+  vpp_test_set_dimensions (ctx, w, h);
+
+  for (i = 0; i < 8; ++i) {
+    vpp_test_set_orientation (ctx, i);
+    vpp_test_mouse_events (ctx, params[i], 4);
+  }
+}
+
+GST_START_TEST (test_orientation_mouse_events)
+{
+  VppTestContext ctx;
+
+  vpp_test_init_context (&ctx);
+
+  vpp_test_orientation_mouse_events (&ctx, 160, 320);
+  vpp_test_orientation_mouse_events (&ctx, 161, 320);
+  vpp_test_orientation_mouse_events (&ctx, 160, 321);
+  vpp_test_orientation_mouse_events (&ctx, 161, 321);
+
+  vpp_test_orientation_mouse_events (&ctx, 320, 160);
+  vpp_test_orientation_mouse_events (&ctx, 320, 161);
+  vpp_test_orientation_mouse_events (&ctx, 321, 160);
+  vpp_test_orientation_mouse_events (&ctx, 321, 161);
+
+  vpp_test_deinit_context (&ctx);
+}
+
+GST_END_TEST;
+
+static Suite *
+vaapipostproc_suite (void)
+{
+  Suite *s = suite_create ("vaapipostproc");
+  TCase *tc_chain = tcase_create ("general");
+
+  suite_add_tcase (s, tc_chain);
+  tcase_add_test (tc_chain, test_make);
+  tcase_add_test (tc_chain, test_crop_mouse_events);
+  tcase_add_test (tc_chain, test_orientation_mouse_events);
+
+  return s;
+}
+
+GST_CHECK_MAIN (vaapipostproc);
diff --git a/subprojects/gstreamer-vaapi/tests/check/meson.build b/subprojects/gstreamer-vaapi/tests/check/meson.build
new file mode 100644 (file)
index 0000000..31fe0d9
--- /dev/null
@@ -0,0 +1,39 @@
+tests = [
+  [ 'elements/vaapipostproc' ],
+]
+
+if USE_DRM
+  tests += [
+  [ 'elements/vaapioverlay' ]
+]
+endif
+
+test_deps = [gst_dep, gstbase_dep, gstvideo_dep, gstcheck_dep]
+test_defines = [
+  '-UG_DISABLE_ASSERT',
+  '-UG_DISABLE_CAST_CHECKS',
+  '-DGST_USE_UNSTABLE_API',
+]
+
+pluginsdirs = []
+if gst_dep.type_name() == 'pkgconfig'
+  pluginsdirs = [gst_dep.get_variable('pluginsdir')]
+endif
+
+foreach t : tests
+  fname = '@0@.c'.format(t.get(0))
+  test_name = t.get(0).underscorify()
+  extra_sources = [ ]
+  extra_deps = [ ]
+  env = environment()
+  env.set('CK_DEFAULT_TIMEOUT', '20')
+  env.set('GST_PLUGIN_SYSTEM_PATH_1_0', '')
+  env.set('GST_PLUGIN_PATH_1_0', [meson.global_build_root()] + pluginsdirs)
+  env.set('GST_REGISTRY', join_paths(meson.current_build_dir(), '@0@.registry'.format(test_name)))
+  exe = executable(test_name, fname, extra_sources,
+    include_directories : [configinc, libsinc],
+    c_args : ['-DHAVE_CONFIG_H=1' ] + test_defines,
+    dependencies : test_deps + extra_deps,
+  )
+  test(test_name, exe, env: env, timeout: 3 * 60)
+endforeach
diff --git a/subprojects/gstreamer-vaapi/tests/examples/meson.build b/subprojects/gstreamer-vaapi/tests/examples/meson.build
new file mode 100644 (file)
index 0000000..e7b1dee
--- /dev/null
@@ -0,0 +1,29 @@
+examples = [
+  'test-vaapisink',
+  'test-vaapipostproc',
+  'test-roi',
+]
+
+foreach example : examples
+  executable(example, '@0@.c'.format(example),
+    c_args : gstreamer_vaapi_args,
+    include_directories: [configinc, libsinc],
+    dependencies : [gst_dep, gstvideo_dep],
+    install: false)
+endforeach
+
+if USE_X11 and USE_WAYLAND
+if gtk_dep.found()
+  executable('test-vaapicontext', 'test-vaapicontext.c',
+    c_args : gstreamer_vaapi_args,
+    include_directories: [configinc, libsinc],
+    dependencies : [ gst_dep,
+                     gstvideo_dep,
+                     libva_dep,
+                     x11_dep,
+                     gtk_dep,
+                     libva_wayland_dep,
+                     libva_x11_dep ],
+    install: false)
+endif
+endif
diff --git a/subprojects/gstreamer-vaapi/tests/examples/test-roi.c b/subprojects/gstreamer-vaapi/tests/examples/test-roi.c
new file mode 100644 (file)
index 0000000..2ce614e
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ *  test-roi.c - Testsuite for Region of Interest
+ *
+ *  Copyright (C) 2017 Intel Corporation
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <gst/gst.h>
+#include <gst/video/navigation.h>
+#include <gst/video/gstvideometa.h>
+
+typedef struct _CustomData
+{
+  GstElement *pipeline;
+  GMainLoop *loop;
+  gboolean roi_enabled;
+} AppData;
+
+static void
+send_eos_event (AppData * data)
+{
+  gst_element_send_event (data->pipeline, gst_event_new_eos ());
+}
+
+static void
+dispatch_keystroke (AppData * app, const gchar * str)
+{
+  switch (g_ascii_tolower (str[0])) {
+    case 'r':
+      app->roi_enabled = !app->roi_enabled;
+      gst_println ("ROI %s", app->roi_enabled ? "enabled" : "disabled");
+      break;
+    case 'q':
+      send_eos_event (app);
+      break;
+    default:
+      break;
+  }
+
+  return;
+}
+
+static void
+cb_msg (GstBus * bus, GstMessage * msg, gpointer data)
+{
+  AppData *app = data;
+  GstNavigationMessageType mtype = gst_navigation_message_get_type (msg);
+  GstEvent *ev = NULL;
+  GstNavigationEventType type;
+  const gchar *key;
+
+  if (mtype != GST_NAVIGATION_MESSAGE_EVENT)
+    return;
+  if (!gst_navigation_message_parse_event (msg, &ev))
+    goto bail;
+
+  type = gst_navigation_event_get_type (ev);
+  if (type != GST_NAVIGATION_EVENT_KEY_PRESS)
+    goto bail;
+  if (!gst_navigation_event_parse_key_event (ev, &key))
+    goto bail;
+
+  dispatch_keystroke (app, key);
+
+bail:
+  if (ev)
+    gst_event_unref (ev);
+}
+
+static void
+cb_msg_eos (GstBus * bus, GstMessage * msg, gpointer data)
+{
+  AppData *app = data;
+  g_main_loop_quit (app->loop);
+}
+
+
+static void
+cb_msg_error (GstBus * bus, GstMessage * msg, gpointer data)
+{
+  AppData *app = data;
+  gchar *debug = NULL;
+  GError *err = NULL;
+
+  gst_message_parse_error (msg, &err, &debug);
+
+  g_print ("Error: %s\n", err->message);
+  g_error_free (err);
+
+  if (debug) {
+    g_print ("Debug details: %s\n", debug);
+    g_free (debug);
+  }
+
+  g_main_loop_quit (app->loop);
+}
+
+static GstPadProbeReturn
+cb_add_roi (GstPad * pad, GstPadProbeInfo * info, gpointer data)
+{
+  AppData *app = data;
+  GstVideoRegionOfInterestMeta *rmeta;
+  GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
+  GstStructure *s;
+
+  if (!app->roi_enabled)
+    return GST_PAD_PROBE_OK;
+
+  buf = gst_buffer_make_writable (buf);
+  if (!buf)
+    return GST_PAD_PROBE_OK;
+
+  rmeta =
+      gst_buffer_add_video_region_of_interest_meta (buf, "test", 0, 0, 320,
+      240);
+  if (!rmeta)
+    return GST_PAD_PROBE_OK;
+
+  s = gst_structure_new ("roi/vaapi", "delta-qp", G_TYPE_INT, -10, NULL);
+  gst_video_region_of_interest_meta_add_param (rmeta, s);
+
+  GST_PAD_PROBE_INFO_DATA (info) = buf;
+  return GST_PAD_PROBE_OK;
+}
+
+/* Process keyboard input */
+static gboolean
+handle_keyboard (GIOChannel * source, GIOCondition cond, gpointer data)
+{
+  AppData *app = data;
+  gchar *str = NULL;
+
+  if (g_io_channel_read_line (source, &str, NULL, NULL,
+          NULL) != G_IO_STATUS_NORMAL) {
+    return TRUE;
+  }
+
+  dispatch_keystroke (app, str);
+
+  g_free (str);
+  return TRUE;
+}
+
+/*
+ * This is an example pipeline to recognize difference between ROI and non-ROI.
+ * 1. Produce snow pattern with 320p
+ * 2. Encode and decode the raw data with 2 pipelines at same time.
+ *    2.1. Insert GstVideoRegionOfInterestMeta to the 2nd pipeline buffers to enable ROI.
+ * 3. Mix both streams in videomixer.
+ * 5. Output the result in one window.
+ *
+ * Note that the higher definition of original raw data, the easier we
+ * recognize.  So you can replace videotestsrc with your
+ * high-definition camera or other src elements.
+ */
+
+/*
+.----------.  .---.     .--------.  .---.  .---.  .---.  .--------.  .----------.  .-----.
+| videosrc |->|tee|->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->|videomixer|->|vsink|
+'----------'  '---'     '--------'  '---'  '---'  '---'  '--------'  '----------'  '-----'
+                ^                                                    ^
+                |                                                    |
+                |       .--------.  .---.  .---.  .---.  .--------.  |
+                '--->Q->|txtovrly|->|enc|->|dec|->|vpp|->|videobox|->'
+                     ^  '--------'  '---'  '---'  '---'  '--------'
+                     |
+                     '-- Insert GstVideoRegionOfInterestMeta width roit/vaapi params on buffers
+*/
+
+int
+main (int argc, char *argv[])
+{
+  AppData data = { 0, };
+  GstStateChangeReturn ret;
+  GstElement *el;
+  GstPad *pad;
+  GError *err = NULL;
+  GIOChannel *io_stdin;
+  GstBus *bus;
+
+  data.roi_enabled = TRUE;
+
+  /* Initialize GStreamer */
+  gst_init (&argc, &argv);
+
+  /* Print usage map */
+  g_print ("USAGE: 'r' to enable/disable ROI && 'q' to quit\n");
+
+#define SRC "videotestsrc pattern=snow ! " \
+            "video/x-raw, format=NV12, width=320, framerate=5/1"
+#define ENCDEC "vaapih265enc rate-control=cbr bitrate=2000 ! vaapih265dec ! " \
+               "vaapipostproc ! video/x-raw, width=640"
+#define TEXT "textoverlay font-desc=\"Arial Bold 48\" "
+
+  data.pipeline =
+      gst_parse_launch
+      ("videomixer name=mix ! vaapipostproc ! vaapisink sync=false "
+      SRC " ! tee name=t ! queue ! " TEXT " text=\"non-ROI\" ! " ENCDEC
+      " ! videobox left=-640 ! mix. "
+      " t. ! queue name=roi ! " TEXT " text=\"ROI\" ! " ENCDEC
+      " ! videobox ! mix.", &err);
+
+  if (err) {
+    g_printerr ("failed to parse pipeline: %s\n", err->message);
+    g_error_free (err);
+    return -1;
+  }
+
+  bus = gst_pipeline_get_bus (GST_PIPELINE (data.pipeline));
+  gst_bus_add_signal_watch_full (bus, G_PRIORITY_HIGH);
+  gst_bus_enable_sync_message_emission (bus);
+  g_signal_connect (bus, "message::error", G_CALLBACK (cb_msg_error), &data);
+  g_signal_connect (bus, "message::eos", G_CALLBACK (cb_msg_eos), &data);
+  g_signal_connect (bus, "message::element", G_CALLBACK (cb_msg), &data);
+  gst_object_unref (bus);
+
+  el = gst_bin_get_by_name (GST_BIN (data.pipeline), "roi");
+  pad = gst_element_get_static_pad (el, "src");
+  gst_object_unref (el);
+  gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_BUFFER, cb_add_roi, &data, NULL);
+  gst_object_unref (pad);
+
+  /* Add a keyboard watch so we get notified of keystrokes */
+  io_stdin = g_io_channel_unix_new (fileno (stdin));
+  g_io_add_watch (io_stdin, G_IO_IN, handle_keyboard, &data);
+
+  /* Start playing */
+  ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    g_printerr ("Unable to set the pipeline to the playing state.\n");
+    gst_object_unref (data.pipeline);
+    return -1;
+  }
+
+  /* Create a GLib Main Loop and set it to run */
+  data.loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (data.loop);
+
+  /* Free resources */
+  g_main_loop_unref (data.loop);
+  gst_element_set_state (data.pipeline, GST_STATE_NULL);
+  gst_object_unref (data.pipeline);
+  g_io_channel_unref (io_stdin);
+
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/examples/test-vaapicontext.c b/subprojects/gstreamer-vaapi/tests/examples/test-vaapicontext.c
new file mode 100644 (file)
index 0000000..98760dc
--- /dev/null
@@ -0,0 +1,468 @@
+/*
+ *  test-vaapicontext.c - Testsuite for VAAPI app context
+ *
+ *  Copyright (C) 2017 Intel Corporation
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include <gst/gst.h>
+#include <gst/video/videooverlay.h>
+
+#include <va/va.h>
+
+#include <gtk/gtk.h>
+
+#ifdef GDK_WINDOWING_X11
+#include <X11/Xlib.h>
+#include <gdk/gdkx.h>
+#include <va/va_x11.h>
+#endif
+#ifdef GDK_WINDOWING_WAYLAND
+#include <gdk/gdkwayland.h>
+#include <va/va_wayland.h>
+#endif
+
+static gboolean g_multisink;
+static gchar *g_filepath;
+static GstElement *g_vaapisink;
+
+static GOptionEntry g_options[] = {
+  {"multi", 'm', 0, G_OPTION_ARG_NONE, &g_multisink, "test multiple vaapisink",
+      NULL},
+  {"file", 'f', 0, G_OPTION_ARG_STRING, &g_filepath, "file path to play", NULL},
+  {NULL,}
+};
+
+typedef struct _CustomData
+{
+  GtkWidget *main_window;
+  VADisplay va_display;
+  GstElement *pipeline;
+  guintptr videoarea_handle[2];
+  GstObject *gstvaapidisplay;
+  GtkWidget *video_widget[2];
+  GstVideoOverlay *overlay[2];
+} AppData;
+
+static void
+delete_event_cb (GtkWidget * widget, GdkEvent * event, gpointer data)
+{
+  AppData *app = data;
+
+  gst_element_set_state (app->pipeline, GST_STATE_NULL);
+  gtk_main_quit ();
+}
+
+static void
+button_rotate_cb (GtkWidget * widget, GstElement * elem)
+{
+  static gint counter = 0;
+  const static gint tags[] = { 90, 180, 270, 0 };
+
+  g_object_set (elem, "rotation", tags[counter++ % G_N_ELEMENTS (tags)], NULL);
+}
+
+static gpointer
+get_native_display (AppData * app, gboolean * is_x11)
+{
+  GdkDisplay *gdk_display;
+
+  gdk_display = gtk_widget_get_display (app->main_window);
+
+#if defined(GDK_WINDOWING_X11)
+  if (GDK_IS_X11_DISPLAY (gdk_display)) {
+    *is_x11 = TRUE;
+    return gdk_x11_display_get_xdisplay (gdk_display);
+  } else
+#endif
+#ifdef GDK_WINDOWING_WAYLAND
+  if (GDK_IS_WAYLAND_DISPLAY (gdk_display)) {
+    *is_x11 = FALSE;
+    return gdk_wayland_display_get_wl_display (gdk_display);
+  } else
+#endif
+    g_error ("Running in a non supported environment");
+}
+
+static VADisplay
+ensure_va_display (AppData * app, gpointer native_display, gboolean is_x11)
+{
+  if (app->va_display)
+    return app->va_display;
+  app->va_display = is_x11 ?
+      vaGetDisplay (native_display) : vaGetDisplayWl (native_display);
+  /* There's no need to call vaInitialize() since element does it
+   * internally */
+  return app->va_display;
+}
+
+static GstContext *
+create_vaapi_app_display_context (AppData * app, gboolean new_va_display)
+{
+  GstContext *context;
+  GstStructure *s;
+  VADisplay va_display;
+  gpointer native_display = NULL;
+  const gchar *name = NULL;
+  gboolean is_x11;
+
+  native_display = get_native_display (app, &is_x11);
+
+  if (new_va_display) {
+    va_display = is_x11 ?
+        vaGetDisplay (native_display) : vaGetDisplayWl (native_display);
+  } else
+    va_display = ensure_va_display (app, native_display, is_x11);
+
+  name = is_x11 ? "x11-display" : "wl-display";
+
+  context = gst_context_new ("gst.vaapi.app.Display", FALSE);
+  s = gst_context_writable_structure (context);
+  gst_structure_set (s, "va-display", G_TYPE_POINTER, va_display, NULL);
+  gst_structure_set (s, name, G_TYPE_POINTER, native_display, NULL);
+
+  return context;
+}
+
+static void
+get_allocation (GtkWidget * widget, GtkAllocation * allocation)
+{
+  GdkDisplay *display = gdk_display_get_default ();
+
+  gtk_widget_get_allocation (widget, allocation);
+
+  /* On Wayland the whole gtk window is one surface and the video is a
+   * subsurface of the top-level surface. So the position must be relative
+   * to the top-level window not relative to the parent widget */
+  if (GDK_IS_WAYLAND_DISPLAY (display))
+    gtk_widget_translate_coordinates (widget, gtk_widget_get_toplevel (widget),
+        0, 0, &allocation->x, &allocation->y);
+}
+
+static GstBusSyncReply
+bus_sync_handler (GstBus * bus, GstMessage * msg, gpointer data)
+{
+  AppData *app = data;
+
+  switch (GST_MESSAGE_TYPE (msg)) {
+    case GST_MESSAGE_NEED_CONTEXT:{
+      const gchar *context_type;
+      gboolean new_va_disp;
+      GstContext *context;
+
+      gst_message_parse_context_type (msg, &context_type);
+      gst_println ("Got need context %s from %s", context_type,
+          GST_MESSAGE_SRC_NAME (msg));
+
+      if (g_strcmp0 (context_type, "gst.vaapi.Display") == 0) {
+        if (app->gstvaapidisplay) {
+          GstStructure *s;
+
+          context = gst_context_new ("gst.vaapi.Display", FALSE);
+          s = gst_context_writable_structure (context);
+          gst_structure_set (s, "gst.vaapi.Display",
+              GST_TYPE_OBJECT, app->gstvaapidisplay, NULL);
+        }
+        break;
+      }
+
+      if (g_strcmp0 (context_type, "gst.vaapi.app.Display") != 0)
+        break;
+
+      /* create a new VA display *only* for the second video sink */
+      new_va_disp = (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0);
+
+      context = create_vaapi_app_display_context (app, new_va_disp);
+      gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (msg)), context);
+      gst_context_unref (context);
+      break;
+    }
+    case GST_MESSAGE_ELEMENT:{
+      GstVideoOverlay *overlay;
+      GtkAllocation allocation;
+      guint i;
+
+      if (!gst_is_video_overlay_prepare_window_handle_message (msg))
+        break;
+
+      overlay = GST_VIDEO_OVERLAY (GST_MESSAGE_SRC (msg));
+
+      i = (g_strcmp0 (GST_MESSAGE_SRC_NAME (msg), "sink2") == 0) ? 1 : 0;
+
+      app->overlay[i] = overlay;
+      get_allocation (app->video_widget[i], &allocation);
+      gst_video_overlay_set_window_handle (overlay, app->videoarea_handle[i]);
+      gtk_widget_queue_draw_area (app->video_widget[i], 0, 0, allocation.width,
+          allocation.height);
+
+      break;
+    }
+    case GST_MESSAGE_HAVE_CONTEXT:{
+      const gchar *context_type;
+      const GstStructure *s;
+      GstContext *context = NULL;
+      const GValue *value;
+
+      gst_message_parse_have_context (msg, &context);
+      if (!context)
+        break;
+
+      context_type = gst_context_get_context_type (context);
+      gst_println ("Got have context %s from %s", context_type,
+          GST_MESSAGE_SRC_NAME (msg));
+
+      if (g_strcmp0 (context_type, "gst.vaapi.Display") != 0)
+        break;
+      s = gst_context_get_structure (context);
+      if (!s)
+        break;
+      value = gst_structure_get_value (s, "gst.vaapi.Display");
+      if (!value)
+        break;
+      app->gstvaapidisplay = g_value_dup_object (value);
+      gst_println ("found display %s", GST_OBJECT_NAME (app->gstvaapidisplay));
+      break;
+    }
+    case GST_MESSAGE_EOS:
+      gtk_main_quit ();
+      break;
+    default:
+      break;
+  }
+
+  return GST_BUS_PASS;
+}
+
+static void
+play_cb (GtkButton * button, gpointer data)
+{
+  AppData *app = data;
+
+  gst_element_set_state (app->pipeline, GST_STATE_PLAYING);
+}
+
+static void
+null_cb (GtkButton * button, gpointer data)
+{
+  AppData *app = data;
+
+  gst_element_set_state (app->pipeline, GST_STATE_NULL);
+  app->va_display = NULL;
+}
+
+
+static void
+realize_cb (GtkWidget * widget, gpointer data)
+{
+  AppData *app = data;
+  GdkWindow *window;
+  GdkDisplay *display;
+  static guint counter = 0;
+
+  display = gdk_display_get_default ();
+
+#ifdef GDK_WINDOWING_WAYLAND
+  /* On wayland gtk_widget_get_window() only works correctly for the
+   * toplevel widget. Otherwise a new wayland surface is created but
+   * never used and the video remains invisible. */
+  if (GDK_IS_WAYLAND_DISPLAY (display))
+    window = gtk_widget_get_window (app->main_window);
+  else
+#endif
+    window = gtk_widget_get_window (widget);
+
+  if (!gdk_window_ensure_native (window))
+    g_error ("Couldn't create native window needed for GstOverlay!");
+
+#ifdef GDK_WINDOWING_X11
+  if (GDK_IS_X11_DISPLAY (display)) {
+    app->videoarea_handle[counter++ % 2] = GDK_WINDOW_XID (window);
+  } else
+#endif
+#ifdef GDK_WINDOWING_WAYLAND
+  if (GDK_IS_WAYLAND_DISPLAY (display)) {
+    app->videoarea_handle[counter++ % 2] =
+        (guintptr) gdk_wayland_window_get_wl_surface (window);
+  } else
+#endif
+    g_error ("Unsupported GDK backend");
+}
+
+static void
+draw_cb (GtkWidget * widget, cairo_t * cr, gpointer data)
+{
+  AppData *app = data;
+  GtkAllocation allocation;
+  int i;
+
+  i = (widget == app->video_widget[0]) ? 0 : 1;
+
+  get_allocation (widget, &allocation);
+
+  gst_println ("draw_cb[%d] x %d, y %d, w %d, h %d\n", i,
+      allocation.x, allocation.y, allocation.width, allocation.height);
+
+  if (app->overlay[i]) {
+    gst_video_overlay_set_render_rectangle (app->overlay[i], allocation.x,
+        allocation.y, allocation.width, allocation.height);
+  }
+}
+
+static GtkWidget *
+create_video_box (AppData * app)
+{
+  GtkWidget *video_area;
+
+  video_area = gtk_drawing_area_new ();
+  gtk_widget_set_size_request (video_area, 640, 480);
+  g_signal_connect (video_area, "realize", G_CALLBACK (realize_cb), app);
+  g_signal_connect (video_area, "draw", G_CALLBACK (draw_cb), app);
+  return video_area;
+}
+
+static GtkWidget *
+create_rotate_button (AppData * app, const gchar * name)
+{
+  GtkWidget *rotate;
+  GstElement *sink;
+
+  sink = gst_bin_get_by_name (GST_BIN (app->pipeline), name);
+  if (!sink && !g_strcmp0 (name, "sink1"))
+    sink = g_vaapisink;
+  g_assert (sink);
+
+  rotate = gtk_button_new_with_label ("Rotate");
+  g_signal_connect (rotate, "clicked", G_CALLBACK (button_rotate_cb), sink);
+  if (sink != g_vaapisink)
+    gst_object_unref (sink);
+
+  return rotate;
+}
+
+static void
+build_ui (AppData * app)
+{
+  GtkWidget *mainwin, *vbox, *pane, *bbox;
+
+  mainwin = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (mainwin), "VAAPI display context test");
+  gtk_window_set_resizable (GTK_WINDOW (mainwin), FALSE);
+  g_signal_connect (mainwin, "delete-event", G_CALLBACK (delete_event_cb), app);
+  app->main_window = mainwin;
+
+  vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+  gtk_container_add (GTK_CONTAINER (mainwin), vbox);
+
+  pane = gtk_paned_new (GTK_ORIENTATION_HORIZONTAL);
+  gtk_box_pack_start (GTK_BOX (vbox), pane, TRUE, TRUE, 0);
+
+  /* first video box */
+  app->video_widget[0] = create_video_box (app);
+  gtk_paned_pack1 (GTK_PANED (pane), app->video_widget[0], TRUE, TRUE);
+
+  /* rotate buttons */
+  bbox = gtk_button_box_new (GTK_ORIENTATION_HORIZONTAL);
+  gtk_button_box_set_layout (GTK_BUTTON_BOX (bbox), GTK_BUTTONBOX_SPREAD);
+  gtk_box_pack_end (GTK_BOX (vbox), bbox, TRUE, TRUE, 0);
+
+  gtk_box_pack_start (GTK_BOX (bbox), create_rotate_button (app, "sink1"), TRUE,
+      TRUE, 0);
+
+  if (g_multisink) {
+    /* second video box */
+    app->video_widget[1] = create_video_box (app);
+    gtk_paned_pack2 (GTK_PANED (pane), app->video_widget[1], TRUE, TRUE);
+
+    gtk_box_pack_start (GTK_BOX (bbox), create_rotate_button (app, "sink2"),
+        TRUE, TRUE, 0);
+  } else {
+    GtkWidget *button;
+
+    button = gtk_button_new_with_label ("PLAYING");
+    gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
+    g_signal_connect (button, "clicked", G_CALLBACK (play_cb), app);
+
+    button = gtk_button_new_with_label ("NULL");
+    gtk_box_pack_start (GTK_BOX (bbox), button, TRUE, TRUE, 0);
+    g_signal_connect (button, "clicked", G_CALLBACK (null_cb), app);
+  }
+
+  gtk_widget_show_all (mainwin);
+}
+
+int
+main (gint argc, gchar ** argv)
+{
+  AppData app = { 0, };
+  GstBus *bus;
+  GOptionContext *ctx;
+  GError *error = NULL;
+
+  XInitThreads ();
+
+  ctx = g_option_context_new ("- test options");
+  if (!ctx)
+    return -1;
+
+  g_option_context_add_group (ctx, gtk_get_option_group (TRUE));
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  g_option_context_add_main_entries (ctx, g_options, NULL);
+  if (!g_option_context_parse (ctx, &argc, &argv, NULL))
+    return -1;
+  g_option_context_free (ctx);
+
+  if (g_multisink) {
+    app.pipeline = gst_parse_launch ("videotestsrc ! tee name=t ! queue ! "
+        "vaapisink name=sink1 t. ! queue ! vaapisink name=sink2", &error);
+  } else if (!g_filepath) {
+    app.pipeline = gst_parse_launch ("videotestsrc ! vaapih264enc ! "
+        "vaapidecodebin ! vaapisink name=sink1", &error);
+  } else {
+    app.pipeline = gst_element_factory_make ("playbin", NULL);
+    g_assert (app.pipeline);
+  }
+
+  if (error) {
+    gst_printerrln ("failed to parse pipeline: %s", error->message);
+    g_error_free (error);
+    return -1;
+  }
+
+  if (!g_multisink && g_filepath) {
+    g_vaapisink = gst_element_factory_make ("vaapisink", "sink1");
+    g_assert (g_vaapisink);
+    g_object_set (app.pipeline, "uri", g_filepath, "video-sink", g_vaapisink,
+        NULL);
+  }
+
+  build_ui (&app);
+
+  bus = gst_element_get_bus (app.pipeline);
+  gst_bus_set_sync_handler (bus, bus_sync_handler, (gpointer) & app, NULL);
+  gst_object_unref (bus);
+
+  gst_element_set_state (app.pipeline, GST_STATE_PLAYING);
+  gst_println ("Now playing…");
+
+  gtk_main ();
+
+  gst_object_unref (app.pipeline);
+  gst_object_unref (app.gstvaapidisplay);
+  /* there is no need to call vaTerminate() because it is done by the
+   * vaapi elements */
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/examples/test-vaapipostproc.c b/subprojects/gstreamer-vaapi/tests/examples/test-vaapipostproc.c
new file mode 100644 (file)
index 0000000..87d1353
--- /dev/null
@@ -0,0 +1,157 @@
+/*
+ *  test-vaapipostproc.c - Testsuite for VAAPI Postprocessor
+ *
+ *  Copyright (C) 2017 Intel Corporation
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include <stdio.h>
+#include <gst/gst.h>
+#include <gst/base/gstbasetransform.h>
+
+typedef struct _CustomData
+{
+  GstElement *pipeline;
+  GstElement *postproc;
+  GMainLoop *loop;
+} AppData;
+
+static gboolean
+_check_passthrough_mode (gpointer user_data)
+{
+  gboolean ret;
+  AppData *data = (AppData *) user_data;
+
+  ret = gst_base_transform_is_passthrough (GST_BASE_TRANSFORM (data->postproc));
+
+  if (ret)
+    gst_println ("Now this pipeline is on passthrough mode");
+  else
+    gst_println ("Now this pipeline is NOT on passthrough mode");
+
+  return FALSE;
+}
+
+static void
+set_contrast (AppData * data)
+{
+  static gfloat value = 1.0;
+
+  value = value == 1.0 ? 0.5 : 1.0;
+  g_object_set (data->postproc, "contrast", value, NULL);
+  gst_println ("contrast value is changed to %f", value);
+
+  g_timeout_add (300, _check_passthrough_mode, data);
+}
+
+static void
+change_size (AppData * data)
+{
+  static gint i = 0;
+  if (i == 0) {
+    g_object_set (data->postproc, "width", 1280, "height", 720, NULL);
+    gst_println ("frame size is changed to 1280x720");
+    i++;
+  } else {
+    g_object_set (data->postproc, "width", 0, "height", 0, NULL);
+    gst_println ("frame size is changed to default");
+    i = 0;
+  }
+
+  g_timeout_add (300, _check_passthrough_mode, data);
+}
+
+/* Process keyboard input */
+static gboolean
+handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data)
+{
+  gchar *str = NULL;
+
+  if (g_io_channel_read_line (source, &str, NULL, NULL,
+          NULL) != G_IO_STATUS_NORMAL) {
+    return TRUE;
+  }
+
+  switch (g_ascii_tolower (str[0])) {
+    case 's':{
+      set_contrast (data);
+      break;
+    }
+    case 'c':{
+      change_size (data);
+      break;
+    }
+    case 'q':
+      g_main_loop_quit (data->loop);
+      break;
+    default:
+      break;
+  }
+
+  g_free (str);
+
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  AppData data = { 0, };
+  GstStateChangeReturn ret;
+  GIOChannel *io_stdin;
+
+  /* Initialize GStreamer */
+  gst_init (&argc, &argv);
+
+  /* Print usage map */
+  gst_println ("USAGE: Choose one of the following options, then press enter:\n"
+      " 's' to set contrast\n" " 'c' to change size\n" " 'q' to quit\n");
+
+  data.pipeline =
+      gst_parse_launch
+      ("videotestsrc name=src ! vaapih264enc ! vaapih264dec ! vaapipostproc name=postproc ! vaapisink",
+      NULL);
+  data.postproc = gst_bin_get_by_name (GST_BIN (data.pipeline), "postproc");
+
+  /* Add a keyboard watch so we get notified of keystrokes */
+  io_stdin = g_io_channel_unix_new (fileno (stdin));
+  g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc) handle_keyboard, &data);
+
+  /* Start playing */
+  ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    g_printerr ("Unable to set the pipeline to the playing state.\n");
+    gst_object_unref (data.pipeline);
+    return -1;
+  }
+
+  g_timeout_add (300, _check_passthrough_mode, &data);
+
+  /* Create a GLib Main Loop and set it to run */
+  data.loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (data.loop);
+
+  /* Free resources */
+  g_main_loop_unref (data.loop);
+  g_io_channel_unref (io_stdin);
+  gst_element_set_state (data.pipeline, GST_STATE_NULL);
+
+  gst_object_unref (data.postproc);
+  gst_object_unref (data.pipeline);
+
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/examples/test-vaapisink.c b/subprojects/gstreamer-vaapi/tests/examples/test-vaapisink.c
new file mode 100644 (file)
index 0000000..41f3fc3
--- /dev/null
@@ -0,0 +1,189 @@
+#include <stdio.h>
+#include <string.h>
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+static gboolean use_postproc;
+static GOptionEntry g_options[] = {
+  {"postproc", 'p', 0, G_OPTION_ARG_NONE, &use_postproc,
+      "use vaapipostproc to rotate rather than vaapisink", NULL},
+  {NULL,}
+};
+
+typedef struct _CustomData
+{
+  GstElement *pipeline;
+  GstElement *rotator;
+  GMainLoop *loop;
+  gboolean orient_automatic;
+} AppData;
+
+static void
+send_rotate_event (AppData * data)
+{
+  gboolean res = FALSE;
+  GstEvent *event;
+  static gint counter = 0;
+  const static gchar *tags[] = { "rotate-90", "rotate-180", "rotate-270",
+    "rotate-0", "flip-rotate-0", "flip-rotate-90", "flip-rotate-180",
+    "flip-rotate-270",
+  };
+
+  event = gst_event_new_tag (gst_tag_list_new (GST_TAG_IMAGE_ORIENTATION,
+          tags[counter++ % G_N_ELEMENTS (tags)], NULL));
+
+  /* Send the event */
+  g_print ("Sending event %" GST_PTR_FORMAT ": ", event);
+  res = gst_element_send_event (data->pipeline, event);
+  g_print ("%s\n", res ? "ok" : "failed");
+
+}
+
+static void
+keyboard_cb (const gchar * key, AppData * data)
+{
+  switch (g_ascii_tolower (key[0])) {
+    case 'r':
+      send_rotate_event (data);
+      break;
+    case 's':{
+      if (use_postproc) {
+        g_object_set (G_OBJECT (data->rotator), "video-direction",
+            GST_VIDEO_ORIENTATION_AUTO, NULL);
+      } else {
+        /* rotation=360 means auto for vaapisnk */
+        g_object_set (G_OBJECT (data->rotator), "rotation", 360, NULL);
+      }
+      break;
+    }
+    case 'q':
+      g_main_loop_quit (data->loop);
+      break;
+    default:
+      break;
+  }
+}
+
+static gboolean
+bus_msg (GstBus * bus, GstMessage * msg, gpointer user_data)
+{
+  AppData *data = user_data;
+
+  switch (GST_MESSAGE_TYPE (msg)) {
+    case GST_MESSAGE_ELEMENT:
+    {
+      GstNavigationMessageType mtype = gst_navigation_message_get_type (msg);
+      if (mtype == GST_NAVIGATION_MESSAGE_EVENT) {
+        GstEvent *ev = NULL;
+
+        if (gst_navigation_message_parse_event (msg, &ev)) {
+          GstNavigationEventType type = gst_navigation_event_get_type (ev);
+          if (type == GST_NAVIGATION_EVENT_KEY_PRESS) {
+            const gchar *key;
+
+            if (gst_navigation_event_parse_key_event (ev, &key))
+              keyboard_cb (key, data);
+          }
+        }
+        if (ev)
+          gst_event_unref (ev);
+      }
+      break;
+    }
+    default:
+      break;
+  }
+
+  return TRUE;
+}
+
+/* Process keyboard input */
+static gboolean
+handle_keyboard (GIOChannel * source, GIOCondition cond, AppData * data)
+{
+  gchar *str = NULL;
+
+  if (g_io_channel_read_line (source, &str, NULL, NULL,
+          NULL) != G_IO_STATUS_NORMAL) {
+    return TRUE;
+  }
+
+  keyboard_cb (str, data);
+  g_free (str);
+
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  AppData data;
+  GstStateChangeReturn ret;
+  GIOChannel *io_stdin;
+  GOptionContext *ctx;
+  GError *err = NULL;
+  guint srcid;
+
+  /* Initialize GStreamer */
+  ctx = g_option_context_new ("- test options");
+  if (!ctx)
+    return -1;
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  g_option_context_add_main_entries (ctx, g_options, NULL);
+  if (!g_option_context_parse (ctx, &argc, &argv, NULL))
+    return -1;
+  g_option_context_free (ctx);
+
+  /* Print usage map */
+  g_print ("USAGE: Choose one of the following options, then press enter:\n"
+      " 'r' to send image-orientation tag event\n"
+      " 's' to set orient-automatic\n" " 'Q' to quit\n");
+
+  if (use_postproc) {
+    data.pipeline =
+        gst_parse_launch ("videotestsrc ! vaapipostproc name=pp ! xvimagesink",
+        &err);
+  } else {
+    data.pipeline =
+        gst_parse_launch ("videotestsrc ! vaapisink name=sink", &err);
+  }
+  if (err) {
+    g_printerr ("failed to create pipeline: %s\n", err->message);
+    g_error_free (err);
+    return -1;
+  }
+
+  if (use_postproc)
+    data.rotator = gst_bin_get_by_name (GST_BIN (data.pipeline), "pp");
+  else
+    data.rotator = gst_bin_get_by_name (GST_BIN (data.pipeline), "sink");
+  srcid = gst_bus_add_watch (GST_ELEMENT_BUS (data.pipeline), bus_msg, &data);
+
+  /* Add a keyboard watch so we get notified of keystrokes */
+  io_stdin = g_io_channel_unix_new (fileno (stdin));
+  g_io_add_watch (io_stdin, G_IO_IN, (GIOFunc) handle_keyboard, &data);
+
+  /* Start playing */
+  ret = gst_element_set_state (data.pipeline, GST_STATE_PLAYING);
+  if (ret == GST_STATE_CHANGE_FAILURE) {
+    g_printerr ("Unable to set the pipeline to the playing state.\n");
+    goto bail;
+  }
+
+  /* Create a GLib Main Loop and set it to run */
+  data.loop = g_main_loop_new (NULL, FALSE);
+  g_main_loop_run (data.loop);
+
+  gst_element_set_state (data.pipeline, GST_STATE_NULL);
+
+bail:
+  /* Free resources */
+  g_source_remove (srcid);
+  g_main_loop_unref (data.loop);
+  g_io_channel_unref (io_stdin);
+
+  gst_object_unref (data.rotator);
+  gst_object_unref (data.pipeline);
+
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/codec.c b/subprojects/gstreamer-vaapi/tests/internal/codec.c
new file mode 100644 (file)
index 0000000..d14981a
--- /dev/null
@@ -0,0 +1,195 @@
+/*
+ *  codec.c - Codec utilities for the tests
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/vaapi/gstvaapidisplay.h>
+#include "codec.h"
+
+typedef struct
+{
+  const gchar *codec_str;
+  GstVaapiCodec codec;
+  const gchar *caps_str;
+} CodecMap;
+
+static const CodecMap g_codec_map[] = {
+  {"h264", GST_VAAPI_CODEC_H264,
+      "video/x-h264"},
+  {"jpeg", GST_VAAPI_CODEC_JPEG,
+      "image/jpeg"},
+  {"mpeg2", GST_VAAPI_CODEC_MPEG2,
+      "video/mpeg, mpegversion=2"},
+  {"mpeg4", GST_VAAPI_CODEC_MPEG4,
+      "video/mpeg, mpegversion=4"},
+  {"wmv3", GST_VAAPI_CODEC_VC1,
+      "video/x-wmv, wmvversion=3"},
+  {"vc1", GST_VAAPI_CODEC_VC1,
+      "video/x-wmv, wmvversion=3, format=(string)WVC1"},
+  {NULL,}
+};
+
+static const CodecMap *
+get_codec_map (GstVaapiCodec codec)
+{
+  const CodecMap *m;
+
+  if (codec) {
+    for (m = g_codec_map; m->codec_str != NULL; m++) {
+      if (m->codec == codec)
+        return m;
+    }
+  }
+  return NULL;
+}
+
+const gchar *
+string_from_codec (GstVaapiCodec codec)
+{
+  const CodecMap *const m = get_codec_map (codec);
+
+  return m ? m->codec_str : NULL;
+}
+
+GstCaps *
+caps_from_codec (GstVaapiCodec codec)
+{
+  const CodecMap *const m = get_codec_map (codec);
+
+  return m ? gst_caps_from_string (m->caps_str) : NULL;
+}
+
+GstVaapiCodec
+identify_codec_from_string (const gchar * codec_str)
+{
+  const CodecMap *m;
+
+  if (codec_str) {
+    for (m = g_codec_map; m->codec_str != NULL; m++) {
+      if (g_ascii_strcasecmp (m->codec_str, codec_str) == 0)
+        return m->codec;
+    }
+  }
+  return 0;
+}
+
+typedef struct
+{
+  GMappedFile *file;
+  guint8 *data;
+  guint size;
+  guint probability;
+  GstCaps *caps;
+  GstTypeFind type_find;
+} CodecIdentifier;
+
+static const guint8 *
+codec_identifier_peek (gpointer data, gint64 offset, guint size)
+{
+  CodecIdentifier *const cip = data;
+
+  if (offset >= 0 && offset + size <= cip->size)
+    return cip->data + offset;
+  if (offset < 0 && ((gint) cip->size + offset) >= 0)
+    return &cip->data[cip->size + offset];
+  return NULL;
+}
+
+static void
+codec_identifier_suggest (gpointer data, guint probability, GstCaps * caps)
+{
+  CodecIdentifier *const cip = data;
+
+  if (cip->probability < probability) {
+    cip->probability = probability;
+    gst_caps_replace (&cip->caps, caps);
+  }
+}
+
+static void
+codec_identifier_free (CodecIdentifier * cip)
+{
+  if (!cip)
+    return;
+
+  if (cip->file) {
+    g_mapped_file_unref (cip->file);
+    cip->file = NULL;
+  }
+  gst_caps_replace (&cip->caps, NULL);
+  g_slice_free (CodecIdentifier, cip);
+}
+
+static CodecIdentifier *
+codec_identifier_new (const gchar * filename)
+{
+  CodecIdentifier *cip;
+  GstTypeFind *tfp;
+
+  cip = g_slice_new0 (CodecIdentifier);
+  if (!cip)
+    return NULL;
+
+  cip->file = g_mapped_file_new (filename, FALSE, NULL);
+  if (!cip->file)
+    goto error;
+
+  cip->size = g_mapped_file_get_length (cip->file);
+  cip->data = (guint8 *) g_mapped_file_get_contents (cip->file);
+  if (!cip->data)
+    goto error;
+
+  tfp = &cip->type_find;
+  tfp->peek = codec_identifier_peek;
+  tfp->suggest = codec_identifier_suggest;
+  tfp->data = cip;
+  return cip;
+
+error:
+  codec_identifier_free (cip);
+  return NULL;
+}
+
+GstVaapiCodec
+identify_codec (const gchar * filename)
+{
+  CodecIdentifier *cip;
+  GList *type_list, *l;
+  guint32 codec = 0;
+
+  cip = codec_identifier_new (filename);
+  if (!cip)
+    return 0;
+
+  type_list = gst_type_find_factory_get_list ();
+  for (l = type_list; l != NULL; l = l->next) {
+    GstTypeFindFactory *const factory = GST_TYPE_FIND_FACTORY (l->data);
+    gst_type_find_factory_call_function (factory, &cip->type_find);
+  }
+  g_list_free (type_list);
+
+  if (cip->probability >= GST_TYPE_FIND_LIKELY)
+    codec =
+        gst_vaapi_profile_get_codec (gst_vaapi_profile_from_caps (cip->caps));
+
+  codec_identifier_free (cip);
+  return codec;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/codec.h b/subprojects/gstreamer-vaapi/tests/internal/codec.h
new file mode 100644 (file)
index 0000000..6aaf5b8
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  codec.h - Codec utilities for the tests
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef CODEC_H
+#define CODEC_H
+
+#include <gst/vaapi/gstvaapiprofile.h>
+
+const gchar *
+string_from_codec(GstVaapiCodec codec);
+
+GstCaps *
+caps_from_codec(GstVaapiCodec codec);
+
+GstVaapiCodec
+identify_codec_from_string(const gchar *codec_str);
+
+GstVaapiCodec
+identify_codec(const gchar *filename);
+
+#endif /* CODEC_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/decoder.c b/subprojects/gstreamer-vaapi/tests/internal/decoder.c
new file mode 100644 (file)
index 0000000..1dfbba2
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ *  decoder.h - Decoder utilities for the tests
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/vaapi/gstvaapidecoder_h264.h>
+#include <gst/vaapi/gstvaapidecoder_jpeg.h>
+#include <gst/vaapi/gstvaapidecoder_mpeg2.h>
+#include <gst/vaapi/gstvaapidecoder_mpeg4.h>
+#include <gst/vaapi/gstvaapidecoder_vc1.h>
+#include "decoder.h"
+#include "test-jpeg.h"
+#include "test-mpeg2.h"
+#include "test-mpeg4.h"
+#include "test-h264.h"
+#include "test-vc1.h"
+
+typedef void (*GetVideoInfoFunc) (VideoDecodeInfo * info);
+
+typedef struct _CodecDefs CodecDefs;
+struct _CodecDefs
+{
+  const gchar *codec_str;
+  GetVideoInfoFunc get_video_info;
+};
+
+static const CodecDefs g_codec_defs[] = {
+#define INIT_FUNCS(CODEC) { #CODEC, CODEC##_get_video_info }
+  INIT_FUNCS (jpeg),
+  INIT_FUNCS (mpeg2),
+  INIT_FUNCS (mpeg4),
+  INIT_FUNCS (h264),
+  INIT_FUNCS (vc1),
+#undef INIT_FUNCS
+  {NULL,}
+};
+
+static const CodecDefs *
+find_codec_defs (const gchar * codec_str)
+{
+  const CodecDefs *c;
+  for (c = g_codec_defs; c->codec_str; c++)
+    if (strcmp (codec_str, c->codec_str) == 0)
+      return c;
+  return NULL;
+}
+
+static inline const CodecDefs *
+get_codec_defs (GstVaapiDecoder * decoder)
+{
+  return gst_vaapi_decoder_get_user_data (decoder);
+}
+
+static inline void
+set_codec_defs (GstVaapiDecoder * decoder, const CodecDefs * c)
+{
+  gst_vaapi_decoder_set_user_data (decoder, (gpointer) c);
+}
+
+GstVaapiDecoder *
+decoder_new (GstVaapiDisplay * display, const gchar * codec_name)
+{
+  GstVaapiDecoder *decoder;
+  const CodecDefs *codec;
+  GstCaps *caps;
+  VideoDecodeInfo info;
+
+  if (!codec_name)
+    codec_name = "h264";
+
+  codec = find_codec_defs (codec_name);
+  if (!codec) {
+    GST_ERROR ("failed to find %s codec data", codec_name);
+    return NULL;
+  }
+
+  codec->get_video_info (&info);
+  caps = gst_vaapi_profile_get_caps (info.profile);
+  if (!caps) {
+    GST_ERROR ("failed to create decoder caps");
+    return NULL;
+  }
+
+  if (info.width > 0 && info.height > 0)
+    gst_caps_set_simple (caps,
+        "width", G_TYPE_INT, info.width,
+        "height", G_TYPE_INT, info.height, NULL);
+
+  switch (gst_vaapi_profile_get_codec (info.profile)) {
+    case GST_VAAPI_CODEC_H264:
+      decoder = gst_vaapi_decoder_h264_new (display, caps);
+      break;
+    case GST_VAAPI_CODEC_JPEG:
+      decoder = gst_vaapi_decoder_jpeg_new (display, caps);
+      break;
+    case GST_VAAPI_CODEC_MPEG2:
+      decoder = gst_vaapi_decoder_mpeg2_new (display, caps);
+      break;
+    case GST_VAAPI_CODEC_MPEG4:
+      decoder = gst_vaapi_decoder_mpeg4_new (display, caps);
+      break;
+    case GST_VAAPI_CODEC_VC1:
+      decoder = gst_vaapi_decoder_vc1_new (display, caps);
+      break;
+    default:
+      decoder = NULL;
+      break;
+  }
+  gst_caps_unref (caps);
+  if (!decoder) {
+    GST_ERROR ("failed to create %s decoder", codec->codec_str);
+    return NULL;
+  }
+
+  set_codec_defs (decoder, codec);
+  return decoder;
+}
+
+gboolean
+decoder_put_buffers (GstVaapiDecoder * decoder)
+{
+  const CodecDefs *codec;
+  VideoDecodeInfo info;
+  GstBuffer *buffer;
+  gboolean success;
+
+  g_return_val_if_fail (decoder != NULL, FALSE);
+
+  codec = get_codec_defs (decoder);
+  g_return_val_if_fail (codec != NULL, FALSE);
+
+  codec->get_video_info (&info);
+  buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+      (guchar *) info.data, info.data_size, 0, info.data_size, NULL, NULL);
+  if (!buffer) {
+    GST_ERROR ("failed to create encoded data buffer");
+    return FALSE;
+  }
+
+  success = gst_vaapi_decoder_put_buffer (decoder, buffer);
+  gst_buffer_unref (buffer);
+  if (!success) {
+    GST_ERROR ("failed to send video data to the decoder");
+    return FALSE;
+  }
+
+  if (!gst_vaapi_decoder_put_buffer (decoder, NULL)) {
+    GST_ERROR ("failed to submit <end-of-stream> to the decoder");
+    return FALSE;
+  }
+  return TRUE;
+}
+
+GstVaapiSurfaceProxy *
+decoder_get_surface (GstVaapiDecoder * decoder)
+{
+  GstVaapiSurfaceProxy *proxy;
+  GstVaapiDecoderStatus status;
+
+  g_return_val_if_fail (decoder != NULL, NULL);
+
+  status = gst_vaapi_decoder_get_surface (decoder, &proxy);
+  if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+    GST_ERROR ("failed to get decoded surface (decoder status %d)", status);
+    return NULL;
+  }
+  return proxy;
+}
+
+const gchar *
+decoder_get_codec_name (GstVaapiDecoder * decoder)
+{
+  const CodecDefs *codec;
+
+  g_return_val_if_fail (decoder != NULL, NULL);
+
+  codec = get_codec_defs (decoder);
+  g_return_val_if_fail (codec != NULL, FALSE);
+
+  return codec->codec_str;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/decoder.h b/subprojects/gstreamer-vaapi/tests/internal/decoder.h
new file mode 100644 (file)
index 0000000..6853000
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  decoder.h - Decoder utilities for the tests
+ *
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef DECODER_H
+#define DECODER_H
+
+#include <gst/vaapi/gstvaapidecoder.h>
+
+GstVaapiDecoder *
+decoder_new(GstVaapiDisplay *display, const gchar *codec_name);
+
+gboolean
+decoder_put_buffers(GstVaapiDecoder *decoder);
+
+GstVaapiSurfaceProxy *
+decoder_get_surface(GstVaapiDecoder *decoder);
+
+const gchar *
+decoder_get_codec_name(GstVaapiDecoder *decoder);
+
+#endif /* DECODER_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/image.c b/subprojects/gstreamer-vaapi/tests/internal/image.c
new file mode 100644 (file)
index 0000000..ea532fb
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ *  image.c - Image utilities for the tests
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "image.h"
+
+static gboolean
+image_draw_rectangle (GstVaapiImage * image,
+    gint x, gint y, guint width, guint height, guint32 color, guint32 flags);
+
+static gboolean
+image_draw_color_rectangles (GstVaapiImage * image,
+    guint width, guint height, const guint32 colors[4], guint32 flags)
+{
+  const guint w = width / 2;
+  const guint h = height / 2;
+
+  if (!image_draw_rectangle (image, 0, 0, w, h, colors[0], flags))
+    return FALSE;
+  if (!image_draw_rectangle (image, w, 0, w, h, colors[1], flags))
+    return FALSE;
+  if (!image_draw_rectangle (image, 0, h, w, h, colors[2], flags))
+    return FALSE;
+  if (!image_draw_rectangle (image, w, h, w, h, colors[3], flags))
+    return FALSE;
+  return TRUE;
+}
+
+GstVaapiImage *
+image_generate (GstVaapiDisplay * display,
+    GstVideoFormat format, guint width, guint height)
+{
+  return image_generate_full (display, format, width, height, 0);
+}
+
+GstVaapiImage *
+image_generate_full (GstVaapiDisplay * display,
+    GstVideoFormat format, guint width, guint height, guint32 flags)
+{
+  GstVaapiImage *image;
+
+  static const guint32 rgb_colors[4] =
+      { 0xffff0000, 0xff00ff00, 0xff0000ff, 0xff000000 };
+  static const guint32 bgr_colors[4] =
+      { 0xff000000, 0xff0000ff, 0xff00ff00, 0xffff0000 };
+  static const guint32 inv_colors[4] =
+      { 0xffdeadc0, 0xffdeadc0, 0xffdeadc0, 0xffdeadc0 };
+
+  image = gst_vaapi_image_new (display, format, width, height);
+  if (!image)
+    return NULL;
+
+  if (flags) {
+    if (!image_draw_color_rectangles (image, width, height,
+            ((flags & GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD) ?
+                rgb_colors : inv_colors),
+            GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD))
+      goto error;
+
+    if (!image_draw_color_rectangles (image, width, height,
+            ((flags & GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD) ?
+                bgr_colors : inv_colors),
+            GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD))
+      goto error;
+  } else if (!image_draw_color_rectangles (image, width, height, rgb_colors, 0))
+    goto error;
+  return image;
+
+error:
+  gst_vaapi_image_unref (image);
+  return NULL;
+}
+
+typedef void (*DrawRectFunc) (guchar * pixels[3],
+    guint stride[3], gint x, gint y, guint width, guint height, guint32 color);
+
+static void
+draw_rect_ARGB (guchar * pixels[3],
+    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
+{
+  guint i, j;
+
+  color = GUINT32_TO_BE (color);
+
+  for (j = 0; j < height; j++) {
+    guint32 *p = (guint32 *) (pixels[0] + (y + j) * stride[0] + x * 4);
+    for (i = 0; i < width; i++)
+      p[i] = color;
+  }
+}
+
+static void
+draw_rect_BGRA (guchar * pixels[3],
+    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
+{
+  // Converts ARGB color to BGRA
+  color = GUINT32_SWAP_LE_BE (color);
+
+  draw_rect_ARGB (pixels, stride, x, y, width, height, color);
+}
+
+static void
+draw_rect_RGBA (guchar * pixels[3],
+    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
+{
+  // Converts ARGB color to RGBA
+  color = ((color >> 24) & 0xff) | ((color & 0xffffff) << 8);
+
+  draw_rect_ARGB (pixels, stride, x, y, width, height, color);
+}
+
+static void
+draw_rect_ABGR (guchar * pixels[3],
+    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
+{
+  // Converts ARGB color to ABGR
+  color = ((color & 0xff00ff00) |
+      ((color >> 16) & 0xff) | ((color & 0xff) << 16));
+
+  draw_rect_ARGB (pixels, stride, x, y, width, height, color);
+}
+
+static void
+draw_rect_NV12 (                // Y, UV planes
+    guchar * pixels[3],
+    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
+{
+  const guchar Y = color >> 16;
+  const guchar Cb = color >> 8;
+  const guchar Cr = color;
+  guchar *dst;
+  guint i, j;
+
+  dst = pixels[0] + y * stride[0] + x;
+  for (j = 0; j < height; j++, dst += stride[0])
+    for (i = 0; i < width; i++)
+      dst[i] = Y;
+
+  x /= 2;
+  y /= 2;
+  width /= 2;
+  height /= 2;
+
+  dst = pixels[1] + y * stride[1] + x * 2;
+  for (j = 0; j < height; j++, dst += stride[1])
+    for (i = 0; i < width; i++) {
+      dst[2 * i + 0] = Cb;
+      dst[2 * i + 1] = Cr;
+    }
+}
+
+static void
+draw_rect_YV12 (                // Y, V, U planes
+    guchar * pixels[3],
+    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
+{
+  const guchar Y = color >> 16;
+  const guchar Cb = color >> 8;
+  const guchar Cr = color;
+  guchar *pY, *pU, *pV;
+  guint i, j;
+
+  pY = pixels[0] + y * stride[0] + x;
+  for (j = 0; j < height; j++, pY += stride[0])
+    for (i = 0; i < width; i++)
+      pY[i] = Y;
+
+  x /= 2;
+  y /= 2;
+  width /= 2;
+  height /= 2;
+
+  pV = pixels[1] + y * stride[1] + x;
+  pU = pixels[2] + y * stride[2] + x;
+  for (j = 0; j < height; j++, pU += stride[1], pV += stride[2])
+    for (i = 0; i < width; i++) {
+      pU[i] = Cb;
+      pV[i] = Cr;
+    }
+}
+
+static void
+draw_rect_I420 (                // Y, U, V planes
+    guchar * pixels[3],
+    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
+{
+  guchar *new_pixels[3] = { pixels[0], pixels[2], pixels[1] };
+  guint new_stride[3] = { stride[0], stride[2], stride[1] };
+
+  draw_rect_YV12 (new_pixels, new_stride, x, y, width, height, color);
+}
+
+static void
+draw_rect_YUV422 (guchar * pixels[3], guint stride[3],
+    gint x, gint y, guint width, guint height, guint32 color)
+{
+  guint i, j;
+
+  width /= 2;
+  for (j = 0; j < height; j++) {
+    guint32 *const p = (guint32 *)
+        (pixels[0] + (y + j) * stride[0] + x * 2);
+    for (i = 0; i < width; i++)
+      p[i] = color;
+  }
+}
+
+static void
+draw_rect_YUY2 (guchar * pixels[3], guint stride[3],
+    gint x, gint y, guint width, guint height, guint32 color)
+{
+  const guchar Y = color >> 16;
+  const guchar Cb = color >> 8;
+  const guchar Cr = color;
+
+  color = (Y << 24) | (Cb << 16) | (Y << 8) | Cr;
+  draw_rect_YUV422 (pixels, stride, x, y, width, height, GUINT32_TO_BE (color));
+}
+
+static void
+draw_rect_UYVY (guchar * pixels[3], guint stride[3],
+    gint x, gint y, guint width, guint height, guint32 color)
+{
+  const guchar Y = color >> 16;
+  const guchar Cb = color >> 8;
+  const guchar Cr = color;
+
+  color = (Cb << 24) | (Y << 16) | (Cr << 8) | Y;
+  draw_rect_YUV422 (pixels, stride, x, y, width, height, GUINT32_TO_BE (color));
+}
+
+static void
+draw_rect_AYUV (guchar * pixels[3],
+    guint stride[3], gint x, gint y, guint width, guint height, guint32 color)
+{
+  guint i, j;
+
+  color = color | 0xff000000;
+
+  for (j = 0; j < height; j++) {
+    guint32 *p = (guint32 *) (pixels[0] + (y + j) * stride[0] + x * 4);
+    for (i = 0; i < width; i++)
+      p[i] = color;
+  }
+}
+
+static inline guint32
+argb2yuv (guint32 color)
+{
+  const gint32 r = (color >> 16) & 0xff;
+  const gint32 g = (color >> 8) & 0xff;
+  const gint32 b = (color) & 0xff;
+
+  const guint32 y = ((306 * r + 601 * g + 116 * b) >> 10);
+  const guint32 u = ((-172 * r - 339 * g + 512 * b) >> 10) + 128;
+  const guint32 v = ((512 * r - 428 * g - 83 * b) >> 10) + 128;
+
+  return (y << 16) | (u << 8) | v;
+}
+
+gboolean
+image_draw_rectangle (GstVaapiImage * image,
+    gint x, gint y, guint width, guint height, guint32 color, guint32 flags)
+{
+  const GstVideoFormat image_format = gst_vaapi_image_get_format (image);
+  const guint image_width = gst_vaapi_image_get_width (image);
+  const guint image_height = gst_vaapi_image_get_height (image);
+  GstVaapiDisplay *display;
+  guchar *pixels[3];
+  guint stride[3];
+  DrawRectFunc draw_rect = NULL;
+  guint i;
+
+  static const struct
+  {
+    GstVideoFormat format;
+    DrawRectFunc draw_rect;
+  }
+  map[] = {
+#define _(FORMAT) { GST_VIDEO_FORMAT_##FORMAT, draw_rect_##FORMAT }
+    _(ARGB),
+        _(BGRA),
+        _(RGBA), _(ABGR), _(NV12), _(YV12), _(I420), _(YUY2), _(UYVY), _(AYUV),
+#undef  _
+    {
+    0,}
+  };
+
+  for (i = 0; !draw_rect && map[i].format; i++)
+    if (map[i].format == image_format)
+      draw_rect = map[i].draw_rect;
+  if (!draw_rect)
+    return FALSE;
+
+  if (x < 0)
+    x = 0;
+  if (y < 0)
+    y = 0;
+  if (width > image_width - x)
+    width = image_width - x;
+  if (height > image_height - y)
+    height = image_height - y;
+
+  display = gst_vaapi_image_get_display (image);
+  if (!display)
+    return FALSE;
+
+  if (!gst_vaapi_image_map (image))
+    return FALSE;
+
+  for (i = 0; i < gst_vaapi_image_get_plane_count (image); i++) {
+    pixels[i] = gst_vaapi_image_get_plane (image, i);
+    stride[i] = gst_vaapi_image_get_pitch (image, i);
+    switch (flags) {
+      case GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD:
+        pixels[i] += stride[i];
+        // fall-through
+      case GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD:
+        stride[i] *= 2;
+        break;
+    }
+  }
+
+  if (flags)
+    y /= 2, height /= 2;
+
+  if (gst_vaapi_video_format_is_yuv (image_format))
+    color = argb2yuv (color);
+
+  draw_rect (pixels, stride, x, y, width, height, color);
+  return gst_vaapi_image_unmap (image);
+}
+
+gboolean
+image_upload (GstVaapiImage * image, GstVaapiSurface * surface)
+{
+  GstVaapiDisplay *display;
+  GstVideoFormat format;
+  GstVaapiImage *surface_image;
+  GstVaapiSubpicture *subpicture;
+  gboolean success;
+
+  display = gst_vaapi_surface_get_display (surface);
+  if (!display)
+    return FALSE;
+
+  format = gst_vaapi_image_get_format (image);
+  if (!format)
+    return FALSE;
+
+  if (gst_vaapi_surface_put_image (surface, image))
+    return TRUE;
+
+  surface_image = gst_vaapi_surface_derive_image (surface);
+  if (surface_image) {
+    success = gst_vaapi_image_copy (surface_image, image);
+    gst_vaapi_image_unref (surface_image);
+    if (success)
+      return TRUE;
+  }
+
+  g_print ("could not upload %s image to surface\n",
+      gst_vaapi_video_format_to_string (format));
+
+  if (!gst_vaapi_display_has_subpicture_format (display, format, NULL))
+    return FALSE;
+
+  g_print ("trying as a subpicture\n");
+
+  subpicture = gst_vaapi_subpicture_new (image, 0);
+  if (!subpicture)
+    g_error ("could not create VA subpicture");
+
+  if (!gst_vaapi_surface_associate_subpicture (surface, subpicture, NULL, NULL))
+    g_error ("could not associate subpicture to surface");
+
+  /* The surface holds a reference to the subpicture. This is safe */
+  gst_vaapi_subpicture_unref (subpicture);
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/image.h b/subprojects/gstreamer-vaapi/tests/internal/image.h
new file mode 100644 (file)
index 0000000..6abbdb0
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *  image.h - Image utilities for the tests
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef IMAGE_H
+#define IMAGE_H
+
+#include <gst/vaapi/gstvaapiimage.h>
+#include <gst/vaapi/gstvaapisurface.h>
+
+GstVaapiImage *
+image_generate(
+    GstVaapiDisplay    *display,
+    GstVideoFormat      format,
+    guint               width,
+    guint               height
+);
+
+GstVaapiImage *
+image_generate_full(
+    GstVaapiDisplay    *display,
+    GstVideoFormat      format,
+    guint               width,
+    guint               height,
+    guint32             flags
+);
+
+gboolean
+image_upload(GstVaapiImage *image, GstVaapiSurface *surface);
+
+#endif /* IMAGE_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/meson.build b/subprojects/gstreamer-vaapi/tests/internal/meson.build
new file mode 100644 (file)
index 0000000..1afd22b
--- /dev/null
@@ -0,0 +1,74 @@
+libdecutils_sources = [
+  'decoder.c',
+  'test-h264.c',
+  'test-jpeg.c',
+  'test-mpeg2.c',
+  'test-mpeg4.c',
+  'test-vc1.c',
+]
+
+libdecutils_headers = [
+  'decoder.h',
+  'test-h264.h',
+  'test-jpeg.h',
+  'test-mpeg2.h',
+  'test-mpeg4.h',
+  'test-vc1.h',
+]
+
+libutils_sources = [
+  'codec.c',
+  'image.c',
+  'output.c',
+  'test-subpicture-data.c',
+  'y4mreader.c',
+]
+
+libutils_headers = [
+  'codec.h',
+  'image.h',
+  'output.h',
+  'test-subpicture-data.h',
+  'y4mreader.h',
+]
+
+test_examples = [
+  'simple-decoder',
+  'test-decode',
+  'test-display',
+  'test-filter',
+  'test-surfaces',
+  'test-windows',
+  'test-subpicture',
+]
+
+if USE_ENCODERS
+  test_examples += [ 'simple-encoder' ]
+endif
+
+if USE_GLX
+  test_examples += [ 'test-textures' ]
+endif
+
+libutils = static_library('libutils',
+  libutils_sources + libutils_headers,
+  c_args : gstreamer_vaapi_args,
+  include_directories: [configinc, libsinc],
+  dependencies : gstlibvaapi_deps,
+  install: false)
+
+libdecutils = static_library('libdecutils',
+  libdecutils_sources + libdecutils_headers,
+  c_args : gstreamer_vaapi_args,
+  include_directories: [configinc, libsinc],
+  dependencies : gstlibvaapi_deps,
+  install: false)
+
+foreach example : test_examples
+  executable(example, '@0@.c'.format(example),
+    c_args : gstreamer_vaapi_args,
+    include_directories: [configinc, libsinc],
+    dependencies : [gst_dep, libva_dep,  gstlibvaapi_dep],
+    link_with: [libutils, libdecutils],
+    install: false)
+endforeach
diff --git a/subprojects/gstreamer-vaapi/tests/internal/output.c b/subprojects/gstreamer-vaapi/tests/internal/output.c
new file mode 100644 (file)
index 0000000..074afa2
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *  output.c - Video output helpers
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/gst.h>
+#if GST_VAAPI_USE_DRM
+# include <gst/vaapi/gstvaapidisplay_drm.h>
+# include <gst/vaapi/gstvaapiwindow_drm.h>
+#endif
+#if GST_VAAPI_USE_X11
+# include <gst/vaapi/gstvaapidisplay_x11.h>
+# include <gst/vaapi/gstvaapiwindow_x11.h>
+#endif
+#if GST_VAAPI_USE_GLX
+# include <gst/vaapi/gstvaapidisplay_glx.h>
+# include <gst/vaapi/gstvaapiwindow_glx.h>
+#endif
+#if GST_VAAPI_USE_EGL
+# include <gst/vaapi/gstvaapidisplay_egl.h>
+# include <gst/vaapi/gstvaapiwindow_egl.h>
+#endif
+#if GST_VAAPI_USE_WAYLAND
+# include <gst/vaapi/gstvaapidisplay_wayland.h>
+# include <gst/vaapi/gstvaapiwindow_wayland.h>
+#endif
+#include "output.h"
+
+static const VideoOutputInfo *g_video_output;
+static const VideoOutputInfo g_video_outputs[] = {
+  /* Video outputs are sorted in test order for automatic characterisation */
+#if GST_VAAPI_USE_WAYLAND
+  {"wayland",
+        gst_vaapi_display_wayland_new,
+      gst_vaapi_window_wayland_new},
+#endif
+#if GST_VAAPI_USE_X11
+  {"x11",
+        gst_vaapi_display_x11_new,
+      gst_vaapi_window_x11_new},
+#endif
+#if GST_VAAPI_USE_GLX
+  {"glx",
+        gst_vaapi_display_glx_new,
+      gst_vaapi_window_glx_new},
+#endif
+#if GST_VAAPI_USE_DRM
+  {"drm",
+        gst_vaapi_display_drm_new,
+      gst_vaapi_window_drm_new},
+#endif
+  {NULL,}
+};
+
+static gchar *g_output_name;
+static gboolean g_list_outputs = FALSE;
+static gboolean g_fullscreen = FALSE;
+
+static gboolean g_egl_mode = FALSE;
+static guint g_gles_version;
+
+static GOptionEntry g_options[] = {
+  {"list-outputs", 0,
+        0,
+        G_OPTION_ARG_NONE, &g_list_outputs,
+      "list video outputs", NULL},
+  {"output", 'o',
+        0,
+        G_OPTION_ARG_STRING, &g_output_name,
+      "video output name", NULL},
+  {"fullscreen", 'f',
+        0,
+        G_OPTION_ARG_NONE, &g_fullscreen,
+      "fullscreen mode", NULL},
+  {"egl", 0,
+        0,
+        G_OPTION_ARG_NONE, &g_egl_mode,
+      "enable EGL rendering", NULL},
+  {"gles-version", 0,
+        0,
+        G_OPTION_ARG_INT, &g_gles_version,
+      "OpenGL|ES version (in --egl mode)", NULL},
+  {NULL,}
+};
+
+static void
+list_outputs (void)
+{
+  const VideoOutputInfo *o;
+
+  g_print ("Video outputs:");
+  for (o = g_video_outputs; o->name != NULL; o++)
+    g_print (" %s", o->name);
+  g_print ("\n");
+}
+
+gboolean
+video_output_init (int *argc, char *argv[], GOptionEntry * options)
+{
+  GOptionContext *ctx;
+  gboolean success;
+
+  ctx = g_option_context_new ("- test options");
+  if (!ctx)
+    return FALSE;
+
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  g_option_context_add_main_entries (ctx, g_options, NULL);
+  if (options)
+    g_option_context_add_main_entries (ctx, options, NULL);
+  success = g_option_context_parse (ctx, argc, &argv, NULL);
+  g_option_context_free (ctx);
+
+  if (g_list_outputs) {
+    list_outputs ();
+    exit (0);
+  }
+  return success;
+}
+
+void
+video_output_exit (void)
+{
+  g_free (g_output_name);
+  gst_deinit ();
+}
+
+const VideoOutputInfo *
+video_output_lookup (const gchar * output_name)
+{
+  const VideoOutputInfo *o;
+
+  if (!output_name)
+    return NULL;
+
+  for (o = g_video_outputs; o->name != NULL; o++) {
+    if (g_ascii_strcasecmp (o->name, output_name) == 0)
+      return o;
+  }
+  return NULL;
+}
+
+GstVaapiDisplay *
+video_output_create_display (const gchar * display_name)
+{
+  const VideoOutputInfo *o = g_video_output;
+  GstVaapiDisplay *egl_display, *display = NULL;
+
+  if (!o) {
+    if (g_output_name)
+      o = video_output_lookup (g_output_name);
+    else {
+      for (o = g_video_outputs; o->name != NULL; o++) {
+        display = o->create_display (display_name);
+        if (display) {
+          if (gst_vaapi_display_get_display (display))
+            break;
+          gst_object_unref (display);
+          display = NULL;
+        }
+      }
+    }
+    if (!o || !o->name)
+      return NULL;
+    g_print ("Using %s video output\n", o->name);
+    g_video_output = o;
+  }
+
+  if (!display)
+    display = o->create_display (display_name);
+
+  if (g_egl_mode) {
+#if GST_VAAPI_USE_EGL
+    egl_display = gst_vaapi_display_egl_new (display, g_gles_version);
+#else
+    egl_display = NULL;
+    g_print ("error: unsupported EGL renderering mode\n");
+#endif
+    gst_object_unref (display);
+    if (!egl_display)
+      return NULL;
+    display = egl_display;
+  }
+  return display;
+}
+
+GstVaapiWindow *
+video_output_create_window (GstVaapiDisplay * display, guint width,
+    guint height)
+{
+  GstVaapiWindow *window;
+
+  if (!g_video_output)
+    return NULL;
+
+#if GST_VAAPI_USE_EGL
+  if (g_egl_mode)
+    window = gst_vaapi_window_egl_new (display, width, height);
+  else
+#endif
+    window = g_video_output->create_window (display, width, height);
+  if (!window)
+    return NULL;
+
+  /* Force fullscreen mode, should this be requested by the user */
+  if (g_fullscreen)
+    gst_vaapi_window_set_fullscreen (window, TRUE);
+  return window;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/output.h b/subprojects/gstreamer-vaapi/tests/internal/output.h
new file mode 100644 (file)
index 0000000..6929915
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  output.h - Video output helpers
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef OUTPUT_H
+#define OUTPUT_H
+
+#include <glib.h>
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+
+typedef GstVaapiDisplay *(*CreateDisplayFunc)(const gchar *display_name);
+typedef GstVaapiWindow *(*CreateWindowFunc)(GstVaapiDisplay *display,
+                                            guint width, guint height);
+
+typedef struct _VideoOutputInfo VideoOutputInfo;
+struct _VideoOutputInfo {
+    const gchar        *name;
+    CreateDisplayFunc   create_display;
+    CreateWindowFunc    create_window;
+};
+
+gboolean
+video_output_init(int *argc, char *argv[], GOptionEntry *options);
+
+void
+video_output_exit(void);
+
+const VideoOutputInfo *
+video_output_lookup(const gchar *output_name);
+
+GstVaapiDisplay *
+video_output_create_display(const gchar *display_name);
+
+GstVaapiWindow *
+video_output_create_window(GstVaapiDisplay *display, guint width, guint height);
+
+#endif /* OUTPUT_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/simple-decoder.c b/subprojects/gstreamer-vaapi/tests/internal/simple-decoder.c
new file mode 100644 (file)
index 0000000..7575276
--- /dev/null
@@ -0,0 +1,691 @@
+/*
+ *  simple-decoder.c - Simple Decoder Application
+ *
+ *  Copyright (C) 2013-2014 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+/*
+ * This is a really simple decoder application that only accepts raw
+ * bitstreams. So, it may be needed to suggest what codec to use to
+ * the application.
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <stdarg.h>
+#include <gst/vaapi/gstvaapidecoder.h>
+#include <gst/vaapi/gstvaapidecoder_h264.h>
+#include <gst/vaapi/gstvaapidecoder_jpeg.h>
+#include <gst/vaapi/gstvaapidecoder_mpeg2.h>
+#include <gst/vaapi/gstvaapidecoder_mpeg4.h>
+#include <gst/vaapi/gstvaapidecoder_vc1.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+#include "codec.h"
+#include "output.h"
+
+static gchar *g_codec_str;
+static gboolean g_benchmark;
+
+static GOptionEntry g_options[] = {
+  {"codec", 'c',
+        0,
+        G_OPTION_ARG_STRING, &g_codec_str,
+      "suggested codec", NULL},
+  {"benchmark", 0,
+        0,
+        G_OPTION_ARG_NONE, &g_benchmark,
+      "benchmark mode", NULL},
+  {NULL,}
+};
+
+typedef enum
+{
+  APP_RUNNING,
+  APP_GOT_EOS,
+  APP_GOT_ERROR,
+} AppEvent;
+
+typedef enum
+{
+  APP_ERROR_NONE,
+  APP_ERROR_DECODER,
+  APP_ERROR_RENDERER,
+} AppError;
+
+typedef struct
+{
+  GstVaapiSurfaceProxy *proxy;
+  GstClockTime pts;
+  GstClockTime duration;
+} RenderFrame;
+
+typedef struct
+{
+  GMutex mutex;
+  GMappedFile *file;
+  gchar *file_name;
+  guint file_offset;
+  guint file_size;
+  guchar *file_data;
+  GstVaapiDisplay *display;
+  GstVaapiDecoder *decoder;
+  GThread *decoder_thread;
+  gboolean decoder_thread_cancel;
+  GAsyncQueue *decoder_queue;
+  GstVaapiCodec codec;
+  guint fps_n;
+  guint fps_d;
+  guint32 frame_duration;
+  guint surface_width;
+  guint surface_height;
+  GstVaapiWindow *window;
+  guint window_width;
+  guint window_height;
+  GThread *render_thread;
+  gboolean render_thread_cancel;
+  GCond render_ready;
+  RenderFrame *last_frame;
+  GError *error;
+  AppEvent event;
+  GCond event_cond;
+  GTimer *timer;
+  guint32 num_frames;
+} App;
+
+static inline RenderFrame *
+render_frame_new (void)
+{
+  return g_slice_new (RenderFrame);
+}
+
+static void
+render_frame_free (RenderFrame * rfp)
+{
+  if (G_UNLIKELY (!rfp))
+    return;
+  gst_vaapi_surface_proxy_replace (&rfp->proxy, NULL);
+  g_slice_free (RenderFrame, rfp);
+}
+
+static inline void
+render_frame_replace (RenderFrame ** rfp_ptr, RenderFrame * new_rfp)
+{
+  if (*rfp_ptr)
+    render_frame_free (*rfp_ptr);
+  *rfp_ptr = new_rfp;
+}
+
+#define APP_ERROR app_error_quark()
+static GQuark
+app_error_quark (void)
+{
+  static gsize g_quark;
+
+  if (g_once_init_enter (&g_quark)) {
+    gsize quark = (gsize) g_quark_from_static_string ("AppError");
+    g_once_init_leave (&g_quark, quark);
+  }
+  return g_quark;
+}
+
+static void
+app_send_error (App * app, GError * error)
+{
+  g_mutex_lock (&app->mutex);
+  app->error = error;
+  app->event = APP_GOT_ERROR;
+  g_cond_signal (&app->event_cond);
+  g_mutex_unlock (&app->mutex);
+}
+
+static void
+app_send_eos (App * app)
+{
+  g_mutex_lock (&app->mutex);
+  app->event = APP_GOT_EOS;
+  g_cond_signal (&app->event_cond);
+  g_mutex_unlock (&app->mutex);
+}
+
+static const gchar *
+get_decoder_status_string (GstVaapiDecoderStatus status)
+{
+  const gchar *str;
+
+#define DEFINE_STATUS(status, status_string) \
+    case GST_VAAPI_DECODER_STATUS_##status:  \
+        str = status_string;                 \
+        break
+
+  switch (status) {
+      DEFINE_STATUS (SUCCESS, "<success>");
+      DEFINE_STATUS (END_OF_STREAM, "<EOS>");
+      DEFINE_STATUS (ERROR_ALLOCATION_FAILED, "allocation failed");
+      DEFINE_STATUS (ERROR_INIT_FAILED, "initialization failed");
+      DEFINE_STATUS (ERROR_UNSUPPORTED_CODEC, "unsupported codec");
+      DEFINE_STATUS (ERROR_NO_DATA, "not enough data");
+      DEFINE_STATUS (ERROR_NO_SURFACE, "no surface vailable");
+      DEFINE_STATUS (ERROR_INVALID_SURFACE, "invalid surface");
+      DEFINE_STATUS (ERROR_BITSTREAM_PARSER, "bitstream parser error");
+      DEFINE_STATUS (ERROR_UNSUPPORTED_PROFILE, "unsupported profile");
+      DEFINE_STATUS (ERROR_UNSUPPORTED_CHROMA_FORMAT,
+          "unsupported chroma-format");
+      DEFINE_STATUS (ERROR_INVALID_PARAMETER, "invalid parameter");
+    default:
+      str = "<unknown>";
+      break;
+  }
+#undef DEFINE_STATUS
+
+  return str;
+}
+
+static const gchar *
+get_error_string (AppError error)
+{
+  const gchar *str;
+
+#define DEFINE_ERROR(error, error_string)       \
+    case APP_ERROR_##error:                     \
+        str = error_string;                     \
+        break
+
+  switch (error) {
+      DEFINE_ERROR (NONE, "<none>");
+      DEFINE_ERROR (DECODER, "decoder");
+      DEFINE_ERROR (RENDERER, "renderer");
+    default:
+      str = "unknown";
+      break;
+  }
+#undef DEFINE_ERROR
+
+  return str;
+}
+
+static gpointer
+decoder_thread (gpointer data)
+{
+  App *const app = data;
+  GError *error = NULL;
+  GstVaapiDecoderStatus status;
+  GstVaapiSurfaceProxy *proxy;
+  RenderFrame *rfp;
+  GstBuffer *buffer;
+  GstClockTime pts;
+  gboolean got_eos = FALSE;
+  guint ofs;
+
+  g_print ("Decoder thread started\n");
+
+#define SEND_ERROR(...)                                                 \
+    do {                                                                \
+        error = g_error_new(APP_ERROR, APP_ERROR_DECODER, __VA_ARGS__); \
+        goto send_error;                                                \
+    } while (0)
+
+  pts = g_get_monotonic_time ();
+  ofs = 0;
+  while (!g_atomic_int_get (&app->decoder_thread_cancel)) {
+    if (G_UNLIKELY (ofs == app->file_size))
+      buffer = NULL;
+    else {
+      const gsize size = MIN (4096, app->file_size - ofs);
+      buffer = gst_buffer_new_wrapped_full (GST_MEMORY_FLAG_READONLY,
+          app->file_data, app->file_size, ofs, size, NULL, NULL);
+      if (!buffer)
+        SEND_ERROR ("failed to allocate new buffer");
+      ofs += size;
+    }
+    if (!gst_vaapi_decoder_put_buffer (app->decoder, buffer))
+      SEND_ERROR ("failed to push buffer to decoder");
+    gst_buffer_replace (&buffer, NULL);
+
+    status = gst_vaapi_decoder_get_surface (app->decoder, &proxy);
+    switch (status) {
+      case GST_VAAPI_DECODER_STATUS_SUCCESS:
+        rfp = render_frame_new ();
+        if (!rfp)
+          SEND_ERROR ("failed to allocate render frame");
+        rfp->proxy = proxy;
+        rfp->pts = pts;
+        rfp->duration = app->frame_duration;
+        pts += app->frame_duration;
+        g_async_queue_push (app->decoder_queue, rfp);
+        break;
+      case GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA:
+        /* nothing to do, just continue to the next iteration */
+        break;
+      case GST_VAAPI_DECODER_STATUS_END_OF_STREAM:
+        gst_vaapi_decoder_flush (app->decoder);
+        if (got_eos)
+          goto send_eos;
+        got_eos = TRUE;
+        break;
+      default:
+        SEND_ERROR ("%s", get_decoder_status_string (status));
+        break;
+    }
+  }
+  return NULL;
+
+#undef SEND_ERROR
+
+send_eos:
+  app_send_eos (app);
+  return NULL;
+
+send_error:
+  app_send_error (app, error);
+  return NULL;
+}
+
+static void
+app_set_framerate (App * app, guint fps_n, guint fps_d)
+{
+  if (!fps_n || !fps_d)
+    return;
+
+  g_mutex_lock (&app->mutex);
+  if (fps_n != app->fps_n || fps_d != app->fps_d) {
+    app->fps_n = fps_n;
+    app->fps_d = fps_d;
+    app->frame_duration =
+        gst_util_uint64_scale (GST_TIME_AS_USECONDS (GST_SECOND), fps_d, fps_n);
+  }
+  g_mutex_unlock (&app->mutex);
+}
+
+static void
+handle_decoder_state_changes (GstVaapiDecoder * decoder,
+    const GstVideoCodecState * codec_state, gpointer user_data)
+{
+  App *const app = user_data;
+
+  g_assert (app->decoder == decoder);
+  app_set_framerate (app, codec_state->info.fps_n, codec_state->info.fps_d);
+}
+
+static gboolean
+start_decoder (App * app)
+{
+  GstCaps *caps;
+
+  app->file = g_mapped_file_new (app->file_name, FALSE, NULL);
+  if (!app->file)
+    return FALSE;
+
+  app->file_size = g_mapped_file_get_length (app->file);
+  app->file_data = (guint8 *) g_mapped_file_get_contents (app->file);
+  if (!app->file_data)
+    return FALSE;
+
+  caps = caps_from_codec (app->codec);
+  switch (app->codec) {
+    case GST_VAAPI_CODEC_H264:
+      app->decoder = gst_vaapi_decoder_h264_new (app->display, caps);
+      break;
+    case GST_VAAPI_CODEC_JPEG:
+      app->decoder = gst_vaapi_decoder_jpeg_new (app->display, caps);
+      break;
+    case GST_VAAPI_CODEC_MPEG2:
+      app->decoder = gst_vaapi_decoder_mpeg2_new (app->display, caps);
+      break;
+    case GST_VAAPI_CODEC_MPEG4:
+      app->decoder = gst_vaapi_decoder_mpeg4_new (app->display, caps);
+      break;
+    case GST_VAAPI_CODEC_VC1:
+      app->decoder = gst_vaapi_decoder_vc1_new (app->display, caps);
+      break;
+    default:
+      app->decoder = NULL;
+      break;
+  }
+  if (!app->decoder)
+    return FALSE;
+
+  gst_vaapi_decoder_set_codec_state_changed_func (app->decoder,
+      handle_decoder_state_changes, app);
+
+  g_timer_start (app->timer);
+
+  app->decoder_thread = g_thread_try_new ("Decoder Thread", decoder_thread,
+      app, NULL);
+  if (!app->decoder_thread)
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+stop_decoder (App * app)
+{
+  g_timer_stop (app->timer);
+
+  g_atomic_int_set (&app->decoder_thread_cancel, TRUE);
+  g_thread_join (app->decoder_thread);
+  g_print ("Decoder thread stopped\n");
+  return TRUE;
+}
+
+static void
+ensure_window_size (App * app, GstVaapiSurface * surface)
+{
+  guint width, height;
+
+  if (gst_vaapi_window_get_fullscreen (app->window))
+    return;
+
+  gst_vaapi_surface_get_size (surface, &width, &height);
+  if (app->surface_width == width && app->surface_height == height)
+    return;
+  app->surface_width = width;
+  app->surface_height = height;
+
+  gst_vaapi_window_set_size (app->window, width, height);
+  gst_vaapi_window_get_size (app->window,
+      &app->window_width, &app->window_height);
+}
+
+static inline void
+renderer_wait_until (App * app, GstClockTime pts)
+{
+  g_mutex_lock (&app->mutex);
+  do {
+  } while (g_cond_wait_until (&app->render_ready, &app->mutex, pts));
+  g_mutex_unlock (&app->mutex);
+}
+
+static gboolean
+renderer_process (App * app, RenderFrame * rfp)
+{
+  GError *error = NULL;
+  GstVaapiSurface *surface;
+  const GstVaapiRectangle *crop_rect;
+
+#define SEND_ERROR(...)                                                 \
+    do {                                                                \
+        error = g_error_new(APP_ERROR, APP_ERROR_RENDERER, __VA_ARGS__); \
+        goto send_error;                                                \
+    } while (0)
+
+  surface = gst_vaapi_surface_proxy_get_surface (rfp->proxy);
+  if (!surface)
+    SEND_ERROR ("failed to get decoded surface from render frame");
+
+  ensure_window_size (app, surface);
+
+  crop_rect = gst_vaapi_surface_proxy_get_crop_rect (rfp->proxy);
+
+  if (!gst_vaapi_surface_sync (surface))
+    SEND_ERROR ("failed to sync decoded surface");
+
+  if (G_LIKELY (!g_benchmark))
+    renderer_wait_until (app, rfp->pts);
+
+  if (!gst_vaapi_window_put_surface (app->window, surface,
+          crop_rect, NULL, GST_VAAPI_PICTURE_STRUCTURE_FRAME))
+    SEND_ERROR ("failed to render surface %" GST_VAAPI_ID_FORMAT,
+        GST_VAAPI_ID_ARGS (gst_vaapi_surface_get_id (surface)));
+
+  app->num_frames++;
+
+  render_frame_replace (&app->last_frame, rfp);
+  return TRUE;
+
+#undef SEND_ERROR
+
+send_error:
+  app_send_error (app, error);
+  return FALSE;
+}
+
+static gpointer
+renderer_thread (gpointer data)
+{
+  App *const app = data;
+  RenderFrame *rfp;
+
+  g_print ("Render thread started\n");
+
+  while (!g_atomic_int_get (&app->render_thread_cancel)) {
+    rfp = g_async_queue_timeout_pop (app->decoder_queue, 1000000);
+    if (rfp && !renderer_process (app, rfp))
+      break;
+  }
+  return NULL;
+}
+
+static gboolean
+flush_decoder_queue (App * app)
+{
+  RenderFrame *rfp;
+
+  /* Flush pending surfaces */
+  do {
+    rfp = g_async_queue_try_pop (app->decoder_queue);
+    if (!rfp)
+      return TRUE;
+  } while (renderer_process (app, rfp));
+  return FALSE;
+}
+
+static gboolean
+start_renderer (App * app)
+{
+  app->render_thread = g_thread_try_new ("Renderer Thread", renderer_thread,
+      app, NULL);
+  if (!app->render_thread)
+    return FALSE;
+  return TRUE;
+}
+
+static gboolean
+stop_renderer (App * app)
+{
+  g_atomic_int_set (&app->render_thread_cancel, TRUE);
+  g_thread_join (app->render_thread);
+
+  g_print ("Render thread stopped\n");
+
+  flush_decoder_queue (app);
+  render_frame_replace (&app->last_frame, NULL);
+  return TRUE;
+}
+
+static void
+app_free (App * app)
+{
+  if (!app)
+    return;
+
+  if (app->file) {
+    g_mapped_file_unref (app->file);
+    app->file = NULL;
+  }
+  g_free (app->file_name);
+
+  gst_vaapi_decoder_replace (&app->decoder, NULL);
+  gst_vaapi_window_replace (&app->window, NULL);
+  gst_vaapi_display_replace (&app->display, NULL);
+
+  if (app->decoder_queue) {
+    g_async_queue_unref (app->decoder_queue);
+    app->decoder_queue = NULL;
+  }
+
+  if (app->timer) {
+    g_timer_destroy (app->timer);
+    app->timer = NULL;
+  }
+
+  g_cond_clear (&app->render_ready);
+  g_cond_clear (&app->event_cond);
+  g_mutex_clear (&app->mutex);
+  g_slice_free (App, app);
+}
+
+static App *
+app_new (void)
+{
+  App *app;
+
+  app = g_slice_new0 (App);
+  if (!app)
+    return NULL;
+
+  g_mutex_init (&app->mutex);
+  g_cond_init (&app->event_cond);
+  g_cond_init (&app->render_ready);
+
+  app_set_framerate (app, 60, 1);
+  app->window_width = 640;
+  app->window_height = 480;
+
+  app->decoder_queue = g_async_queue_new_full (
+      (GDestroyNotify) render_frame_free);
+  if (!app->decoder_queue)
+    goto error;
+
+  app->timer = g_timer_new ();
+  if (!app->timer)
+    goto error;
+  return app;
+
+error:
+  app_free (app);
+  return NULL;
+}
+
+static gboolean
+app_check_events (App * app)
+{
+  GError *error = NULL;
+  gboolean stop = FALSE;
+
+  do {
+    g_mutex_lock (&app->mutex);
+    while (app->event == APP_RUNNING)
+      g_cond_wait (&app->event_cond, &app->mutex);
+
+    switch (app->event) {
+      case APP_GOT_ERROR:
+        error = app->error;
+        app->error = NULL;
+        /* fall-through */
+      case APP_GOT_EOS:
+        stop = TRUE;
+        break;
+      default:
+        break;
+    }
+    g_mutex_unlock (&app->mutex);
+  } while (!stop);
+
+  if (!error)
+    return TRUE;
+
+  g_message ("%s error: %s", get_error_string (error->code), error->message);
+  g_error_free (error);
+  return FALSE;
+}
+
+static gboolean
+app_run (App * app, int argc, char *argv[])
+{
+  if (argc < 2) {
+    g_message ("no bitstream file specified");
+    return FALSE;
+  }
+  app->file_name = g_strdup (argv[1]);
+
+  if (!g_file_test (app->file_name, G_FILE_TEST_IS_REGULAR)) {
+    g_message ("failed to find file '%s'", app->file_name);
+    return FALSE;
+  }
+
+  app->codec = identify_codec (app->file_name);
+  if (!app->codec) {
+    app->codec = identify_codec_from_string (g_codec_str);
+    if (!app->codec) {
+      g_message ("failed to identify codec for '%s'", app->file_name);
+      return FALSE;
+    }
+  }
+
+  g_print ("Simple decoder (%s bitstream)\n", string_from_codec (app->codec));
+
+  app->display = video_output_create_display (NULL);
+  if (!app->display) {
+    g_message ("failed to create VA display");
+    return FALSE;
+  }
+
+  app->window = video_output_create_window (app->display,
+      app->window_width, app->window_height);
+  if (!app->window) {
+    g_message ("failed to create window");
+    return FALSE;
+  }
+
+  gst_vaapi_window_show (app->window);
+
+  if (!start_decoder (app)) {
+    g_message ("failed to start decoder thread");
+    return FALSE;
+  }
+
+  if (!start_renderer (app)) {
+    g_message ("failed to start renderer thread");
+    return FALSE;
+  }
+
+  app_check_events (app);
+
+  stop_renderer (app);
+  stop_decoder (app);
+
+  g_print ("Decoded %u frames", app->num_frames);
+  if (g_benchmark) {
+    const gdouble elapsed = g_timer_elapsed (app->timer, NULL);
+    g_print (" in %.2f sec (%.1f fps)\n",
+        elapsed, (gdouble) app->num_frames / elapsed);
+  }
+  g_print ("\n");
+  return TRUE;
+}
+
+int
+main (int argc, char *argv[])
+{
+  App *app;
+  gint ret;
+
+  if (!video_output_init (&argc, argv, g_options))
+    g_error ("failed to initialize video output subsystem");
+
+  app = app_new ();
+  if (!app)
+    g_error ("failed to create application context");
+
+  ret = !app_run (app, argc, argv);
+
+  app_free (app);
+  g_free (g_codec_str);
+  video_output_exit ();
+  return ret;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/simple-encoder.c b/subprojects/gstreamer-vaapi/tests/internal/simple-encoder.c
new file mode 100644 (file)
index 0000000..90b778e
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * simple-encoder.c - Test GstVaapiencoder
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/vaapi/gstvaapiencoder_mpeg2.h>
+#include <gst/vaapi/gstvaapiencoder_h264.h>
+#include <gst/vaapi/gstvaapisurfacepool.h>
+#include <gst/vaapi/gstvaapisurfaceproxy.h>
+
+#include "output.h"
+#include "y4mreader.h"
+
+static guint g_bitrate = 0;
+static gchar *g_codec_str;
+static gchar *g_output_file_name;
+static char **g_input_files = NULL;
+
+#define SURFACE_NUM 16
+
+static GOptionEntry g_options[] = {
+  {"codec", 'c', 0, G_OPTION_ARG_STRING, &g_codec_str,
+      "codec to use for video encoding (h264/mpeg2)", NULL},
+  {"bitrate", 'b', 0, G_OPTION_ARG_INT, &g_bitrate,
+      "desired bitrate expressed in kbps", NULL},
+  {"output", 'o', 0, G_OPTION_ARG_FILENAME, &g_output_file_name,
+      "output file name", NULL},
+  {G_OPTION_REMAINING, ' ', 0, G_OPTION_ARG_FILENAME_ARRAY, &g_input_files,
+      "input file name", NULL},
+  {NULL}
+};
+
+typedef struct
+{
+  GstVaapiDisplay *display;
+  GstVaapiEncoder *encoder;
+  guint read_frames;
+  guint encoded_frames;
+  guint saved_frames;
+  Y4MReader *parser;
+  FILE *output_file;
+  guint input_stopped:1;
+  guint encode_failed:1;
+} App;
+
+static inline gchar *
+generate_output_filename (const gchar * ext)
+{
+  gchar *fn;
+  int i = 0;
+
+  while (1) {
+    fn = g_strdup_printf ("temp%02d.%s", i, ext);
+    if (g_file_test (fn, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+      i++;
+      g_free (fn);
+    } else {
+      break;
+    }
+  }
+
+  return fn;
+}
+
+static gboolean
+parse_options (int *argc, char *argv[])
+{
+  GOptionContext *ctx;
+  gboolean success;
+  GError *error = NULL;
+
+  ctx = g_option_context_new (" - encoder test options");
+  if (!ctx)
+    return FALSE;
+
+  g_option_context_add_group (ctx, gst_init_get_option_group ());
+  g_option_context_add_main_entries (ctx, g_options, NULL);
+  g_option_context_set_help_enabled (ctx, TRUE);
+  success = g_option_context_parse (ctx, argc, &argv, &error);
+  if (!success) {
+    g_printerr ("Option parsing failed: %s\n", error->message);
+    g_error_free (error);
+    goto bail;
+  }
+
+  if (!g_codec_str)
+    g_codec_str = g_strdup ("h264");
+  if (!g_output_file_name)
+    g_output_file_name = generate_output_filename (g_codec_str);
+
+bail:
+  g_option_context_free (ctx);
+  return success;
+}
+
+static void
+print_yuv_info (App * app)
+{
+  g_print ("\n");
+  g_print ("Encode      : %s\n", g_codec_str);
+  g_print ("Resolution  : %dx%d\n", app->parser->width, app->parser->height);
+  g_print ("Source YUV  : %s\n", g_input_files ? g_input_files[0] : "stdin");
+  g_print ("Frame Rate  : %0.1f fps\n",
+      1.0 * app->parser->fps_n / app->parser->fps_d);
+  g_print ("Coded file  : %s\n", g_output_file_name);
+  g_print ("\n");
+}
+
+static void
+print_num_frame (App * app)
+{
+  g_print ("\n");
+  g_print ("read frames    : %d\n", app->read_frames);
+  g_print ("encoded frames : %d\n", app->encoded_frames);
+  g_print ("saved frames   : %d\n", app->saved_frames);
+  g_print ("\n");
+}
+
+static GstVaapiEncoder *
+encoder_new (GstVaapiDisplay * display)
+{
+  GstVaapiEncoder *encoder = NULL;
+
+  if (!g_strcmp0 (g_codec_str, "mpeg2"))
+    encoder = gst_vaapi_encoder_mpeg2_new (display);
+  else if (!g_strcmp0 (g_codec_str, "h264"))
+    encoder = gst_vaapi_encoder_h264_new (display);
+  else
+    return NULL;
+
+  gst_vaapi_encoder_set_bitrate (encoder, g_bitrate);
+
+  return encoder;
+}
+
+static inline GstVideoCodecState *
+new_codec_state (gint width, gint height, gint fps_n, gint fps_d)
+{
+  GstVideoCodecState *state;
+
+  state = g_slice_new0 (GstVideoCodecState);
+  state->ref_count = 1;
+  gst_video_info_set_format (&state->info, GST_VIDEO_FORMAT_ENCODED, width,
+      height);
+
+  state->info.fps_n = fps_n;
+  state->info.fps_d = fps_d;
+
+  return state;
+}
+
+static gboolean
+set_format (GstVaapiEncoder * encoder, gint width, gint height, gint fps_n,
+    gint fps_d)
+{
+  GstVideoCodecState *in_state;
+  GstVaapiEncoderStatus status;
+
+  in_state = new_codec_state (width, height, fps_n, fps_d);
+  status = gst_vaapi_encoder_set_codec_state (encoder, in_state);
+  g_slice_free (GstVideoCodecState, in_state);
+
+  return (status == GST_VAAPI_ENCODER_STATUS_SUCCESS);
+}
+
+static GstBuffer *
+allocate_buffer (GstVaapiCodedBuffer * vbuf)
+{
+  GstBuffer *buf;
+  gssize size;
+
+  size = gst_vaapi_coded_buffer_get_size (vbuf);
+  if (size <= 0) {
+    g_warning ("Invalid VA buffer size (%zd)", size);
+    return NULL;
+  }
+
+  buf = gst_buffer_new_and_alloc (size);
+  if (!buf) {
+    g_warning ("Failed to create output buffer of size %zd", size);
+    return NULL;
+  }
+
+  if (!gst_vaapi_coded_buffer_copy_into (buf, vbuf)) {
+    g_warning ("Failed to copy VA buffer data");
+    gst_buffer_unref (buf);
+    return NULL;
+  }
+
+  return buf;
+}
+
+static GstVaapiEncoderStatus
+get_encoder_buffer (GstVaapiEncoder * encoder, GstBuffer ** buffer)
+{
+  GstVaapiCodedBufferProxy *proxy = NULL;
+  GstVaapiEncoderStatus status;
+
+  status = gst_vaapi_encoder_get_buffer_with_timeout (encoder, &proxy, 50000);
+  if (status < GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+    g_warning ("Failed to get a buffer from encoder: %d", status);
+    return status;
+  } else if (status > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+    return status;
+  }
+
+  *buffer = allocate_buffer (GST_VAAPI_CODED_BUFFER_PROXY_BUFFER (proxy));
+  gst_vaapi_coded_buffer_proxy_unref (proxy);
+
+  return status;
+}
+
+static gboolean
+outputs_to_file (GstBuffer * buffer, FILE * file)
+{
+  GstMapInfo info;
+  size_t written;
+  gboolean ret = FALSE;
+
+  if (!gst_buffer_map (buffer, &info, GST_MAP_READ))
+    return FALSE;
+
+  if (info.size <= 0 || !info.data)
+    return FALSE;
+
+  written = fwrite (info.data, 1, info.size, file);
+  if (written < info.size) {
+    g_warning ("write file error.");
+    goto bail;
+  }
+
+  ret = TRUE;
+
+bail:
+  gst_buffer_unmap (buffer, &info);
+  return ret;
+}
+
+static gpointer
+get_buffer_thread (gpointer data)
+{
+  App *app = data;
+
+  GstVaapiEncoderStatus ret;
+  GstBuffer *obuf;
+
+  while (1) {
+    obuf = NULL;
+    ret = get_encoder_buffer (app->encoder, &obuf);
+    if (app->input_stopped && ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) {
+      break;                    /* finished */
+    } else if (ret > GST_VAAPI_ENCODER_STATUS_SUCCESS) {        /* another chance */
+      continue;
+    }
+    if (ret < GST_VAAPI_ENCODER_STATUS_SUCCESS) {       /* fatal error */
+      app->encode_failed = TRUE;
+      break;
+    }
+
+    app->encoded_frames++;
+    g_debug ("encoded frame %d, buffer = %p", app->encoded_frames, obuf);
+
+    if (app->output_file && outputs_to_file (obuf, app->output_file))
+      app->saved_frames++;
+
+    gst_buffer_unref (obuf);
+  }
+
+  if (obuf)
+    gst_buffer_replace (&obuf, NULL);
+
+  return NULL;
+}
+
+static void
+app_free (App * app)
+{
+  g_return_if_fail (app);
+
+  if (app->parser)
+    y4m_reader_close (app->parser);
+
+  if (app->encoder) {
+    gst_vaapi_encoder_flush (app->encoder);
+    gst_object_unref (app->encoder);
+  }
+
+  if (app->display)
+    gst_object_unref (app->display);
+
+  if (app->output_file)
+    fclose (app->output_file);
+
+  g_slice_free (App, app);
+}
+
+static App *
+app_new (const gchar * input_fn, const gchar * output_fn)
+{
+  App *app = g_slice_new0 (App);
+  if (!app)
+    return NULL;
+
+  app->parser = y4m_reader_open (input_fn);
+  if (!app->parser) {
+    g_warning ("Could not parse input stream.");
+    goto error;
+  }
+
+  app->output_file = fopen (output_fn, "w");
+  if (app->output_file == NULL) {
+    g_warning ("Could not open file \"%s\" for writing: %s.", output_fn,
+        g_strerror (errno));
+    goto error;
+  }
+
+  app->display = video_output_create_display (NULL);
+  if (!app->display) {
+    g_warning ("Could not create VA display.");
+    goto error;
+  }
+
+  app->encoder = encoder_new (app->display);
+  if (!app->encoder) {
+    g_warning ("Could not create encoder.");
+    goto error;
+  }
+
+  if (!set_format (app->encoder, app->parser->width, app->parser->height,
+          app->parser->fps_n, app->parser->fps_d)) {
+    g_warning ("Could not set format.");
+    goto error;
+  }
+
+  return app;
+
+error:
+  app_free (app);
+  return NULL;
+}
+
+static gboolean
+upload_frame (GstVaapiEncoder * encoder, GstVaapiSurfaceProxy * proxy)
+{
+  GstVideoCodecFrame *frame;
+  GstVaapiEncoderStatus ret;
+
+  frame = g_slice_new0 (GstVideoCodecFrame);
+  gst_video_codec_frame_set_user_data (frame,
+      gst_vaapi_surface_proxy_ref (proxy),
+      (GDestroyNotify) gst_vaapi_surface_proxy_unref);
+
+  ret = gst_vaapi_encoder_put_frame (encoder, frame);
+  return (ret == GST_VAAPI_ENCODER_STATUS_SUCCESS);
+}
+
+static gboolean
+load_frame (App * app, GstVaapiImage * image)
+{
+  gboolean ret = FALSE;
+
+  if (!gst_vaapi_image_map (image))
+    return FALSE;
+
+  ret = y4m_reader_load_image (app->parser, image);
+
+  if (!gst_vaapi_image_unmap (image))
+    return FALSE;
+
+  return ret;
+}
+
+static int
+app_run (App * app)
+{
+  GstVaapiImage *image;
+  GstVaapiVideoPool *pool;
+  GThread *buffer_thread;
+  gsize id;
+  int ret = EXIT_FAILURE;
+
+  image = gst_vaapi_image_new (app->display, GST_VIDEO_FORMAT_I420,
+      app->parser->width, app->parser->height);
+
+  {
+    GstVideoInfo vi;
+    gst_video_info_set_format (&vi, GST_VIDEO_FORMAT_ENCODED,
+        app->parser->width, app->parser->height);
+    pool = gst_vaapi_surface_pool_new_full (app->display, &vi, 0);
+  }
+
+  buffer_thread = g_thread_new ("get buffer thread", get_buffer_thread, app);
+
+  while (1) {
+    GstVaapiSurfaceProxy *proxy;
+    GstVaapiSurface *surface;
+
+    if (!load_frame (app, image))
+      break;
+
+    if (!gst_vaapi_image_unmap (image))
+      break;
+
+    proxy =
+        gst_vaapi_surface_proxy_new_from_pool (GST_VAAPI_SURFACE_POOL (pool));
+    if (!proxy) {
+      g_warning ("Could not get surface proxy from pool.");
+      break;
+    }
+    surface = gst_vaapi_surface_proxy_get_surface (proxy);
+    if (!surface) {
+      g_warning ("Could not get surface from proxy.");
+      break;
+    }
+
+    if (!gst_vaapi_surface_put_image (surface, image)) {
+      g_warning ("Could not update surface");
+      break;
+    }
+
+    if (!upload_frame (app->encoder, proxy)) {
+      g_warning ("put frame failed");
+      break;
+    }
+
+    app->read_frames++;
+    id = gst_vaapi_surface_get_id (surface);
+    g_debug ("input frame %d, surface id = %" G_GSIZE_FORMAT, app->read_frames,
+        id);
+
+    gst_vaapi_surface_proxy_unref (proxy);
+  }
+
+  app->input_stopped = TRUE;
+
+  g_thread_join (buffer_thread);
+
+  if (!app->encode_failed && feof (app->parser->fp))
+    ret = EXIT_SUCCESS;
+
+  gst_vaapi_video_pool_replace (&pool, NULL);
+  gst_vaapi_image_unref (image);
+  return ret;
+}
+
+int
+main (int argc, char *argv[])
+{
+  App *app;
+  int ret = EXIT_FAILURE;
+  gchar *input_fn;
+
+  if (!parse_options (&argc, argv))
+    return EXIT_FAILURE;
+
+  /* @TODO: iterate all the input files */
+  input_fn = g_input_files ? g_input_files[0] : NULL;
+  if (input_fn && !g_file_test (input_fn,
+          G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) {
+    g_warning ("input file \"%s\" doesn't exist", input_fn);
+    goto bail;
+  }
+
+  app = app_new (input_fn, g_output_file_name);
+  if (!app)
+    goto bail;
+
+  print_yuv_info (app);
+  ret = app_run (app);
+  print_num_frame (app);
+
+  app_free (app);
+
+bail:
+  g_free (g_codec_str);
+  g_free (g_output_file_name);
+  g_strfreev (g_input_files);
+
+  gst_deinit ();
+
+  return ret;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-decode.c b/subprojects/gstreamer-vaapi/tests/internal/test-decode.c
new file mode 100644 (file)
index 0000000..3940e71
--- /dev/null
@@ -0,0 +1,115 @@
+/*
+ *  test-decode.c - Test GstVaapiDecoder
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2011-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/vaapi/gstvaapisurface.h>
+#include "decoder.h"
+#include "output.h"
+
+/* Set to 1 to check display cache works (shared VA display) */
+#define CHECK_DISPLAY_CACHE 1
+
+static inline void
+pause (void)
+{
+  g_print ("Press any key to continue...\n");
+  getchar ();
+}
+
+static gchar *g_codec_str;
+
+static GOptionEntry g_options[] = {
+  {"codec", 'c',
+        0,
+        G_OPTION_ARG_STRING, &g_codec_str,
+      "codec to test", NULL},
+  {NULL,}
+};
+
+int
+main (int argc, char *argv[])
+{
+  GstVaapiDisplay *display, *display2;
+  GstVaapiWindow *window;
+  GstVaapiDecoder *decoder;
+  GstVaapiSurfaceProxy *proxy;
+  GstVaapiSurface *surface;
+  const GstVaapiRectangle *crop_rect;
+
+  static const guint win_width = 640;
+  static const guint win_height = 480;
+
+  if (!video_output_init (&argc, argv, g_options))
+    g_error ("failed to initialize video output subsystem");
+
+  g_print ("Test decode\n");
+
+  display = video_output_create_display (NULL);
+  if (!display)
+    g_error ("could not create VA display");
+
+  if (CHECK_DISPLAY_CACHE)
+    display2 = video_output_create_display (NULL);
+  else
+    display2 = gst_object_ref (display);
+  if (!display2)
+    g_error ("could not create second VA display");
+
+  window = video_output_create_window (display, win_width, win_height);
+  if (!window)
+    g_error ("could not create window");
+
+  decoder = decoder_new (display, g_codec_str);
+  if (!decoder)
+    g_error ("could not create decoder");
+
+  g_print ("Decode %s sample frame\n", decoder_get_codec_name (decoder));
+
+  if (!decoder_put_buffers (decoder))
+    g_error ("could not fill decoder with sample data");
+
+  proxy = decoder_get_surface (decoder);
+  if (!proxy)
+    g_error ("could not get decoded surface");
+
+  surface = gst_vaapi_surface_proxy_get_surface (proxy);
+  crop_rect = gst_vaapi_surface_proxy_get_crop_rect (proxy);
+
+  gst_vaapi_window_show (window);
+
+  if (!gst_vaapi_window_put_surface (window, surface, crop_rect, NULL,
+          GST_VAAPI_PICTURE_STRUCTURE_FRAME))
+    g_error ("could not render surface");
+
+  pause ();
+
+  gst_vaapi_surface_proxy_unref (proxy);
+  gst_object_unref (decoder);
+  gst_object_unref (window);
+  gst_object_unref (display);
+  gst_object_unref (display2);
+  g_free (g_codec_str);
+  video_output_exit ();
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-decode.h b/subprojects/gstreamer-vaapi/tests/internal/test-decode.h
new file mode 100644 (file)
index 0000000..fbe46a6
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  test-decode.h - Test GstVaapiDecoder
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_DECODE_H
+#define TEST_DECODE_H
+
+#include <gst/vaapi/gstvaapidisplay.h>
+#include <gst/vaapi/gstvaapiprofile.h>
+
+typedef struct _VideoDecodeInfo VideoDecodeInfo;
+struct _VideoDecodeInfo {
+    GstVaapiProfile     profile;
+    guint               width;
+    guint               height;
+    const guchar       *data;
+    guint               data_size;
+};
+
+#endif /* TEST_DECODE_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-display.c b/subprojects/gstreamer-vaapi/tests/internal/test-display.c
new file mode 100644 (file)
index 0000000..aa3d867
--- /dev/null
@@ -0,0 +1,426 @@
+/*
+ *  test-display.c - Test GstVaapiDisplayX11
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#define _GNU_SOURCE
+#include "gst/vaapi/sysdeps.h"
+#include <gst/video/video.h>
+#if GST_VAAPI_USE_DRM
+# include <gst/vaapi/gstvaapidisplay_drm.h>
+# include <va/va_drm.h>
+# include <fcntl.h>
+# include <unistd.h>
+# ifndef DRM_DEVICE_PATH
+# define DRM_DEVICE_PATH "/dev/dri/card0"
+# endif
+#endif
+#if GST_VAAPI_USE_X11
+# include <gst/vaapi/gstvaapidisplay_x11.h>
+#endif
+#if GST_VAAPI_USE_GLX
+# include <gst/vaapi/gstvaapidisplay_glx.h>
+#endif
+#if GST_VAAPI_USE_WAYLAND
+# include <gst/vaapi/gstvaapidisplay_wayland.h>
+#endif
+#if GST_VAAPI_USE_EGL
+# include <gst/vaapi/gstvaapidisplay_egl.h>
+#endif
+
+#ifdef HAVE_VA_VA_GLX_H
+# include <va/va_glx.h>
+#endif
+
+static void
+print_value (const GValue * value, const gchar * name)
+{
+  gchar *value_string;
+
+  value_string = g_strdup_value_contents (value);
+  if (!value_string)
+    return;
+  g_print ("  %s: %s\n", name, value_string);
+  g_free (value_string);
+}
+
+static void
+print_profiles (GArray * profiles, const gchar * name)
+{
+  GstVaapiCodec codec;
+  const gchar *codec_name, *profile_name;
+  guint i;
+
+  g_print ("%u %s caps\n", profiles->len, name);
+
+  for (i = 0; i < profiles->len; i++) {
+    const GstVaapiProfile profile =
+        g_array_index (profiles, GstVaapiProfile, i);
+
+    codec = gst_vaapi_profile_get_codec (profile);
+    if (!codec)
+      continue;
+
+    codec_name = gst_vaapi_codec_get_name (codec);
+    if (!codec_name)
+      continue;
+
+    profile_name = gst_vaapi_profile_get_va_name (profile);
+    if (!profile_name)
+      continue;
+
+    g_print ("  %s: %s profile\n", codec_name, profile_name);
+  }
+}
+
+static void
+print_format_yuv (const VAImageFormat * va_format)
+{
+  const guint32 fourcc = va_format->fourcc;
+
+  g_print (" fourcc '%c%c%c%c'",
+      fourcc & 0xff,
+      (fourcc >> 8) & 0xff, (fourcc >> 16) & 0xff, (fourcc >> 24) & 0xff);
+}
+
+static void
+print_format_rgb (const VAImageFormat * va_format)
+{
+  g_print (" %d bits per pixel, %s endian,",
+      va_format->bits_per_pixel,
+      va_format->byte_order == VA_MSB_FIRST ? "big" : "little");
+  g_print (" %s masks", va_format->alpha_mask ? "rgba" : "rgb");
+  g_print (" 0x%08x 0x%08x 0x%08x",
+      va_format->red_mask, va_format->green_mask, va_format->blue_mask);
+  if (va_format->alpha_mask)
+    g_print (" 0x%08x", va_format->alpha_mask);
+}
+
+static void
+print_formats (GArray * formats, const gchar * name)
+{
+  guint i;
+
+  g_print ("%u %s caps\n", formats->len, name);
+
+  for (i = 0; i < formats->len; i++) {
+    const GstVideoFormat format = g_array_index (formats, GstVideoFormat, i);
+    const VAImageFormat *va_format;
+
+    g_print ("  %s:", gst_vaapi_video_format_to_string (format));
+
+    va_format = gst_vaapi_video_format_to_va_format (format);
+    if (!va_format)
+      g_error ("could not determine VA format");
+
+    if (gst_vaapi_video_format_is_yuv (format))
+      print_format_yuv (va_format);
+    else
+      print_format_rgb (va_format);
+    g_print ("\n");
+  }
+}
+
+static void
+dump_properties (GstVaapiDisplay * display)
+{
+  GParamSpec **properties;
+  guint i, n_properties;
+
+  properties =
+      g_object_class_list_properties (G_OBJECT_GET_CLASS (display),
+      &n_properties);
+
+  for (i = 0; i < n_properties; i++) {
+    const gchar *const name = g_param_spec_get_nick (properties[i]);
+    GValue value = G_VALUE_INIT;
+
+    if (!gst_vaapi_display_has_property (display, name))
+      continue;
+
+    g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (properties[i]));
+    g_object_get_property (G_OBJECT (display), name, &value);
+    print_value (&value, name);
+  }
+
+  g_free (properties);
+}
+
+static void
+dump_info (GstVaapiDisplay * display)
+{
+  GArray *profiles, *formats;
+
+  profiles = gst_vaapi_display_get_decode_profiles (display);
+  if (!profiles)
+    g_error ("could not get VA decode profiles");
+
+  print_profiles (profiles, "decoders");
+  g_array_unref (profiles);
+
+  profiles = gst_vaapi_display_get_encode_profiles (display);
+  if (!profiles)
+    g_error ("could not get VA encode profiles");
+
+  print_profiles (profiles, "encoders");
+  g_array_unref (profiles);
+
+  formats = gst_vaapi_display_get_image_formats (display);
+  if (!formats)
+    g_error ("could not get VA image formats");
+
+  print_formats (formats, "image");
+  g_array_unref (formats);
+
+  formats = gst_vaapi_display_get_subpicture_formats (display);
+  if (!formats)
+    g_error ("could not get VA subpicture formats");
+
+  print_formats (formats, "subpicture");
+  g_array_unref (formats);
+
+  dump_properties (display);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstVaapiDisplay *display;
+#if GST_VAAPI_USE_GLX || GST_VAAPI_USE_WAYLAND
+  guint width, height;
+  guint par_n, par_d;
+#endif
+
+  gst_init (&argc, &argv);
+
+#if GST_VAAPI_USE_DRM
+  g_print ("#\n");
+  g_print ("# Create display with gst_vaapi_display_drm_new()\n");
+  g_print ("#\n");
+  {
+    display = gst_vaapi_display_drm_new (NULL);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+
+    dump_info (display);
+    gst_object_unref (display);
+  }
+  g_print ("\n");
+
+  g_print ("#\n");
+  g_print ("# Create display with gst_vaapi_display_drm_new_with_device()\n");
+  g_print ("#\n");
+  {
+    int drm_device;
+
+    drm_device = open (DRM_DEVICE_PATH, O_RDWR | O_CLOEXEC);
+    if (drm_device < 0)
+      g_error ("could not open DRM device");
+
+    display = gst_vaapi_display_drm_new_with_device (drm_device);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+
+    dump_info (display);
+    gst_object_unref (display);
+    close (drm_device);
+  }
+  g_print ("\n");
+
+  g_print ("#\n");
+  g_print
+      ("# Create display with gst_vaapi_display_new_with_display() [vaGetDisplayDRM()]\n");
+  g_print ("#\n");
+  {
+    int drm_device;
+    VADisplay va_display;
+
+    drm_device = open (DRM_DEVICE_PATH, O_RDWR | O_CLOEXEC);
+    if (drm_device < 0)
+      g_error ("could not open DRM device");
+
+    va_display = vaGetDisplayDRM (drm_device);
+    if (!va_display)
+      g_error ("could not create VA display");
+
+    display = gst_vaapi_display_new_with_display (va_display);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+
+    dump_info (display);
+    gst_object_unref (display);
+    close (drm_device);
+  }
+  g_print ("\n");
+#endif
+
+#if GST_VAAPI_USE_X11
+  g_print ("#\n");
+  g_print ("# Create display with gst_vaapi_display_x11_new()\n");
+  g_print ("#\n");
+  {
+    display = gst_vaapi_display_x11_new (NULL);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+  }
+  g_print ("\n");
+
+  g_print ("#\n");
+  g_print ("# Create display with gst_vaapi_display_x11_new_with_display()\n");
+  g_print ("#\n");
+  {
+    Display *x11_display;
+
+    x11_display = XOpenDisplay (NULL);
+    if (!x11_display)
+      g_error ("could not create X11 display");
+
+    display = gst_vaapi_display_x11_new_with_display (x11_display);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+
+    dump_info (display);
+    gst_object_unref (display);
+    XCloseDisplay (x11_display);
+  }
+  g_print ("\n");
+
+  g_print ("#\n");
+  g_print
+      ("# Create display with gst_vaapi_display_new_with_display() [vaGetDisplay()]\n");
+  g_print ("#\n");
+  {
+    Display *x11_display;
+    VADisplay va_display;
+
+    x11_display = XOpenDisplay (NULL);
+    if (!x11_display)
+      g_error ("could not create X11 display");
+
+    va_display = vaGetDisplay (x11_display);
+    if (!va_display)
+      g_error ("could not create VA display");
+
+    display = gst_vaapi_display_new_with_display (va_display);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+
+    dump_info (display);
+    gst_object_unref (display);
+    XCloseDisplay (x11_display);
+  }
+  g_print ("\n");
+#endif
+
+#if GST_VAAPI_USE_GLX
+  g_print ("#\n");
+  g_print ("# Create display with gst_vaapi_display_glx_new()\n");
+  g_print ("#\n");
+  {
+    display = gst_vaapi_display_glx_new (NULL);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+
+    gst_vaapi_display_get_size (display, &width, &height);
+    g_print ("Display size: %ux%u\n", width, height);
+
+    gst_vaapi_display_get_pixel_aspect_ratio (display, &par_n, &par_d);
+    g_print ("Pixel aspect ratio: %u/%u\n", par_n, par_d);
+
+    dump_info (display);
+    gst_object_unref (display);
+  }
+  g_print ("\n");
+
+  g_print ("#\n");
+  g_print ("# Create display with gst_vaapi_display_glx_new_with_display()\n");
+  g_print ("#\n");
+  {
+    Display *x11_display;
+
+    x11_display = XOpenDisplay (NULL);
+    if (!x11_display)
+      g_error ("could not create X11 display");
+
+    display = gst_vaapi_display_glx_new_with_display (x11_display);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+
+    dump_info (display);
+    gst_object_unref (display);
+    XCloseDisplay (x11_display);
+  }
+  g_print ("\n");
+
+#ifdef HAVE_VA_VA_GLX_H
+  g_print ("#\n");
+  g_print
+      ("# Create display with gst_vaapi_display_new_with_display() [vaGetDisplayGLX()]\n");
+  g_print ("#\n");
+  {
+    Display *x11_display;
+    VADisplay va_display;
+
+    x11_display = XOpenDisplay (NULL);
+    if (!x11_display)
+      g_error ("could not create X11 display");
+
+    va_display = vaGetDisplayGLX (x11_display);
+    if (!va_display)
+      g_error ("could not create VA display");
+
+    display = gst_vaapi_display_new_with_display (va_display);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+
+    dump_info (display);
+    gst_object_unref (display);
+    XCloseDisplay (x11_display);
+  }
+  g_print ("\n");
+#endif
+#endif
+
+#if GST_VAAPI_USE_WAYLAND
+  g_print ("#\n");
+  g_print ("# Create display with gst_vaapi_display_wayland_new()\n");
+  g_print ("#\n");
+  {
+    display = gst_vaapi_display_wayland_new (NULL);
+    if (!display)
+      g_error ("could not create Gst/VA display");
+
+    gst_vaapi_display_get_size (display, &width, &height);
+    g_print ("Display size: %ux%u\n", width, height);
+
+    gst_vaapi_display_get_pixel_aspect_ratio (display, &par_n, &par_d);
+    g_print ("Pixel aspect ratio: %u/%u\n", par_n, par_d);
+
+    dump_info (display);
+    gst_object_unref (display);
+  }
+  g_print ("\n");
+#endif
+
+  gst_deinit ();
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-filter.c b/subprojects/gstreamer-vaapi/tests/internal/test-filter.c
new file mode 100644 (file)
index 0000000..dbe47c1
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ *  test-filter.c - Test GstVaapiFilter
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Halley Zhao <halley.zhao@intel.com>
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <errno.h>
+#include <gst/vaapi/gstvaapifilter.h>
+#include <gst/vaapi/gstvaapiwindow.h>
+#include "image.h"
+#include "output.h"
+
+static gchar *g_src_format_str;
+static gchar *g_crop_rect_str;
+static gchar *g_denoise_str;
+static gchar *g_sharpen_str;
+static gchar *g_deinterlace_str;
+static gchar *g_deinterlace_flags_str;
+
+static GOptionEntry g_options[] = {
+  {"src-format", 's',
+        0,
+        G_OPTION_ARG_STRING, &g_src_format_str,
+      "source surface format", NULL},
+  {"crop-rect", 'c',
+        0,
+        G_OPTION_ARG_STRING, &g_crop_rect_str,
+      "cropping rectangle", NULL},
+  {"denoise", 0,
+        0,
+        G_OPTION_ARG_STRING, &g_denoise_str,
+      "set noise reduction level", NULL},
+  {"sharpen", 0,
+        0,
+        G_OPTION_ARG_STRING, &g_sharpen_str,
+      "set sharpening level", NULL},
+  {"deinterlace", 0,
+        0,
+        G_OPTION_ARG_STRING, &g_deinterlace_str,
+      "enable deinterlacing", NULL},
+  {"deinterlace-flags", 0,
+        0,
+        G_OPTION_ARG_STRING, &g_deinterlace_flags_str,
+      "deinterlacing flags", NULL},
+  {NULL,}
+};
+
+#define APP_ERROR app_error_quark()
+static GQuark
+app_error_quark (void)
+{
+  static gsize g_quark;
+
+  if (g_once_init_enter (&g_quark)) {
+    gsize quark = (gsize) g_quark_from_static_string ("AppError");
+    g_once_init_leave (&g_quark, quark);
+  }
+  return g_quark;
+}
+
+typedef enum
+{
+  APP_ERROR_NONE,
+  APP_ERROR_CREATE_TEST_SURFACE,
+} AppError;
+
+static inline void
+pause (void)
+{
+  g_print ("Press any key to continue...\n");
+  getchar ();
+}
+
+static GstVaapiSurface *
+create_test_surface (GstVaapiDisplay * display, guint width, guint height,
+    guint flags, GError ** error_ptr)
+{
+  GstVideoFormat format = GST_VIDEO_FORMAT_I420;
+  GstVaapiSurface *surface = NULL;
+  GstVaapiImage *image = NULL;
+  GError *error = NULL;
+
+  if (g_src_format_str) {
+    format = gst_video_format_from_string (g_src_format_str);
+    if (format == GST_VIDEO_FORMAT_UNKNOWN)
+      goto error_invalid_format;
+  }
+
+  surface =
+      gst_vaapi_surface_new_with_format (display, format, width, height, 0);
+  if (!surface)
+    goto error_create_surface;
+
+  image = image_generate_full (display, format, width, height, flags);
+  if (!image)
+    goto error_create_image;
+
+  if (!image_upload (image, surface))
+    goto error_upload_image;
+
+  gst_vaapi_image_unref (image);
+  return surface;
+
+  /* ERRORS */
+error_invalid_format:
+  error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
+      "unknown format %s", g_src_format_str);
+  goto error_cleanup;
+error_create_surface:
+  error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
+      "unsupported format %s", gst_vaapi_video_format_to_string (format));
+  goto error_cleanup;
+error_create_image:
+  error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
+      "unsupported %s image", gst_vaapi_video_format_to_string (format));
+  goto error_cleanup;
+error_upload_image:
+  error = g_error_new (APP_ERROR, APP_ERROR_CREATE_TEST_SURFACE,
+      "failed to upload %s image", gst_vaapi_video_format_to_string (format));
+  goto error_cleanup;
+error_cleanup:
+  if (image)
+    gst_vaapi_image_unref (image);
+  if (surface)
+    gst_vaapi_surface_unref (surface);
+  if (error_ptr)
+    *error_ptr = error;
+  else
+    g_error_free (error);
+  return NULL;
+}
+
+static void
+dump_operation (GstVaapiFilterOpInfo * op_info)
+{
+  GParamSpec *pspec;
+  GValue value = G_VALUE_INIT;
+  gchar *value_str;
+
+  if (!op_info)
+    return;
+
+  pspec = op_info->pspec;
+  g_print ("  %s: ", g_param_spec_get_name (pspec));
+  g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+  g_param_value_set_default (pspec, &value);
+  value_str = g_strdup_value_contents (&value);
+  g_print ("%s (default: %s)\n", G_VALUE_TYPE_NAME (&value),
+      value_str ? value_str : "<unknown>");
+  g_free (value_str);
+}
+
+static void
+dump_operations (GstVaapiFilter * filter)
+{
+  GPtrArray *const ops = gst_vaapi_filter_get_operations (filter);
+  guint i;
+
+  if (!ops)
+    return;
+
+  g_print ("%u operations\n", ops->len);
+  for (i = 0; i < ops->len; i++)
+    dump_operation (g_ptr_array_index (ops, i));
+  g_ptr_array_unref (ops);
+}
+
+static void
+dump_formats (GstVaapiFilter * filter)
+{
+  GArray *const formats = gst_vaapi_filter_get_formats (filter,
+      NULL, NULL, NULL, NULL);
+  guint i;
+
+  if (!formats)
+    return;
+
+  g_print ("%u formats\n", formats->len);
+  for (i = 0; i < formats->len; i++) {
+    GstVideoFormat format = g_array_index (formats, GstVideoFormat, i);
+    g_print ("  %s\n", gst_vaapi_video_format_to_string (format));
+  }
+  g_array_unref (formats);
+}
+
+static gboolean
+parse_double (const gchar * str, gdouble * out_value_ptr)
+{
+  gchar *endptr = NULL;
+  gdouble out_value;
+
+  g_return_val_if_fail (out_value_ptr != NULL, FALSE);
+
+  errno = 0;
+  out_value = g_ascii_strtod (str, &endptr);
+  if (!endptr || *endptr != '\0' || errno == ERANGE)
+    return FALSE;
+
+  *out_value_ptr = out_value;
+  return TRUE;
+}
+
+static gboolean
+parse_crop_rect (const gchar * str, GstVaapiRectangle * crop_rect)
+{
+  if (str) {
+    // Format: <WIDTH> 'x' <HEIGHT>
+    if (sscanf (str, "%ux%u", &crop_rect->width, &crop_rect->height) == 2) {
+      crop_rect->x = 0;
+      crop_rect->y = 0;
+      return TRUE;
+    }
+    // Format: '('? <X> ',' <Y> ')'? <WIDTH> 'x' <HEIGHT>
+    if (sscanf (str, "(%d,%d):%ux%u", &crop_rect->x, &crop_rect->y,
+            &crop_rect->width, &crop_rect->height) == 4 ||
+        sscanf (str, "%d,%d:%ux%u", &crop_rect->x, &crop_rect->y,
+            &crop_rect->width, &crop_rect->height) == 4)
+      return TRUE;
+  }
+  return FALSE;
+}
+
+static gboolean
+parse_enum (const gchar * str, GType type, gint default_value,
+    gint * out_value_ptr)
+{
+  gint out_value = default_value;
+
+  g_return_val_if_fail (out_value_ptr != NULL, FALSE);
+
+  if (str) {
+    const GEnumValue *enum_value;
+    GEnumClass *const enum_class = g_type_class_ref (type);
+
+    if (!enum_class)
+      return FALSE;
+
+    enum_value = g_enum_get_value_by_nick (enum_class, str);
+    if (enum_value)
+      out_value = enum_value->value;
+    g_type_class_unref (enum_class);
+
+    if (!enum_value)
+      return FALSE;
+  }
+  *out_value_ptr = out_value;
+  return TRUE;
+}
+
+static gboolean
+parse_flags (const gchar * str, GType type, guint * out_value_ptr)
+{
+  gchar **tokens = NULL;
+  gint i, value, out_value = 0;
+  gboolean success = FALSE;
+
+  g_return_val_if_fail (out_value_ptr != NULL, FALSE);
+
+  if (str) {
+    tokens = g_strsplit (str, ",", 32);
+    if (!tokens)
+      return FALSE;
+
+    for (i = 0; tokens[i] != NULL; i++) {
+      if (!parse_enum (tokens[i], type, 0, &value))
+        goto end;
+      out_value |= value;
+    }
+  }
+  *out_value_ptr = out_value;
+  success = TRUE;
+
+end:
+  g_strfreev (tokens);
+  return success;
+}
+
+static inline gboolean
+parse_deinterlace (const gchar * str,
+    GstVaapiDeinterlaceMethod * deinterlace_ptr)
+{
+  g_return_val_if_fail (deinterlace_ptr != NULL, FALSE);
+
+  if (!str) {
+    *deinterlace_ptr = GST_VAAPI_DEINTERLACE_METHOD_NONE;
+    return TRUE;
+  }
+  return parse_enum (str, GST_VAAPI_TYPE_DEINTERLACE_METHOD,
+      GST_VAAPI_DEINTERLACE_METHOD_NONE, (gint *) deinterlace_ptr);
+}
+
+static inline gboolean
+parse_deinterlace_flags (const gchar * str, guint * deinterlace_flags_ptr)
+{
+  return parse_flags (str, GST_VAAPI_TYPE_DEINTERLACE_FLAGS,
+      deinterlace_flags_ptr);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstVaapiDisplay *display;
+  GstVaapiWindow *window;
+  GstVaapiSurface *src_surface, *dst_surface;
+  GstVaapiFilter *filter = NULL;
+  GstVaapiFilterStatus status;
+  GstVaapiDeinterlaceMethod deinterlace_method;
+  guint deinterlace_flags = 0;
+  guint filter_flags = 0;
+  guint surface_flags = 0;
+  gdouble denoise_level, sharpen_level;
+  GError *error = NULL;
+
+  static const guint src_width = 320;
+  static const guint src_height = 240;
+  static const guint dst_width = 480;
+  static const guint dst_height = 360;
+  static const guint win_width = 640;
+  static const guint win_height = 480;
+
+  if (!video_output_init (&argc, argv, g_options))
+    g_error ("failed to initialize video output subsystem");
+
+  if (g_denoise_str && !parse_double (g_denoise_str, &denoise_level))
+    g_error ("failed to parse noise reduction level");
+
+  if (g_sharpen_str && !parse_double (g_sharpen_str, &sharpen_level))
+    g_error ("failed to parse sharpening level");
+
+  if (!parse_deinterlace (g_deinterlace_str, &deinterlace_method))
+    g_error ("failed to parse deinterlace method `%s'", g_deinterlace_str);
+
+  if (!parse_deinterlace_flags (g_deinterlace_flags_str, &deinterlace_flags))
+    g_error ("failed to parse deinterlace flags `%s'", g_deinterlace_flags_str);
+
+  display = video_output_create_display (NULL);
+  if (!display)
+    g_error ("failed to create VA display");
+
+  window = video_output_create_window (display, win_width, win_height);
+  if (!window)
+    g_error ("failed to create window");
+
+  filter = gst_vaapi_filter_new (display);
+  if (!filter)
+    g_error ("failed to create video processing pipeline");
+
+  dump_operations (filter);
+  dump_formats (filter);
+
+  if (g_crop_rect_str) {
+    GstVaapiRectangle crop_rect;
+
+    if (!parse_crop_rect (g_crop_rect_str, &crop_rect))
+      g_error ("failed to parse cropping rectangle");
+
+    printf ("Frame cropping: (%d,%d), size %ux%u\n",
+        crop_rect.x, crop_rect.y, crop_rect.width, crop_rect.height);
+
+    if (!gst_vaapi_filter_set_cropping_rectangle (filter, &crop_rect))
+      g_error ("failed to set cropping rectangle");
+  }
+
+  if (g_denoise_str) {
+    printf ("Noise reduction level: %f\n", denoise_level);
+
+    if (!gst_vaapi_filter_set_denoising_level (filter, denoise_level))
+      g_error ("failed to set denoising level");
+  }
+
+  if (g_sharpen_str) {
+    printf ("Sharpening level: %f\n", sharpen_level);
+
+    if (!gst_vaapi_filter_set_sharpening_level (filter, sharpen_level))
+      g_error ("failed to set sharpening level");
+  }
+
+  if (deinterlace_method != GST_VAAPI_DEINTERLACE_METHOD_NONE) {
+    printf ("Enable deinterlacing: %s\n", g_deinterlace_str);
+
+    if (!gst_vaapi_filter_set_deinterlacing (filter, deinterlace_method,
+            deinterlace_flags))
+      g_error ("failed to set deinterlacing method");
+  } else if (deinterlace_flags) {
+    if (deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD)
+      filter_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
+    else
+      filter_flags = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
+  }
+
+  if (deinterlace_method != GST_VAAPI_DEINTERLACE_METHOD_NONE ||
+      deinterlace_flags) {
+    if (!(deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_ONEFIELD))
+      surface_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD |
+          GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
+    else if (deinterlace_flags & GST_VAAPI_DEINTERLACE_FLAG_TOPFIELD)
+      surface_flags = GST_VAAPI_PICTURE_STRUCTURE_TOP_FIELD;
+    else
+      surface_flags = GST_VAAPI_PICTURE_STRUCTURE_BOTTOM_FIELD;
+  }
+
+  src_surface = create_test_surface (display, src_width, src_height,
+      surface_flags, &error);
+  if (!src_surface)
+    g_error ("failed to create source VA surface: %s", error->message);
+
+  dst_surface = gst_vaapi_surface_new (display, GST_VAAPI_CHROMA_TYPE_YUV420,
+      dst_width, dst_height);
+  if (!dst_surface)
+    g_error ("failed to create target VA surface");
+
+  status = gst_vaapi_filter_process (filter, src_surface, dst_surface,
+      filter_flags);
+  if (status != GST_VAAPI_FILTER_STATUS_SUCCESS)
+    g_error ("failed to process video filters");
+
+  gst_vaapi_window_show (window);
+
+  if (!gst_vaapi_window_put_surface (window, dst_surface, NULL, NULL,
+          GST_VAAPI_PICTURE_STRUCTURE_FRAME))
+    g_error ("failed to render target surface");
+
+  pause ();
+
+  gst_object_unref (filter);
+  gst_vaapi_surface_unref (dst_surface);
+  gst_vaapi_surface_unref (src_surface);
+  gst_object_unref (window);
+  gst_object_unref (display);
+  video_output_exit ();
+  g_free (g_src_format_str);
+  g_free (g_crop_rect_str);
+  g_free (g_denoise_str);
+  g_free (g_sharpen_str);
+  g_free (g_deinterlace_str);
+  g_free (g_deinterlace_flags_str);
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-h264.c b/subprojects/gstreamer-vaapi/tests/internal/test-h264.c
new file mode 100644 (file)
index 0000000..d94dc42
--- /dev/null
@@ -0,0 +1,1051 @@
+/*
+ *  test-h264.c - H.264 test data
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "test-h264.h"
+
+#define H264_CLIP_WIDTH           320
+#define H264_CLIP_HEIGHT          240
+#define H264_CLIP_DATA_SIZE     12111
+
+/* Data dump of a 320x240 H.264 video clip (h264.mp4), it has a single frame */
+static const guchar h264_clip[H264_CLIP_DATA_SIZE] = {
+  0x00, 0x00, 0x01, 0x67, 0x4d, 0x40, 0x0d, 0xab, 0x40, 0xa0, 0xfd, 0x80,
+  0x88, 0x00, 0x00, 0x03, 0x00, 0x08, 0x00, 0x00, 0x03, 0x00, 0xc4, 0x78,
+  0xa1, 0x55, 0x00, 0x00, 0x01, 0x68, 0xee, 0x32, 0xc8, 0x00, 0x00, 0x01,
+  0x65, 0x88, 0x82, 0x00, 0x45, 0xbb, 0x9d, 0x38, 0x9b, 0xe8, 0x48, 0xef,
+  0xed, 0xa7, 0xd7, 0x9c, 0x19, 0x9b, 0x5a, 0xca, 0x00, 0x0d, 0x54, 0x0c,
+  0xe3, 0xd5, 0xad, 0xa9, 0x5d, 0x71, 0x24, 0x83, 0xbb, 0x36, 0x4d, 0xb1,
+  0xf5, 0x0f, 0xc6, 0x66, 0xb6, 0x6d, 0x1d, 0xa5, 0x45, 0xfc, 0xa0, 0x4c,
+  0xbf, 0xfb, 0x2f, 0x5c, 0x1a, 0x5a, 0x3b, 0x29, 0xe0, 0x35, 0x95, 0x44,
+  0x8e, 0x2f, 0x22, 0xd3, 0x3a, 0x48, 0x88, 0x7d, 0x32, 0x97, 0xff, 0xd8,
+  0x54, 0x7f, 0x7f, 0x65, 0x57, 0x71, 0xaf, 0xba, 0x17, 0xe0, 0x12, 0x24,
+  0xc9, 0x5b, 0xaa, 0xc7, 0xd5, 0x27, 0xc9, 0x64, 0x5d, 0x5e, 0xa0, 0xea,
+  0x57, 0xd2, 0x7d, 0x55, 0x6c, 0xf2, 0x44, 0x2f, 0x4b, 0x5d, 0xbd, 0x62,
+  0xb9, 0xc2, 0xfa, 0x1e, 0x8f, 0xbc, 0x57, 0x5f, 0xc1, 0x2d, 0xb3, 0x9a,
+  0x0e, 0x58, 0x75, 0xf7, 0x08, 0xdf, 0x2d, 0xda, 0xc1, 0xa5, 0x55, 0x76,
+  0x06, 0xaf, 0x92, 0x28, 0x43, 0xc5, 0x20, 0x16, 0x96, 0xf5, 0x79, 0x1e,
+  0x88, 0x77, 0xb3, 0x4e, 0xb8, 0x4f, 0x3e, 0x51, 0x3c, 0xcf, 0xc0, 0x28,
+  0xda, 0xb8, 0xa3, 0x1d, 0xed, 0x8e, 0x04, 0x74, 0x82, 0xc1, 0x5d, 0xa8,
+  0x3c, 0x25, 0xd2, 0x84, 0x0b, 0x34, 0x40, 0x8b, 0x7f, 0xee, 0xae, 0xf8,
+  0xde, 0x6e, 0x28, 0xf6, 0xfc, 0xfc, 0x14, 0x7e, 0x95, 0xd9, 0xd8, 0x2c,
+  0x09, 0x49, 0x27, 0x64, 0x13, 0x83, 0x5c, 0x6f, 0xd4, 0x09, 0x48, 0xa8,
+  0xd4, 0x1b, 0x6e, 0x4d, 0x05, 0x0a, 0xbe, 0x27, 0xff, 0xf4, 0x27, 0x04,
+  0x41, 0xa0, 0x23, 0x61, 0xe6, 0x26, 0x32, 0xf4, 0xa3, 0xca, 0x97, 0xfc,
+  0xeb, 0x6b, 0x45, 0x35, 0x13, 0x69, 0xd9, 0x41, 0x0f, 0xa6, 0xc0, 0xbe,
+  0xd5, 0xfa, 0x28, 0xa6, 0x4f, 0x62, 0x3e, 0x1f, 0xcb, 0x98, 0x0a, 0x70,
+  0x09, 0xc1, 0xe3, 0x69, 0x30, 0x20, 0xe7, 0xd5, 0x1c, 0xf0, 0x7e, 0x52,
+  0x1d, 0x6a, 0xdd, 0x14, 0x58, 0x5e, 0x7a, 0x35, 0x57, 0xa1, 0xe6, 0x83,
+  0x46, 0x57, 0x6e, 0x57, 0x7f, 0x72, 0x5d, 0x0c, 0x0c, 0xf4, 0x40, 0x11,
+  0x8c, 0xbb, 0xdf, 0xd1, 0x54, 0xfb, 0x7d, 0xf7, 0x03, 0xb9, 0x4e, 0xa3,
+  0x76, 0x4c, 0xce, 0xfb, 0x9e, 0x39, 0x02, 0xf0, 0x48, 0xb5, 0x8c, 0x36,
+  0x6e, 0x93, 0x79, 0x48, 0xcc, 0x28, 0xec, 0xd7, 0xb8, 0x02, 0xe5, 0xa3,
+  0x37, 0x01, 0xe1, 0x3c, 0x40, 0x8f, 0x68, 0x27, 0xbc, 0xec, 0x6b, 0x59,
+  0xb9, 0xfe, 0xb8, 0x67, 0x68, 0x83, 0x99, 0x97, 0x1e, 0xcc, 0x4e, 0x23,
+  0x82, 0x26, 0x93, 0x7b, 0x7a, 0x9e, 0xdc, 0x42, 0xca, 0x1b, 0x3e, 0x13,
+  0x19, 0x45, 0x03, 0x40, 0xab, 0xd2, 0xda, 0x6b, 0x6c, 0x26, 0xdb, 0xe3,
+  0x72, 0x06, 0x89, 0xea, 0x03, 0x95, 0xe3, 0x14, 0xe1, 0x4a, 0x16, 0x58,
+  0x2d, 0x67, 0xaa, 0xbf, 0xbe, 0x37, 0x54, 0x19, 0xb1, 0x57, 0x61, 0x85,
+  0x82, 0x5f, 0x63, 0x33, 0xe2, 0xf8, 0x7f, 0x4f, 0x21, 0x44, 0x8a, 0x0e,
+  0x21, 0x2b, 0x12, 0x99, 0x4d, 0xd9, 0x2e, 0xea, 0x36, 0x2d, 0x45, 0xcb,
+  0xe2, 0xfe, 0xdd, 0x03, 0x3b, 0x08, 0x58, 0x60, 0x1e, 0xb2, 0xfa, 0x3b,
+  0x89, 0xa5, 0x03, 0xde, 0xab, 0x71, 0x32, 0x48, 0x46, 0x2c, 0xfb, 0x2b,
+  0x84, 0x83, 0xc9, 0xff, 0xf6, 0xf5, 0x2f, 0xe7, 0x2f, 0x6a, 0x5d, 0x86,
+  0xe2, 0x48, 0x23, 0x6d, 0x84, 0x60, 0x9b, 0xc0, 0x25, 0x1e, 0xff, 0x94,
+  0xe8, 0xf4, 0xd0, 0x4e, 0x11, 0x60, 0xda, 0x20, 0xa8, 0xfd, 0xf3, 0x00,
+  0x4f, 0x0e, 0x4f, 0xa2, 0xeb, 0xe1, 0xa8, 0xb3, 0x47, 0x35, 0x62, 0x83,
+  0x6f, 0x08, 0x6b, 0xb8, 0x82, 0x04, 0xcc, 0x63, 0x69, 0xd7, 0xba, 0x10,
+  0xd4, 0x51, 0xe6, 0xb5, 0x34, 0xe8, 0x7d, 0xaf, 0x87, 0xcf, 0x1d, 0xeb,
+  0x46, 0xc1, 0xcd, 0xcb, 0xf2, 0x3b, 0x3e, 0xa0, 0x61, 0xc7, 0x68, 0x86,
+  0x0b, 0x9f, 0x0b, 0x59, 0xc0, 0x79, 0x4e, 0xcc, 0x79, 0x91, 0xa0, 0xe8,
+  0x80, 0x6c, 0xbd, 0x35, 0x12, 0x71, 0x2f, 0x5e, 0xa4, 0xfc, 0xe6, 0x51,
+  0xe0, 0xbe, 0x41, 0x1a, 0x19, 0x60, 0xd8, 0xac, 0xcd, 0x93, 0x05, 0x70,
+  0xa0, 0xda, 0x53, 0x4e, 0x5a, 0x6d, 0x9b, 0x3f, 0x28, 0x73, 0x87, 0x6f,
+  0x6d, 0x41, 0x5a, 0x13, 0xd0, 0xea, 0x19, 0xb3, 0xb7, 0xf1, 0x75, 0x92,
+  0xae, 0x43, 0x9d, 0xe3, 0xa7, 0x4d, 0x5a, 0x52, 0x36, 0xce, 0x6b, 0x1e,
+  0x2b, 0x2e, 0xab, 0x0c, 0xd7, 0xe4, 0x1c, 0x44, 0x72, 0x9d, 0x86, 0xb6,
+  0xeb, 0xe5, 0x80, 0xc4, 0x45, 0x21, 0x8b, 0xe0, 0xe0, 0x9d, 0x09, 0xfa,
+  0x0b, 0x59, 0x0c, 0x2c, 0x9d, 0x97, 0x15, 0x56, 0xd0, 0x21, 0xd8, 0x90,
+  0xb4, 0x89, 0xc4, 0x96, 0x76, 0xf1, 0x64, 0xa5, 0x85, 0x2a, 0x13, 0xfb,
+  0xfa, 0x11, 0x1e, 0x2d, 0x63, 0xc2, 0x9a, 0x87, 0x99, 0x2c, 0x18, 0xb8,
+  0xeb, 0x6a, 0x5c, 0x68, 0x26, 0x63, 0xcc, 0x1b, 0x1a, 0x5c, 0x7f, 0x0d,
+  0x45, 0xcc, 0x56, 0x46, 0x92, 0xbb, 0x76, 0xf2, 0x2e, 0x52, 0x05, 0x3c,
+  0xe3, 0xbb, 0x59, 0x9b, 0x89, 0x03, 0x0d, 0x48, 0xb1, 0xdc, 0x78, 0x04,
+  0x03, 0x24, 0xf4, 0x62, 0xcf, 0xb1, 0xc6, 0x64, 0x05, 0xbd, 0x89, 0x94,
+  0x1a, 0x8d, 0xc1, 0xbe, 0xac, 0xe0, 0xed, 0x89, 0xf3, 0x47, 0x81, 0x82,
+  0xb9, 0x64, 0xcc, 0x8e, 0xc4, 0x1e, 0xa9, 0xf6, 0xde, 0x8d, 0xb7, 0x33,
+  0xba, 0x5b, 0x49, 0x0d, 0x0a, 0x16, 0x96, 0x7d, 0x89, 0x82, 0xe0, 0x5a,
+  0x08, 0x55, 0xbd, 0xce, 0xca, 0xc0, 0x46, 0x1a, 0x6b, 0xf9, 0x7d, 0x03,
+  0xe8, 0x35, 0x69, 0x7d, 0x87, 0xc9, 0x71, 0x01, 0x7e, 0xa8, 0x3a, 0x9c,
+  0xd5, 0xe2, 0x71, 0xa6, 0xc7, 0xe2, 0x2d, 0xf3, 0x6f, 0x74, 0x0f, 0x3e,
+  0x03, 0x70, 0x5e, 0xec, 0x8c, 0x66, 0xf9, 0x71, 0x9a, 0xd2, 0x56, 0x57,
+  0x37, 0xcd, 0x50, 0x55, 0x97, 0xea, 0x67, 0x20, 0x59, 0x06, 0x4d, 0x22,
+  0xa0, 0x85, 0x90, 0xb3, 0x59, 0x15, 0x75, 0x0d, 0x70, 0xbd, 0xb5, 0x7d,
+  0x72, 0xaa, 0xea, 0xfc, 0x9d, 0x08, 0x8d, 0xdf, 0x31, 0x21, 0x2d, 0xef,
+  0x00, 0x24, 0x6c, 0xae, 0x82, 0x6e, 0x1a, 0x4b, 0x28, 0xa5, 0x6d, 0x98,
+  0xeb, 0x50, 0x87, 0x6f, 0x1b, 0xa5, 0xba, 0x1c, 0xda, 0x59, 0xb8, 0x4c,
+  0x17, 0xe3, 0xd5, 0x10, 0x46, 0x94, 0x91, 0xed, 0x0b, 0xd3, 0xfc, 0x06,
+  0x81, 0x60, 0x88, 0x5f, 0x58, 0x81, 0x26, 0x54, 0xdc, 0xd5, 0x7c, 0xbe,
+  0x30, 0x04, 0x17, 0x84, 0x76, 0xe8, 0xb6, 0x8a, 0xec, 0x84, 0x02, 0xcf,
+  0xc7, 0xda, 0x2d, 0x2e, 0x31, 0xc2, 0x77, 0x31, 0x54, 0x32, 0xbd, 0x77,
+  0xa2, 0xa5, 0x5d, 0xec, 0x1c, 0x27, 0xf6, 0xec, 0xc8, 0x3f, 0xeb, 0x1a,
+  0x24, 0xcb, 0x74, 0xd0, 0xb3, 0x52, 0xa8, 0x8f, 0x4c, 0x26, 0xbf, 0x68,
+  0xb2, 0x87, 0xf3, 0xa8, 0xa9, 0x4f, 0x71, 0x57, 0xc7, 0xa8, 0x34, 0x5a,
+  0x01, 0x68, 0xae, 0x5c, 0xb3, 0xd8, 0x23, 0x6b, 0xea, 0x18, 0xdf, 0xa9,
+  0xe5, 0xc4, 0x11, 0x49, 0x2b, 0xfa, 0xa8, 0xf3, 0x8f, 0x80, 0x47, 0xa0,
+  0x19, 0xc7, 0x20, 0xef, 0xbf, 0xed, 0xe1, 0x38, 0x8b, 0x16, 0x54, 0x36,
+  0x60, 0x8b, 0x04, 0x26, 0x9c, 0x6b, 0x1a, 0x95, 0x4c, 0x94, 0x6a, 0x53,
+  0xcf, 0xb4, 0x4b, 0x38, 0x3a, 0x15, 0x26, 0x94, 0x10, 0x1c, 0x35, 0xe4,
+  0x57, 0x80, 0x19, 0xad, 0x1f, 0x82, 0xe8, 0x47, 0xe4, 0x90, 0xa2, 0x42,
+  0x30, 0x43, 0x15, 0x92, 0x2b, 0x39, 0xfb, 0x7b, 0xb3, 0xdb, 0xc7, 0x5b,
+  0x79, 0x5e, 0x91, 0xba, 0x38, 0x74, 0xd6, 0x00, 0x26, 0xa5, 0x8f, 0xa4,
+  0x31, 0xe6, 0x7b, 0xeb, 0x52, 0xc2, 0xe2, 0xa1, 0x6b, 0x5f, 0x17, 0xf1,
+  0x15, 0xc9, 0x4b, 0x44, 0x93, 0x77, 0x28, 0xdf, 0x2a, 0xc0, 0xb5, 0x97,
+  0xfc, 0xbe, 0x2e, 0x72, 0x53, 0x58, 0xf9, 0x33, 0x3a, 0xb0, 0x6e, 0xaf,
+  0x0c, 0x1b, 0xcf, 0x71, 0x37, 0x6b, 0x4a, 0x9a, 0x66, 0x16, 0x90, 0x43,
+  0x9b, 0x70, 0x0d, 0x8f, 0xd3, 0x04, 0x4b, 0x14, 0xf2, 0x58, 0x9f, 0x64,
+  0x33, 0x21, 0xdc, 0x02, 0x8a, 0x5b, 0xd6, 0x80, 0x9c, 0x22, 0xc8, 0x39,
+  0x7d, 0x2d, 0x7c, 0x09, 0x4e, 0x6a, 0x8c, 0x8d, 0x0c, 0xc4, 0xfe, 0x6f,
+  0x8c, 0x50, 0xf2, 0x75, 0xc0, 0x12, 0x6f, 0xd3, 0x9d, 0x07, 0xc0, 0xe9,
+  0xdf, 0x36, 0xa2, 0x6f, 0xca, 0x14, 0x5b, 0x0f, 0x5a, 0xd8, 0x35, 0x72,
+  0x07, 0x08, 0x80, 0xba, 0x2f, 0x61, 0x7f, 0xb0, 0x5e, 0xbb, 0xb1, 0x47,
+  0x6a, 0xbd, 0x6a, 0xe4, 0xb6, 0xa2, 0xec, 0x2e, 0x27, 0x43, 0xbc, 0xd7,
+  0x2c, 0x2c, 0xf3, 0x6c, 0x12, 0x4c, 0x86, 0x5a, 0x38, 0xa4, 0x87, 0xa8,
+  0xe1, 0x70, 0x17, 0x15, 0xd0, 0x2b, 0x87, 0xdb, 0x87, 0xc0, 0x85, 0x57,
+  0x30, 0x31, 0x16, 0x07, 0x9b, 0x72, 0x07, 0xf5, 0x18, 0x6d, 0xd1, 0x8d,
+  0x31, 0xa1, 0x25, 0x6a, 0xb4, 0xf3, 0x07, 0x5f, 0x0c, 0x99, 0x33, 0x68,
+  0xbf, 0x2c, 0xa1, 0xfd, 0xde, 0x16, 0x2d, 0x4a, 0x5a, 0xa0, 0x7e, 0xe5,
+  0x9b, 0x89, 0x4a, 0x8d, 0xe7, 0x18, 0x21, 0x32, 0x47, 0x3c, 0x9d, 0x48,
+  0xab, 0x7d, 0xca, 0xb4, 0x63, 0xd9, 0xfd, 0x29, 0x2d, 0x4c, 0xf1, 0xf2,
+  0x20, 0x0a, 0x91, 0x2e, 0x2c, 0xa1, 0x49, 0x83, 0x73, 0x15, 0xa0, 0x7d,
+  0x6e, 0xae, 0x51, 0x45, 0x0d, 0x09, 0x1f, 0x8f, 0x61, 0x42, 0xbd, 0x24,
+  0xcd, 0x3e, 0xe8, 0x66, 0x84, 0xc6, 0x97, 0x08, 0x7b, 0x72, 0x73, 0x7e,
+  0xe7, 0x99, 0x05, 0xab, 0x63, 0xff, 0x3c, 0x44, 0xa1, 0xc0, 0x1b, 0xfc,
+  0xff, 0x27, 0xe9, 0x45, 0x82, 0x75, 0x82, 0x6f, 0x9c, 0x65, 0xef, 0x67,
+  0xd6, 0x00, 0xd1, 0x9f, 0x61, 0x9f, 0x38, 0xdd, 0x7f, 0x5f, 0x4d, 0x67,
+  0x5b, 0x5d, 0xff, 0x98, 0x6b, 0x13, 0xe0, 0xe7, 0x69, 0xcb, 0x7f, 0x7c,
+  0x11, 0x91, 0xe0, 0x05, 0xb9, 0x64, 0xd0, 0xb7, 0x91, 0xe5, 0xd4, 0x3a,
+  0x47, 0x05, 0x25, 0x4f, 0x15, 0x46, 0xaf, 0x41, 0x9e, 0xc7, 0x49, 0x15,
+  0x17, 0xd1, 0x9c, 0x28, 0xef, 0x80, 0xa3, 0x8b, 0x60, 0xcc, 0x60, 0xeb,
+  0x96, 0x36, 0x3a, 0x23, 0x94, 0xf3, 0x6c, 0xe5, 0x3f, 0xe8, 0x8b, 0x5c,
+  0x8c, 0xfe, 0x6f, 0x91, 0x65, 0x19, 0xa1, 0x4d, 0x45, 0x7b, 0x06, 0x0f,
+  0x71, 0xb7, 0x9a, 0x8d, 0x8e, 0x82, 0x7b, 0x68, 0x44, 0xa4, 0xa6, 0xc3,
+  0xe5, 0x67, 0x9f, 0x6c, 0xd0, 0xe4, 0xe8, 0x37, 0x08, 0x6b, 0xbb, 0xa0,
+  0x3a, 0xd0, 0xa9, 0xd9, 0x04, 0xaa, 0x91, 0xac, 0x71, 0xff, 0xec, 0x7e,
+  0xaf, 0xa9, 0x99, 0xa2, 0x8d, 0x91, 0x95, 0xb3, 0xd8, 0xe4, 0xf3, 0x3f,
+  0xa6, 0x4b, 0x0c, 0x19, 0x23, 0xf7, 0xa7, 0xcd, 0x4c, 0x41, 0x28, 0x63,
+  0x9f, 0x0b, 0x8f, 0x70, 0x70, 0xbd, 0x25, 0x16, 0x8e, 0x86, 0x8a, 0x69,
+  0xe3, 0x6a, 0xd4, 0x98, 0x42, 0x56, 0x15, 0x2d, 0x3d, 0xdb, 0x17, 0x1b,
+  0x23, 0x58, 0x82, 0x56, 0x11, 0x97, 0x85, 0xf2, 0x68, 0x95, 0x92, 0xd5,
+  0x9e, 0x91, 0x05, 0x70, 0xc8, 0x96, 0xb2, 0x73, 0x6d, 0x1e, 0x12, 0x8c,
+  0xa0, 0xe4, 0x1a, 0x84, 0x5b, 0xb4, 0x32, 0xf7, 0x9e, 0x08, 0xd0, 0x6c,
+  0x42, 0xf0, 0x0b, 0xc4, 0x1f, 0xe0, 0xbb, 0x71, 0xe1, 0x2d, 0x86, 0xd7,
+  0x77, 0x24, 0x43, 0x53, 0x0c, 0x88, 0x21, 0x75, 0x95, 0xd0, 0xfe, 0x10,
+  0x23, 0xcd, 0xba, 0x77, 0x3d, 0x9b, 0x0f, 0xb2, 0xe2, 0xcc, 0x0f, 0x94,
+  0xe0, 0x66, 0x90, 0x0e, 0xf7, 0x6a, 0x3c, 0x9f, 0xc0, 0xf6, 0x98, 0x1c,
+  0x4c, 0x9f, 0x25, 0xc4, 0xeb, 0x1d, 0x91, 0x32, 0x29, 0x34, 0x2a, 0xb0,
+  0x7e, 0x1c, 0x09, 0x77, 0x13, 0x83, 0xfa, 0xcf, 0x24, 0xa2, 0x5f, 0x79,
+  0x78, 0x64, 0xf7, 0x45, 0x81, 0xbe, 0x6a, 0x82, 0x26, 0xfd, 0xe7, 0xc3,
+  0x61, 0x41, 0x27, 0xcc, 0x99, 0x69, 0x77, 0xc8, 0xa7, 0xf3, 0x52, 0x01,
+  0xa7, 0x8c, 0x0b, 0x7d, 0x86, 0x8d, 0xbb, 0x31, 0xd6, 0x67, 0xf9, 0xa7,
+  0x8f, 0x76, 0xb6, 0x74, 0x26, 0x43, 0x35, 0xb8, 0x83, 0x7c, 0x16, 0x34,
+  0x88, 0x0c, 0xb6, 0xec, 0xf0, 0x01, 0x8c, 0x1c, 0xe5, 0x52, 0xd4, 0xca,
+  0x01, 0x2e, 0xb5, 0x87, 0xc1, 0xc1, 0x1b, 0xa3, 0x02, 0x17, 0x13, 0xd3,
+  0x35, 0xe8, 0x80, 0xe1, 0xd1, 0x01, 0x9c, 0x0a, 0x62, 0x7d, 0x98, 0x7c,
+  0x68, 0xa4, 0x8e, 0x3a, 0x50, 0x4b, 0x95, 0x59, 0xa3, 0x11, 0xf6, 0xa3,
+  0xde, 0x92, 0x65, 0x00, 0xa0, 0xe8, 0x32, 0xf0, 0xc3, 0x77, 0x68, 0x0b,
+  0xed, 0xc1, 0x69, 0xd2, 0x6e, 0xce, 0x80, 0xe4, 0x56, 0x9b, 0x15, 0xbf,
+  0x3c, 0x4a, 0x38, 0x26, 0xf6, 0x6a, 0xdb, 0x62, 0x7a, 0xab, 0xb1, 0x77,
+  0x75, 0x0d, 0xa7, 0xa4, 0xcf, 0x5e, 0x2d, 0xea, 0x24, 0x84, 0xbd, 0x83,
+  0x8e, 0xaa, 0x91, 0xe1, 0x72, 0x5f, 0x7f, 0x26, 0x54, 0x4f, 0xab, 0xa6,
+  0x50, 0x22, 0x68, 0x8c, 0xa6, 0x06, 0x67, 0x3c, 0x3e, 0x93, 0x9a, 0xc2,
+  0x53, 0x15, 0x08, 0x1a, 0x3c, 0xb3, 0x3f, 0xf0, 0x83, 0xf5, 0x0d, 0x9c,
+  0xe3, 0x76, 0x11, 0x45, 0x21, 0x6b, 0x65, 0x97, 0xea, 0x3c, 0xdb, 0x0d,
+  0xcd, 0x6e, 0xb7, 0x26, 0x7b, 0x82, 0x63, 0x35, 0x7e, 0x76, 0xf4, 0xb8,
+  0x0e, 0xe5, 0x1d, 0x95, 0x94, 0x1c, 0x60, 0xc7, 0xea, 0x9c, 0x1c, 0x73,
+  0x75, 0x0e, 0x9b, 0x5f, 0x78, 0x09, 0x4f, 0x90, 0x31, 0x5c, 0xc8, 0x5b,
+  0x78, 0xce, 0xb3, 0x3e, 0x31, 0x61, 0x90, 0xba, 0xe0, 0xe1, 0x57, 0x1d,
+  0x71, 0x80, 0x92, 0x6b, 0x75, 0xe1, 0x34, 0x95, 0xeb, 0x88, 0xe4, 0x0b,
+  0x72, 0xdc, 0x34, 0x24, 0x3b, 0x6d, 0x94, 0xc9, 0xe9, 0x8d, 0x38, 0x72,
+  0x9c, 0x61, 0x6e, 0x07, 0xd7, 0x35, 0xa1, 0x74, 0xc2, 0x0c, 0x36, 0xc3,
+  0x54, 0xd3, 0xe5, 0xd1, 0x08, 0x8e, 0x24, 0x77, 0xf5, 0x61, 0xcf, 0x69,
+  0x9b, 0x27, 0x70, 0xe7, 0x52, 0xf6, 0xef, 0x66, 0x8f, 0x0e, 0x8b, 0xc0,
+  0xf3, 0x64, 0x2a, 0xa8, 0xff, 0xcc, 0xd9, 0x61, 0x53, 0xac, 0x36, 0x23,
+  0x4f, 0x3c, 0x0f, 0xe0, 0xec, 0xad, 0xc5, 0x35, 0x3f, 0x3b, 0x74, 0x26,
+  0x84, 0x48, 0xd1, 0xfe, 0x72, 0x01, 0xea, 0x4d, 0x03, 0x46, 0x66, 0x5a,
+  0xc4, 0x0a, 0x55, 0x43, 0x61, 0x36, 0x6a, 0xc1, 0xd2, 0x74, 0x0a, 0x8f,
+  0x01, 0xb2, 0xc2, 0xaa, 0xd7, 0x2d, 0x0a, 0x0f, 0x67, 0xa1, 0x25, 0x7d,
+  0x45, 0x60, 0x0f, 0x06, 0xfb, 0x8f, 0x8b, 0xe0, 0x4a, 0x8c, 0xd7, 0x19,
+  0xac, 0xcc, 0x47, 0xa2, 0x7c, 0x30, 0x90, 0x94, 0x81, 0xab, 0xde, 0x38,
+  0xb8, 0xc9, 0xdb, 0x63, 0x9c, 0xcb, 0xdd, 0x71, 0xde, 0x4f, 0x1e, 0x43,
+  0x08, 0xe4, 0xe3, 0x83, 0x86, 0x0f, 0x34, 0xb7, 0x1e, 0x53, 0xc1, 0xde,
+  0x46, 0xf1, 0x70, 0xf5, 0xd8, 0x47, 0xd2, 0x9b, 0x44, 0x88, 0x85, 0x8e,
+  0x32, 0xa9, 0x0c, 0x09, 0x2f, 0xd0, 0xe4, 0x4b, 0x30, 0x3a, 0x2e, 0x65,
+  0x0c, 0xff, 0xb4, 0x0d, 0xa8, 0x8f, 0x61, 0x3e, 0x7e, 0x90, 0x66, 0xbb,
+  0xf6, 0xbe, 0xfd, 0x7d, 0xe4, 0xdc, 0x2c, 0x59, 0x87, 0x81, 0x60, 0x96,
+  0xd7, 0x1d, 0x10, 0x02, 0x35, 0xdd, 0x16, 0x4c, 0xe9, 0x2d, 0x52, 0x45,
+  0xdd, 0x3f, 0xc9, 0xff, 0x8d, 0x19, 0xad, 0x02, 0x74, 0xf1, 0x09, 0x99,
+  0x94, 0x66, 0x2e, 0x8b, 0xa3, 0xdc, 0x3d, 0xf3, 0xf5, 0x85, 0xf2, 0x60,
+  0x7d, 0x9d, 0xe0, 0xd3, 0x0f, 0xa4, 0x92, 0xf3, 0x55, 0xbc, 0x7b, 0x20,
+  0x6b, 0xf6, 0xc4, 0xc4, 0x0f, 0x8a, 0xd7, 0x5a, 0x02, 0xb0, 0xb7, 0x78,
+  0xb4, 0x9e, 0xb6, 0x93, 0x95, 0x2e, 0x76, 0x06, 0x1e, 0x34, 0x5d, 0x34,
+  0x77, 0x77, 0x6d, 0x32, 0xbb, 0x46, 0xad, 0x43, 0xd7, 0x72, 0x61, 0x33,
+  0x4f, 0x98, 0xe9, 0x56, 0x3a, 0x96, 0x89, 0x6e, 0x1f, 0xaf, 0x6b, 0xa0,
+  0x9a, 0xe4, 0x42, 0x5a, 0xb3, 0xb8, 0x2a, 0xe1, 0x2d, 0xa6, 0x32, 0xa2,
+  0x01, 0xf5, 0x3a, 0x9a, 0xbb, 0x06, 0x76, 0x0b, 0xa8, 0xac, 0x02, 0x96,
+  0x0c, 0x58, 0xd3, 0x64, 0xc8, 0xe2, 0xae, 0x6c, 0xf7, 0xa7, 0x32, 0x4b,
+  0x51, 0x50, 0x11, 0x90, 0xcf, 0x37, 0xed, 0xd2, 0xa0, 0xa4, 0x97, 0xb3,
+  0x45, 0x1d, 0x7d, 0xf3, 0xff, 0xde, 0x9f, 0x80, 0xa9, 0x61, 0xac, 0x37,
+  0x7f, 0x5d, 0xc9, 0xf6, 0xdc, 0x26, 0xd0, 0x65, 0xf2, 0xdc, 0x0c, 0x1a,
+  0xcb, 0xde, 0x6b, 0x77, 0xf3, 0x08, 0xa4, 0x93, 0xab, 0x2a, 0xdf, 0x18,
+  0x1a, 0xc7, 0xa6, 0xa1, 0x7e, 0x43, 0x75, 0xca, 0x88, 0xcc, 0x6f, 0xa2,
+  0x85, 0x0e, 0xb0, 0xd5, 0xcd, 0x8a, 0xff, 0xc1, 0x57, 0x20, 0x66, 0xf7,
+  0x19, 0x7a, 0x52, 0x5b, 0x46, 0x87, 0x5f, 0xf7, 0x77, 0xe2, 0xab, 0x4e,
+  0x4a, 0xce, 0x8f, 0x3f, 0xe6, 0x9f, 0x88, 0x3a, 0x33, 0x65, 0x3c, 0x3a,
+  0x41, 0xc3, 0x8e, 0xee, 0x79, 0xe7, 0x2c, 0xb0, 0x3b, 0x93, 0x82, 0xa0,
+  0x1a, 0x71, 0x0e, 0xf6, 0x31, 0xc5, 0x6f, 0xc1, 0xa8, 0x32, 0x89, 0x3b,
+  0x33, 0x68, 0x53, 0x81, 0x15, 0x70, 0x5e, 0x22, 0xdc, 0x99, 0xc6, 0x88,
+  0xf8, 0x11, 0x06, 0x56, 0x1f, 0x80, 0x7e, 0x0b, 0x27, 0x90, 0xfc, 0x97,
+  0x76, 0x61, 0xdc, 0x30, 0x5d, 0x34, 0x4e, 0x83, 0x85, 0xce, 0xe2, 0x91,
+  0x4d, 0x8d, 0x92, 0x88, 0x26, 0xa0, 0xde, 0x47, 0x82, 0xd2, 0xa8, 0xa5,
+  0xe7, 0x27, 0x0c, 0x45, 0x41, 0x85, 0xa1, 0x12, 0xcb, 0x3a, 0x74, 0x53,
+  0x93, 0x77, 0xd0, 0x8b, 0x42, 0x8d, 0x00, 0xca, 0x44, 0x67, 0xa0, 0x6a,
+  0xbd, 0xcd, 0x4a, 0x3c, 0xfe, 0x6c, 0xa1, 0x48, 0x26, 0x0d, 0x51, 0x54,
+  0x59, 0xc9, 0xf9, 0x51, 0x5c, 0xd3, 0x55, 0xf0, 0x72, 0x77, 0xdb, 0x52,
+  0xee, 0x0a, 0x5e, 0x8a, 0xf0, 0xbe, 0x9a, 0x37, 0xa0, 0x1b, 0x94, 0xe3,
+  0x2d, 0x17, 0xc4, 0xbe, 0x9c, 0xad, 0x9c, 0xd1, 0xc6, 0xbc, 0x36, 0x5c,
+  0x3b, 0xe3, 0x2e, 0x66, 0x29, 0x0c, 0x3a, 0x3d, 0xe7, 0xe3, 0xf3, 0x58,
+  0x70, 0x3e, 0x59, 0xb2, 0x6c, 0x91, 0x14, 0xfe, 0x9e, 0x5e, 0x5d, 0xb2,
+  0x7b, 0x46, 0x66, 0x46, 0x55, 0xe2, 0x78, 0x47, 0xeb, 0xdf, 0x2b, 0xb4,
+  0xf2, 0xb2, 0x14, 0xbe, 0x64, 0x9e, 0x17, 0x16, 0x9f, 0xf5, 0x6a, 0xdd,
+  0x25, 0xa1, 0x55, 0x6e, 0xb1, 0xfa, 0x09, 0xd0, 0x97, 0x7c, 0x13, 0xde,
+  0x1d, 0xd4, 0x94, 0x19, 0xde, 0x8b, 0x4d, 0xe7, 0xee, 0x1f, 0xdf, 0xe5,
+  0x3b, 0xdd, 0xbd, 0x13, 0x9c, 0xec, 0xcd, 0xb6, 0xb6, 0xbb, 0x3f, 0xbd,
+  0x54, 0xca, 0x47, 0x5c, 0x05, 0x3c, 0x03, 0x30, 0x9d, 0x56, 0xf6, 0xc6,
+  0x48, 0x6b, 0x74, 0x49, 0x58, 0xa2, 0xd8, 0x45, 0x42, 0x6f, 0xe4, 0x46,
+  0x27, 0x92, 0x83, 0x78, 0x97, 0x55, 0x5b, 0x82, 0xce, 0x2a, 0x08, 0x41,
+  0xb9, 0x7a, 0x66, 0x0f, 0x3c, 0x5b, 0xdf, 0x8d, 0x1d, 0x02, 0x11, 0xa4,
+  0xa7, 0x0a, 0x80, 0x1e, 0xbb, 0x7a, 0xc9, 0x2f, 0xb9, 0x35, 0xc8, 0xd7,
+  0x98, 0x04, 0x29, 0xaa, 0x4b, 0x88, 0x66, 0x73, 0xe4, 0x59, 0xc4, 0x3e,
+  0x50, 0xad, 0xe5, 0x64, 0x54, 0xf0, 0x29, 0x38, 0xee, 0xc0, 0x00, 0xc4,
+  0x22, 0x16, 0xf2, 0xc5, 0x46, 0x5c, 0xee, 0x9e, 0xf2, 0x9a, 0xe7, 0xfd,
+  0x62, 0x50, 0xa2, 0xeb, 0x47, 0x56, 0x4c, 0xe4, 0x75, 0x46, 0xe4, 0xd5,
+  0x25, 0xec, 0xe0, 0x35, 0x33, 0x31, 0x34, 0x1b, 0xcb, 0x72, 0x78, 0x1c,
+  0x4d, 0x3a, 0x19, 0x2e, 0xc4, 0xb7, 0xa4, 0x80, 0xd2, 0x91, 0xeb, 0x2a,
+  0x1d, 0xf2, 0xd1, 0xa3, 0xae, 0xac, 0x41, 0xae, 0xc2, 0x44, 0xd2, 0x3f,
+  0xb4, 0x87, 0x8d, 0x69, 0x6c, 0x67, 0xd6, 0x85, 0xee, 0xd6, 0x3b, 0x03,
+  0xdc, 0x58, 0x46, 0x07, 0x73, 0xb4, 0xb0, 0x3f, 0x5e, 0xc1, 0x13, 0x2c,
+  0x36, 0x58, 0xd0, 0x1c, 0x34, 0x3e, 0x01, 0x88, 0xfa, 0xb1, 0x9a, 0x03,
+  0x85, 0x4f, 0x4c, 0xd2, 0xac, 0xd9, 0x12, 0x09, 0xaa, 0x5f, 0x20, 0x06,
+  0x1f, 0x0a, 0x44, 0x28, 0x50, 0xd1, 0x8f, 0x51, 0x8a, 0x1d, 0xfa, 0xaa,
+  0x46, 0x33, 0xac, 0x0c, 0xb3, 0x10, 0xcf, 0x24, 0x4d, 0x0f, 0xcd, 0xee,
+  0xd9, 0x64, 0x4a, 0x1a, 0x84, 0x0f, 0xff, 0x48, 0x8d, 0x79, 0xd4, 0x43,
+  0x70, 0x1c, 0x7e, 0x7e, 0x12, 0x43, 0x51, 0x4a, 0x7e, 0x45, 0x9e, 0xa4,
+  0x3c, 0x12, 0xbd, 0x95, 0xe9, 0xd6, 0xd4, 0x3f, 0xbf, 0x03, 0xae, 0x9e,
+  0x24, 0x1a, 0x36, 0xbd, 0xea, 0x5d, 0x65, 0xff, 0x9f, 0x95, 0x70, 0xda,
+  0xb0, 0x53, 0x6a, 0x5f, 0x64, 0x7b, 0xb6, 0x7a, 0x8d, 0xa2, 0xd4, 0x9c,
+  0xb1, 0xf9, 0xe6, 0x14, 0x62, 0x3b, 0xe7, 0x5b, 0x40, 0x9d, 0xf4, 0x19,
+  0xb5, 0x50, 0xc8, 0xbd, 0x76, 0xd3, 0xbc, 0x0e, 0x6d, 0x62, 0x91, 0x73,
+  0x3e, 0x7f, 0xbf, 0xd0, 0xf0, 0x33, 0xf8, 0x6a, 0x9f, 0xa6, 0xad, 0xc3,
+  0xa0, 0x8f, 0x45, 0x99, 0x86, 0xa7, 0x49, 0x18, 0x8a, 0xed, 0xf1, 0x7d,
+  0x39, 0xf4, 0xb4, 0xf9, 0x82, 0x62, 0xd0, 0xa1, 0xb8, 0x3f, 0xe8, 0x25,
+  0xf7, 0xb1, 0x59, 0xce, 0x31, 0xba, 0x1d, 0x0b, 0x1f, 0x3d, 0x6c, 0x8b,
+  0xd2, 0xc5, 0x4e, 0x8e, 0xe8, 0x09, 0x9e, 0x1f, 0xf3, 0x67, 0x6f, 0x09,
+  0x03, 0x9d, 0xfe, 0x57, 0x6d, 0x9b, 0xce, 0x99, 0x7b, 0x01, 0x04, 0x52,
+  0xf5, 0x41, 0x7e, 0x38, 0x56, 0xb8, 0x71, 0x44, 0x43, 0x2c, 0x5e, 0x92,
+  0x9d, 0x95, 0xff, 0x0b, 0xf8, 0xfa, 0x89, 0x2c, 0x58, 0xde, 0xc5, 0x4e,
+  0x02, 0xe3, 0x82, 0xf7, 0xdc, 0x92, 0xa8, 0x7c, 0x39, 0x32, 0x76, 0x68,
+  0x9c, 0x73, 0x75, 0x1f, 0xbc, 0x6b, 0x46, 0x33, 0x5a, 0xdb, 0x94, 0x8c,
+  0x76, 0x79, 0x7e, 0x9b, 0xcc, 0x37, 0xeb, 0xed, 0xdc, 0xd5, 0xee, 0x2b,
+  0x30, 0x3f, 0x7b, 0x9b, 0xac, 0x38, 0x8f, 0xf1, 0x5e, 0xec, 0xa0, 0x46,
+  0x2c, 0xd1, 0x27, 0x19, 0x60, 0xec, 0xe2, 0xa7, 0x45, 0x61, 0x2d, 0xa8,
+  0x7e, 0xa9, 0xf8, 0x93, 0xa4, 0x23, 0x3e, 0xd8, 0x9c, 0xcc, 0xb3, 0xee,
+  0xc3, 0x1c, 0xfb, 0xbb, 0xad, 0xec, 0x73, 0x66, 0x31, 0x5d, 0x88, 0x9a,
+  0xec, 0x84, 0x91, 0x1e, 0x58, 0xdd, 0xb0, 0x01, 0x46, 0x18, 0x43, 0x64,
+  0xe2, 0xad, 0xac, 0x5a, 0x63, 0x4c, 0x32, 0x6b, 0xfd, 0xff, 0x66, 0x6d,
+  0xb4, 0x66, 0x88, 0xec, 0xfe, 0x23, 0xaa, 0x3a, 0x2a, 0xd5, 0xff, 0xed,
+  0x3a, 0x13, 0x9a, 0xae, 0x73, 0xc5, 0x62, 0x32, 0x47, 0x89, 0x19, 0x7f,
+  0x2c, 0x88, 0x62, 0x34, 0xc2, 0x90, 0xa9, 0x59, 0x7c, 0x45, 0xdb, 0x98,
+  0xaf, 0xf4, 0xba, 0x4e, 0x45, 0x55, 0xfc, 0x70, 0xa9, 0xfd, 0xb4, 0xa3,
+  0xd9, 0xa8, 0xfb, 0xe2, 0xe6, 0xf9, 0x60, 0xc1, 0x42, 0x70, 0x3d, 0xa5,
+  0x28, 0xcc, 0xd3, 0x54, 0x87, 0xda, 0x93, 0x91, 0x42, 0xa8, 0x8b, 0x62,
+  0xf3, 0x4e, 0xb7, 0x86, 0xfa, 0x52, 0x19, 0x69, 0xe3, 0x6c, 0xd1, 0xc3,
+  0x23, 0x82, 0xf7, 0x1d, 0xa1, 0x80, 0x92, 0xcd, 0x5e, 0x1a, 0x62, 0x3e,
+  0x1b, 0x31, 0x9d, 0x0d, 0xa8, 0x25, 0x3e, 0x83, 0xae, 0x36, 0xce, 0xfd,
+  0xac, 0xf7, 0x35, 0x7f, 0x74, 0xf4, 0x66, 0xa3, 0x5f, 0x00, 0xe5, 0x30,
+  0xc1, 0x11, 0x70, 0x00, 0xb5, 0xd9, 0xd4, 0x6e, 0x95, 0xc4, 0xbc, 0x5b,
+  0x7d, 0x62, 0x6c, 0xd5, 0xc0, 0x1e, 0x81, 0xc0, 0x61, 0x69, 0x13, 0x63,
+  0xbc, 0x7f, 0x70, 0x3f, 0x3d, 0x96, 0x18, 0x39, 0xef, 0x51, 0xc6, 0xe9,
+  0xcc, 0x59, 0xda, 0xc7, 0x5d, 0xb5, 0x59, 0xb0, 0xf2, 0x99, 0x5a, 0x36,
+  0x21, 0x0d, 0xcc, 0x97, 0x16, 0x2b, 0x61, 0x3d, 0x0a, 0xd1, 0x6e, 0x05,
+  0x86, 0x42, 0xff, 0xd8, 0xa7, 0x5c, 0x02, 0xcf, 0x90, 0x6b, 0x4e, 0xee,
+  0x4e, 0xca, 0xdb, 0xd3, 0xfe, 0x7e, 0x9b, 0xe2, 0xf0, 0xa3, 0x45, 0x6d,
+  0xa9, 0x92, 0xba, 0xce, 0xc6, 0x2e, 0x0a, 0xbc, 0xb2, 0x7a, 0x57, 0x07,
+  0x33, 0xc2, 0xa7, 0x16, 0x25, 0x06, 0x36, 0x83, 0x35, 0x31, 0x87, 0x18,
+  0x83, 0xa3, 0xc2, 0x88, 0x55, 0xcc, 0xe4, 0x84, 0x4c, 0xce, 0xb9, 0xeb,
+  0xd5, 0xb2, 0xbe, 0x3d, 0x76, 0x85, 0x10, 0x07, 0x83, 0xfa, 0x1c, 0x42,
+  0xbc, 0xa3, 0x4c, 0x29, 0x49, 0xe6, 0xc0, 0x30, 0x59, 0xe0, 0xc6, 0xbe,
+  0xa7, 0x48, 0x4a, 0xcf, 0x0e, 0x8e, 0xb7, 0x38, 0xf2, 0xa6, 0x26, 0xd3,
+  0x88, 0x06, 0x99, 0x46, 0x19, 0x65, 0x1c, 0x91, 0x8e, 0xae, 0x90, 0x78,
+  0x77, 0x7f, 0xe0, 0xc2, 0x51, 0x6f, 0xb6, 0x44, 0x15, 0xf9, 0xc5, 0x8a,
+  0x6c, 0x33, 0xd5, 0x90, 0x17, 0xc2, 0xca, 0x4e, 0xe1, 0x1f, 0xef, 0x02,
+  0x43, 0x05, 0x3f, 0x1e, 0xb1, 0x13, 0x23, 0x1f, 0xd6, 0xc2, 0xac, 0xc4,
+  0x49, 0x7a, 0x86, 0x06, 0x4b, 0xa1, 0x55, 0x6a, 0x75, 0x91, 0x4e, 0x6b,
+  0x86, 0x95, 0xa7, 0xbc, 0xdc, 0x64, 0xdb, 0x81, 0xc6, 0xa5, 0x33, 0x38,
+  0x98, 0xbb, 0xac, 0x03, 0xf0, 0xba, 0x49, 0xcf, 0x1c, 0xce, 0xe2, 0x3d,
+  0xe5, 0x06, 0xbc, 0x5e, 0xd0, 0xf7, 0x1c, 0xbb, 0x52, 0xa1, 0x47, 0x98,
+  0x12, 0xef, 0x1c, 0xb9, 0x53, 0xec, 0x67, 0x2c, 0xf0, 0x7d, 0x85, 0x9e,
+  0x45, 0x87, 0x00, 0x67, 0x2f, 0xa5, 0x19, 0x9f, 0x3e, 0x20, 0x8c, 0xe9,
+  0xfa, 0x8a, 0xd8, 0x02, 0x6e, 0x16, 0xc4, 0x43, 0xff, 0x08, 0x3f, 0xf3,
+  0x76, 0x53, 0x95, 0x17, 0x6e, 0x74, 0xfe, 0x7e, 0x87, 0x66, 0xc9, 0xe8,
+  0x8d, 0x21, 0xea, 0xd2, 0x4d, 0xc7, 0x9c, 0x5a, 0xef, 0xd5, 0xe1, 0x12,
+  0x85, 0x22, 0x40, 0x3c, 0x9d, 0x89, 0x4f, 0x12, 0xb5, 0x01, 0x95, 0x0e,
+  0x9b, 0xd3, 0x38, 0x5e, 0x21, 0x5a, 0x4e, 0x7e, 0xce, 0xf7, 0xa6, 0x5a,
+  0x63, 0x78, 0x40, 0xba, 0x9f, 0x29, 0xf0, 0x75, 0xb6, 0x8b, 0xd9, 0x4c,
+  0xab, 0xb9, 0xf4, 0xe9, 0x1f, 0x39, 0x01, 0xb3, 0xfc, 0x2c, 0xa4, 0x74,
+  0xa9, 0xa9, 0x90, 0xed, 0x77, 0xd8, 0x0c, 0x6d, 0x5c, 0x7b, 0xfc, 0xbd,
+  0x96, 0x96, 0xcb, 0x9b, 0x9f, 0x88, 0x86, 0x5c, 0x3c, 0x0a, 0xde, 0x28,
+  0x7c, 0xf0, 0x91, 0x1c, 0x06, 0x52, 0xbe, 0xad, 0xc8, 0xef, 0xa5, 0xd3,
+  0x1e, 0x29, 0xbd, 0x1d, 0xd5, 0xba, 0xf4, 0x83, 0x2d, 0x36, 0x9a, 0x8c,
+  0x8d, 0x83, 0xac, 0x3f, 0xea, 0xd2, 0x2e, 0xfb, 0xf1, 0xaa, 0x7a, 0x2e,
+  0xce, 0xd3, 0x90, 0x9f, 0x3c, 0x2c, 0xee, 0xed, 0xf8, 0xfc, 0x3c, 0x0e,
+  0x5f, 0xd1, 0xda, 0x9c, 0x32, 0x52, 0xcd, 0x09, 0xa1, 0x53, 0x33, 0x37,
+  0xe0, 0x37, 0x95, 0xb2, 0x8d, 0x03, 0x46, 0x1f, 0xb5, 0x99, 0x65, 0x54,
+  0x61, 0xa2, 0xdc, 0xe9, 0x87, 0x4d, 0x41, 0xdf, 0xd1, 0xb5, 0x2c, 0x7a,
+  0x46, 0x08, 0x5e, 0x0f, 0xcc, 0x80, 0x96, 0x52, 0x98, 0xa0, 0x82, 0x52,
+  0x6d, 0x62, 0x6f, 0xd9, 0x48, 0xc1, 0x36, 0x0c, 0x5c, 0x7f, 0xad, 0x2c,
+  0x27, 0xcf, 0x17, 0xee, 0xfa, 0xca, 0x14, 0xe7, 0x88, 0xc4, 0x20, 0xb2,
+  0xa1, 0xd2, 0x66, 0xe8, 0x81, 0xce, 0x35, 0x2b, 0x30, 0x54, 0x16, 0x9e,
+  0x42, 0x77, 0x16, 0x3b, 0x84, 0x77, 0x42, 0x71, 0x33, 0xf8, 0x62, 0x9e,
+  0xd4, 0x1d, 0x1d, 0xf3, 0x91, 0x60, 0x97, 0xd8, 0x10, 0x29, 0xc8, 0xf9,
+  0xfa, 0xca, 0x0a, 0xe9, 0x50, 0xe1, 0xcc, 0xa7, 0xe3, 0x77, 0xc2, 0x93,
+  0x68, 0x50, 0x1a, 0x98, 0xd7, 0x68, 0x40, 0x80, 0x12, 0x64, 0xa7, 0x1d,
+  0xb4, 0x52, 0x85, 0x7b, 0x0e, 0x85, 0x0a, 0x59, 0x6a, 0xc8, 0xe4, 0x4b,
+  0xff, 0xd7, 0x0d, 0x7d, 0x9e, 0xef, 0x07, 0x2f, 0x6d, 0x46, 0x05, 0xf9,
+  0x05, 0xb1, 0x97, 0x94, 0x23, 0xc5, 0x2a, 0x99, 0xcc, 0x9c, 0xc2, 0x82,
+  0x97, 0xbc, 0x24, 0x9b, 0xe4, 0xf2, 0xb3, 0x12, 0x84, 0xa0, 0x2a, 0xc4,
+  0x7d, 0x29, 0x4d, 0xa4, 0x97, 0xd0, 0x85, 0xa6, 0x39, 0x18, 0xd2, 0xfb,
+  0xa7, 0x08, 0x53, 0x75, 0x6b, 0xbd, 0xe3, 0x98, 0x4c, 0x94, 0xdd, 0xd4,
+  0x86, 0x94, 0xc2, 0x6a, 0x14, 0x23, 0xdd, 0x69, 0xae, 0x53, 0xec, 0x83,
+  0x58, 0x8e, 0x87, 0x7b, 0xf1, 0xcf, 0xff, 0x34, 0xda, 0x39, 0x67, 0xba,
+  0x90, 0xc5, 0xec, 0xe0, 0xb3, 0xad, 0xad, 0x3d, 0x4c, 0x8e, 0x3f, 0x08,
+  0x62, 0x80, 0x5b, 0x2d, 0xf8, 0xe1, 0x67, 0x61, 0x79, 0xf5, 0xc9, 0xbe,
+  0x74, 0x1b, 0x72, 0x02, 0x56, 0xc6, 0xf8, 0xd5, 0x87, 0x3a, 0x08, 0x7b,
+  0x35, 0x8f, 0xdf, 0xdf, 0x87, 0x3e, 0x09, 0xf7, 0xd2, 0x74, 0xbb, 0xec,
+  0x8c, 0x49, 0x0c, 0xb5, 0x3a, 0x6b, 0x33, 0x43, 0x52, 0xe2, 0x2f, 0x71,
+  0x3e, 0x6f, 0x59, 0x52, 0x50, 0x8f, 0xdb, 0xa6, 0x52, 0xa7, 0x5d, 0xda,
+  0x16, 0x71, 0xb2, 0x52, 0xd7, 0x3e, 0x2d, 0xf6, 0x98, 0x53, 0x0f, 0x8f,
+  0xc1, 0x79, 0xd0, 0xcf, 0xe0, 0xc8, 0x22, 0x27, 0x41, 0x14, 0xe8, 0xb8,
+  0xed, 0x65, 0x3c, 0xaa, 0x11, 0x72, 0x41, 0xa8, 0xd8, 0x0b, 0x35, 0x81,
+  0xec, 0xa6, 0x12, 0x30, 0x23, 0x0b, 0x71, 0x7a, 0x28, 0xd9, 0x01, 0x82,
+  0x35, 0xd1, 0x64, 0x6d, 0xf3, 0x63, 0x69, 0x78, 0xb4, 0x93, 0x1e, 0x05,
+  0xc9, 0xb3, 0xbc, 0xb6, 0xc4, 0x5e, 0xb6, 0x2a, 0x6e, 0xec, 0x91, 0x4a,
+  0x5c, 0xa2, 0x5c, 0xea, 0x2b, 0xe3, 0x33, 0x1a, 0xb3, 0x70, 0xd5, 0x39,
+  0x77, 0x3e, 0xa2, 0x96, 0xd5, 0x10, 0x75, 0x8a, 0x91, 0xc6, 0xbc, 0xb6,
+  0x86, 0xa6, 0x8f, 0xd3, 0x50, 0x09, 0xa3, 0x9a, 0x1f, 0xd0, 0xd7, 0xd7,
+  0x23, 0xa0, 0x32, 0xd0, 0x69, 0x33, 0x2f, 0x18, 0xf2, 0x6f, 0xe2, 0xbc,
+  0x2f, 0x7f, 0xf5, 0x46, 0x81, 0x2e, 0xad, 0x14, 0xc9, 0x57, 0x10, 0xa4,
+  0x71, 0xa9, 0xa4, 0x05, 0x50, 0xcb, 0x93, 0xc7, 0x53, 0x84, 0x68, 0xa5,
+  0x7c, 0x65, 0xc0, 0xe0, 0x37, 0xd6, 0xc3, 0xbb, 0x36, 0xef, 0x22, 0x9e,
+  0x09, 0x32, 0xa5, 0xa6, 0x73, 0x61, 0xb6, 0x3c, 0x5a, 0xbe, 0x2f, 0x63,
+  0x01, 0x35, 0xfe, 0xd8, 0x98, 0xd5, 0x7e, 0xfd, 0x68, 0xd8, 0x96, 0x51,
+  0x6e, 0x3a, 0x17, 0x90, 0x16, 0xeb, 0x03, 0xfa, 0x0a, 0x83, 0x1a, 0xc9,
+  0x48, 0x14, 0x31, 0x32, 0x07, 0x7d, 0xa8, 0xa8, 0x64, 0xd8, 0xba, 0xcf,
+  0x87, 0xc5, 0x0e, 0xc3, 0x1c, 0x5b, 0xfe, 0x31, 0x98, 0xea, 0x25, 0x29,
+  0x9c, 0x77, 0xf2, 0x9f, 0x5e, 0x16, 0x11, 0x6b, 0x29, 0x08, 0xab, 0xb0,
+  0x57, 0xd8, 0x3d, 0x85, 0xdc, 0x3b, 0x69, 0xea, 0xd5, 0xe6, 0x90, 0xfa,
+  0x95, 0x8d, 0xcc, 0x3c, 0x2d, 0x86, 0x07, 0xc6, 0x7e, 0x8d, 0xc4, 0x7a,
+  0x3a, 0xcd, 0x61, 0xa4, 0x1f, 0xd9, 0x6f, 0x07, 0xa3, 0x45, 0xe8, 0x41,
+  0xed, 0x51, 0x14, 0xe4, 0x3d, 0x20, 0x3b, 0x11, 0x9e, 0x93, 0xc3, 0x2e,
+  0xcd, 0x29, 0x85, 0xf0, 0x61, 0x68, 0x8e, 0x19, 0xdc, 0x20, 0x0a, 0xbd,
+  0xc0, 0x15, 0x90, 0x08, 0x96, 0xcf, 0x9b, 0xf3, 0xb5, 0x7b, 0xe4, 0x9a,
+  0x97, 0x22, 0x93, 0x40, 0xd4, 0xde, 0x7a, 0x6e, 0x6b, 0xc4, 0x16, 0x9e,
+  0x1c, 0x98, 0x9b, 0x83, 0x6e, 0x4d, 0xde, 0x11, 0x4f, 0x22, 0xed, 0x2d,
+  0xe1, 0xb3, 0xfa, 0x86, 0xb0, 0xd2, 0x53, 0xd2, 0x34, 0x8a, 0x58, 0xdc,
+  0x8c, 0xd9, 0x60, 0xd3, 0x46, 0x0a, 0xde, 0x48, 0xa3, 0xda, 0x5b, 0x74,
+  0x3e, 0x4c, 0x51, 0xa6, 0x02, 0x20, 0xc6, 0x0d, 0xdb, 0x13, 0x42, 0xad,
+  0xc6, 0x90, 0xb1, 0xe0, 0xb0, 0xac, 0xdc, 0xa7, 0x48, 0xf8, 0x2d, 0x8f,
+  0xd7, 0xd9, 0x10, 0xeb, 0xd8, 0xdb, 0xf0, 0x53, 0x67, 0xa9, 0x03, 0x3e,
+  0x97, 0xbf, 0xe6, 0xc3, 0xa8, 0x87, 0x3a, 0x91, 0xb8, 0xcf, 0x88, 0x5b,
+  0x0d, 0x06, 0xe1, 0xe2, 0x39, 0x74, 0xc8, 0x59, 0xe0, 0x90, 0x9f, 0xc9,
+  0x0a, 0x74, 0xa3, 0xb2, 0xae, 0x69, 0x79, 0xfa, 0x0d, 0xf2, 0xee, 0xde,
+  0xec, 0x88, 0xbf, 0x09, 0x54, 0xd6, 0xbe, 0xbb, 0x25, 0x91, 0xe4, 0x66,
+  0xd2, 0x08, 0x78, 0xda, 0x9d, 0x07, 0xc3, 0x0b, 0x3f, 0x1a, 0xd9, 0xf4,
+  0xb2, 0x2d, 0x69, 0x74, 0xb1, 0x78, 0x5f, 0xc1, 0xaf, 0x7f, 0x6d, 0x17,
+  0xfc, 0x2c, 0x67, 0x62, 0xce, 0xb4, 0x41, 0x6e, 0x21, 0x4b, 0x5c, 0x77,
+  0xa1, 0x1f, 0xfe, 0xe6, 0x28, 0xc8, 0x52, 0xd1, 0x8e, 0x66, 0x88, 0x65,
+  0x0c, 0x58, 0xec, 0x1c, 0x71, 0x4c, 0x8a, 0xc0, 0xef, 0x3e, 0x34, 0xf7,
+  0x90, 0x67, 0x28, 0x16, 0x20, 0x3a, 0x2c, 0x3f, 0x51, 0x53, 0x15, 0x1c,
+  0x6c, 0x75, 0x0e, 0xe1, 0xb4, 0xf3, 0x7f, 0x60, 0x3a, 0x81, 0x34, 0x82,
+  0x51, 0x5e, 0x75, 0xb0, 0x5c, 0x37, 0x87, 0x2d, 0xd5, 0xc5, 0x2c, 0xab,
+  0x33, 0x8a, 0x60, 0x49, 0x2c, 0xde, 0x90, 0x12, 0x11, 0x1f, 0x4b, 0x27,
+  0x15, 0x92, 0xa2, 0xf1, 0x1a, 0xde, 0x35, 0x34, 0x4d, 0x52, 0xcd, 0xc0,
+  0x71, 0x46, 0x7f, 0x3e, 0x21, 0x92, 0x5f, 0xc8, 0x25, 0xd4, 0x2c, 0xf4,
+  0xd9, 0x38, 0xde, 0xa5, 0xae, 0x83, 0xe3, 0x50, 0x9b, 0x1b, 0xad, 0x4b,
+  0xd8, 0x3f, 0x0a, 0x23, 0x40, 0x1e, 0x46, 0x7a, 0x71, 0x06, 0xac, 0x9e,
+  0x06, 0xb8, 0x96, 0xef, 0x07, 0xef, 0x38, 0xe9, 0x79, 0xaa, 0x64, 0x44,
+  0xa9, 0xa3, 0xc5, 0x1d, 0x5d, 0xd3, 0xa7, 0x01, 0xef, 0xf6, 0x3b, 0x15,
+  0x00, 0x0c, 0xf7, 0x59, 0x4a, 0x1c, 0x12, 0x20, 0x89, 0xa8, 0x4e, 0x7b,
+  0xf8, 0x9d, 0x02, 0xa6, 0x5e, 0x19, 0x7e, 0xb8, 0x5f, 0x46, 0xd9, 0xb1,
+  0xbe, 0x25, 0x2c, 0x3c, 0xe7, 0x5d, 0x3b, 0x3f, 0x6f, 0x6e, 0x94, 0x83,
+  0xc3, 0x8e, 0x85, 0x65, 0xff, 0xe9, 0x8e, 0x32, 0xcc, 0x68, 0x51, 0x14,
+  0xbf, 0x94, 0x21, 0x3f, 0x85, 0xa8, 0x76, 0x44, 0xe6, 0xca, 0x20, 0x84,
+  0xec, 0x83, 0x84, 0x64, 0xfb, 0x80, 0x01, 0x73, 0x76, 0x21, 0xd3, 0xf0,
+  0x7b, 0x74, 0x5c, 0xbf, 0x71, 0xe6, 0x34, 0xff, 0x58, 0xe8, 0x6f, 0x88,
+  0xa6, 0xad, 0xcf, 0x93, 0x2a, 0xc5, 0xc5, 0x23, 0x32, 0xc8, 0xec, 0xbd,
+  0xf9, 0x54, 0x3d, 0xda, 0xe4, 0x81, 0x74, 0x94, 0xbf, 0x36, 0x72, 0x11,
+  0xf0, 0x8a, 0x8f, 0x1b, 0x55, 0x47, 0x70, 0x7d, 0x61, 0xf0, 0x7b, 0x11,
+  0x56, 0xdb, 0xbc, 0xe5, 0x72, 0xf2, 0xbd, 0x0b, 0xa0, 0x80, 0x03, 0x1a,
+  0xc6, 0xe9, 0xfc, 0xcd, 0xde, 0x42, 0xae, 0x1a, 0x7d, 0x90, 0x5d, 0x21,
+  0x5b, 0x3d, 0x69, 0x6f, 0x42, 0x42, 0xf2, 0x8a, 0xc8, 0xfc, 0xb9, 0xa9,
+  0xdf, 0x18, 0xc4, 0x97, 0x91, 0x21, 0x28, 0xfd, 0x82, 0x8a, 0xe7, 0xac,
+  0xe5, 0x5d, 0x33, 0x7b, 0x78, 0x0a, 0x48, 0x43, 0xfe, 0xfe, 0xcf, 0x09,
+  0x5f, 0xed, 0x18, 0x33, 0x0c, 0xab, 0x8a, 0x5d, 0x63, 0xd5, 0x43, 0x0b,
+  0xde, 0x75, 0x56, 0xef, 0x11, 0x05, 0x8c, 0xbb, 0xc0, 0x10, 0x4e, 0x85,
+  0x70, 0xe1, 0x7e, 0x62, 0xb6, 0x3a, 0x84, 0x80, 0x17, 0xab, 0x38, 0x59,
+  0x0b, 0xe2, 0xb1, 0x31, 0xb8, 0xb5, 0xf5, 0xad, 0xf6, 0xbf, 0x5b, 0xfb,
+  0x69, 0xc8, 0xb3, 0xce, 0x65, 0xd4, 0x8e, 0x04, 0xc5, 0xc4, 0x09, 0xba,
+  0x36, 0xc9, 0x90, 0xe0, 0xc2, 0x21, 0x3a, 0x94, 0x83, 0xa5, 0xd1, 0xb2,
+  0xe1, 0xae, 0x6a, 0x28, 0x22, 0x59, 0x79, 0x72, 0x82, 0x42, 0x89, 0x42,
+  0x9c, 0xc3, 0xdf, 0x8d, 0x15, 0x22, 0x14, 0xb3, 0xfd, 0x2a, 0x85, 0xbe,
+  0xd3, 0x12, 0xa5, 0x3b, 0x0c, 0x99, 0xb2, 0xe5, 0x43, 0x8d, 0xd7, 0xc0,
+  0xa1, 0xb6, 0xb2, 0xae, 0x42, 0x4a, 0xc0, 0xe5, 0x09, 0xa2, 0xf6, 0xa4,
+  0xbc, 0x01, 0xee, 0x94, 0xd2, 0x0b, 0xeb, 0x28, 0x80, 0xc9, 0x7a, 0x07,
+  0xd7, 0x4b, 0xee, 0x01, 0x10, 0x48, 0xcc, 0xc6, 0x03, 0x99, 0x9d, 0x67,
+  0x2a, 0xbd, 0xa0, 0x6f, 0x51, 0xa4, 0x75, 0x50, 0xe1, 0x84, 0x8e, 0xda,
+  0x7b, 0x5e, 0x9e, 0x78, 0x18, 0x2a, 0x6b, 0xfa, 0xef, 0x87, 0x81, 0xe9,
+  0x48, 0x3f, 0x29, 0x2d, 0xfb, 0x15, 0xd2, 0x15, 0xb5, 0x5c, 0xed, 0x45,
+  0x48, 0x30, 0xec, 0x00, 0x55, 0x15, 0x13, 0xc7, 0x11, 0xc4, 0x29, 0xef,
+  0x0f, 0xa8, 0xa6, 0xef, 0x19, 0x41, 0xc2, 0xb6, 0x11, 0xdc, 0xe8, 0xf4,
+  0xa7, 0x03, 0x80, 0x2d, 0x92, 0xad, 0x7e, 0x7e, 0x8a, 0x71, 0xa4, 0x6c,
+  0x16, 0xb9, 0x84, 0xf5, 0x8d, 0x94, 0xc5, 0xd5, 0x82, 0x29, 0x42, 0x22,
+  0x1f, 0x06, 0xca, 0xdd, 0xbf, 0x74, 0x0f, 0x14, 0x79, 0x26, 0x9c, 0x79,
+  0x30, 0xcb, 0x01, 0x02, 0x76, 0x22, 0x4f, 0x54, 0xff, 0x49, 0xa3, 0x03,
+  0x35, 0x23, 0x45, 0x91, 0xac, 0xed, 0x13, 0x31, 0xa4, 0x4e, 0x51, 0xe8,
+  0x9c, 0x5b, 0xe4, 0xcf, 0x41, 0xd3, 0xa0, 0x86, 0x7f, 0x3a, 0x4d, 0xaf,
+  0xa7, 0x49, 0x63, 0x47, 0x86, 0x08, 0x88, 0xcf, 0x01, 0x7a, 0xc4, 0xf5,
+  0x29, 0x67, 0x8a, 0xd4, 0xdd, 0x6a, 0x6d, 0x81, 0xb8, 0x29, 0x9d, 0x7c,
+  0x32, 0x4e, 0x8f, 0x0c, 0x9f, 0x8c, 0x7e, 0x76, 0xa3, 0xd4, 0x32, 0x80,
+  0xd0, 0x79, 0x7d, 0x56, 0x99, 0x6d, 0x0b, 0x88, 0xfc, 0x98, 0xdb, 0xaf,
+  0x13, 0xf3, 0xb2, 0x20, 0x3f, 0x19, 0xe1, 0x83, 0x70, 0xd2, 0x26, 0xd0,
+  0xd2, 0xad, 0x11, 0xeb, 0x3b, 0x31, 0x03, 0x55, 0x62, 0xca, 0xb5, 0x87,
+  0x31, 0x7a, 0x11, 0x4c, 0xf2, 0xc3, 0xc2, 0x1c, 0x42, 0x94, 0x7b, 0xe6,
+  0x29, 0x86, 0x70, 0x8e, 0x51, 0x4a, 0xa3, 0xf2, 0xf0, 0xed, 0xa1, 0xc6,
+  0x18, 0xff, 0xf2, 0xff, 0xe0, 0x07, 0x85, 0xf1, 0x93, 0x5a, 0x83, 0x1c,
+  0x4c, 0xa9, 0x9b, 0xc5, 0x0c, 0xc4, 0xf0, 0xde, 0x71, 0x93, 0x78, 0xd1,
+  0x3b, 0xcc, 0x5b, 0x51, 0x1f, 0xd7, 0x21, 0x12, 0x57, 0xd5, 0x2a, 0xea,
+  0x64, 0x08, 0x0e, 0xf0, 0x3d, 0x42, 0xe7, 0xdf, 0xc8, 0xea, 0x42, 0x2b,
+  0x41, 0x55, 0x85, 0xb8, 0x54, 0xa4, 0xc9, 0x3f, 0xce, 0xfc, 0x1a, 0xde,
+  0x73, 0x08, 0xaa, 0x09, 0x25, 0x08, 0xa0, 0xdc, 0x64, 0xb7, 0xe7, 0xcc,
+  0xde, 0x85, 0xa6, 0xc3, 0xe9, 0xe1, 0x43, 0x71, 0x86, 0x05, 0x55, 0x86,
+  0x47, 0xf8, 0x71, 0xbd, 0xf5, 0xd7, 0x38, 0x64, 0x7f, 0x71, 0x63, 0xe1,
+  0x22, 0x39, 0x99, 0xc3, 0xdf, 0x27, 0x5d, 0xdd, 0xd0, 0x57, 0x99, 0xd5,
+  0x97, 0xcd, 0xd4, 0x2e, 0xc1, 0x25, 0x3d, 0x2e, 0x03, 0x0b, 0x04, 0x20,
+  0x70, 0xec, 0x46, 0x6c, 0x4b, 0x55, 0x16, 0x02, 0x00, 0x71, 0xfd, 0x8a,
+  0xa0, 0x1e, 0x5f, 0x41, 0xe6, 0x96, 0x58, 0xbe, 0x02, 0x73, 0x91, 0x71,
+  0xb2, 0x7e, 0xc4, 0xcd, 0xce, 0xa5, 0x26, 0xee, 0xff, 0x8c, 0x9a, 0x4c,
+  0xf4, 0x0a, 0x89, 0xba, 0x14, 0x6e, 0x06, 0x86, 0xb0, 0xba, 0x41, 0xdd,
+  0x27, 0xf8, 0xc3, 0x46, 0x4f, 0x39, 0xac, 0x2c, 0x8a, 0x69, 0x09, 0xb7,
+  0x36, 0x0f, 0xe0, 0x8d, 0x31, 0x0f, 0xc3, 0xee, 0x3a, 0x6a, 0x9e, 0x96,
+  0x91, 0xf5, 0x6a, 0x12, 0x98, 0x5a, 0xc3, 0xf3, 0xb8, 0x9b, 0x07, 0xdb,
+  0x8e, 0x2a, 0xb0, 0x91, 0x86, 0xb5, 0xc7, 0xe9, 0x06, 0xe1, 0x4e, 0x83,
+  0x28, 0x3a, 0x0e, 0x67, 0xe5, 0x7e, 0x88, 0x2a, 0x31, 0xd2, 0xfe, 0xf6,
+  0x19, 0x3d, 0x09, 0xd1, 0xef, 0x5d, 0xe1, 0x15, 0x2d, 0xb4, 0xec, 0x23,
+  0xc2, 0x0c, 0x7a, 0xbf, 0xd3, 0x6f, 0xf7, 0x8a, 0x3b, 0x3a, 0x0f, 0x20,
+  0xc4, 0x78, 0xbe, 0x46, 0x30, 0x0f, 0xc2, 0xd0, 0x8c, 0x23, 0xb7, 0xfa,
+  0x3c, 0x19, 0x35, 0x53, 0x5f, 0xf9, 0x94, 0xf5, 0x23, 0xbe, 0xb3, 0x56,
+  0x42, 0xa1, 0x27, 0xff, 0xac, 0xbf, 0x72, 0x7e, 0x89, 0xbe, 0xb9, 0x6d,
+  0x2d, 0xc4, 0x3f, 0x6c, 0x7f, 0xc4, 0x7e, 0x01, 0x09, 0xc8, 0x35, 0x80,
+  0x99, 0x8f, 0x1c, 0x43, 0xd3, 0xb2, 0x4a, 0xb7, 0x08, 0x06, 0x63, 0xcd,
+  0x8a, 0x5e, 0x64, 0xa2, 0x93, 0xa5, 0x15, 0xa0, 0x38, 0xa0, 0xf2, 0x1c,
+  0xab, 0xe1, 0x2d, 0x19, 0x30, 0xee, 0x9b, 0x87, 0x42, 0x54, 0xfb, 0xcc,
+  0xfe, 0x2a, 0xcd, 0x54, 0xf5, 0xeb, 0x52, 0x6b, 0xd4, 0x1d, 0xa3, 0x7c,
+  0xec, 0xf2, 0x56, 0x51, 0x54, 0xab, 0x66, 0xb0, 0x73, 0x49, 0x3e, 0xc4,
+  0x89, 0xac, 0xb0, 0xc1, 0x41, 0x6f, 0x19, 0xd6, 0x41, 0xbd, 0xc2, 0xe2,
+  0x1a, 0x56, 0xb3, 0x01, 0xc9, 0xdf, 0x46, 0xe7, 0xa1, 0x42, 0xfa, 0x1c,
+  0x18, 0x86, 0xe2, 0x07, 0xe4, 0xfe, 0x19, 0x03, 0x7d, 0xc4, 0x51, 0x78,
+  0x29, 0x68, 0x73, 0x70, 0x82, 0x98, 0x34, 0x2e, 0x41, 0x59, 0xd5, 0x20,
+  0x36, 0xe3, 0xe5, 0x2c, 0xbe, 0x76, 0x23, 0x5d, 0xb1, 0xf0, 0xda, 0xee,
+  0x65, 0x54, 0xd9, 0xa1, 0x77, 0x6e, 0xd8, 0x56, 0xcb, 0x6a, 0x35, 0xb5,
+  0xaa, 0x97, 0x22, 0x28, 0x4d, 0x74, 0x13, 0x96, 0x59, 0x3d, 0x3a, 0xe2,
+  0x26, 0xde, 0xd3, 0xc7, 0xed, 0x97, 0x98, 0xa8, 0x4a, 0x6b, 0x4b, 0xd1,
+  0x52, 0xca, 0x84, 0xd6, 0x19, 0x7a, 0x6c, 0x0d, 0xb4, 0x28, 0x4f, 0xb1,
+  0xa2, 0xcc, 0x07, 0x08, 0x57, 0xc9, 0x32, 0xd4, 0xe0, 0xef, 0x96, 0x9a,
+  0x31, 0x1e, 0x68, 0x1d, 0x7b, 0x57, 0x26, 0x62, 0xa4, 0x26, 0xaf, 0xc7,
+  0xd0, 0xab, 0xb6, 0x9e, 0x00, 0x6d, 0xfe, 0x29, 0x30, 0x53, 0xcd, 0xb8,
+  0x4e, 0x30, 0x4e, 0xa5, 0xcc, 0xf6, 0xab, 0xca, 0x4d, 0x74, 0x40, 0xc2,
+  0xb4, 0xfb, 0x3f, 0x75, 0x0a, 0x9d, 0x88, 0xa3, 0xb0, 0x5b, 0x4e, 0x88,
+  0x50, 0x90, 0xcb, 0x5c, 0xcd, 0xc7, 0xff, 0x75, 0x97, 0xc4, 0x1b, 0xe9,
+  0x03, 0x8a, 0xa7, 0x62, 0x32, 0x98, 0x60, 0x39, 0x56, 0xe5, 0x25, 0xed,
+  0xba, 0x58, 0x67, 0xa3, 0xe8, 0x23, 0xd1, 0x55, 0xb3, 0xa5, 0xc0, 0xc9,
+  0x75, 0x14, 0x91, 0xe6, 0x7d, 0x0e, 0xe3, 0xac, 0xc8, 0x6b, 0xa7, 0xdb,
+  0x36, 0xe8, 0x44, 0x92, 0x72, 0xf2, 0x6d, 0x10, 0xeb, 0xd0, 0x7a, 0xdd,
+  0x00, 0x9b, 0xf8, 0x65, 0xaa, 0xef, 0xed, 0xfb, 0x84, 0x5f, 0xfb, 0xd8,
+  0xe9, 0xa8, 0x71, 0xab, 0x20, 0x98, 0x4f, 0x21, 0x7d, 0x33, 0xe2, 0xb1,
+  0x3f, 0x95, 0x9c, 0x28, 0xf5, 0xd5, 0x83, 0x01, 0xe9, 0x71, 0x68, 0xa9,
+  0x3d, 0x9e, 0x49, 0xfb, 0x6c, 0x83, 0x5f, 0x48, 0x9d, 0x91, 0x00, 0xab,
+  0x54, 0x17, 0x11, 0x5b, 0x9d, 0x0a, 0x17, 0x8e, 0x3a, 0xbc, 0xd5, 0x33,
+  0xcd, 0x2a, 0x5b, 0x14, 0x39, 0xe4, 0x30, 0x45, 0xde, 0x6e, 0xde, 0x92,
+  0x7f, 0xb5, 0x91, 0x5d, 0x5b, 0xe4, 0x18, 0x17, 0x7c, 0x22, 0x1e, 0x2d,
+  0x97, 0x8b, 0x6f, 0xe0, 0x54, 0x2e, 0x25, 0xbc, 0x5f, 0xef, 0x27, 0x1b,
+  0x95, 0x71, 0xcc, 0x29, 0x96, 0x30, 0x82, 0xb1, 0x99, 0x98, 0x28, 0x36,
+  0x5f, 0xd6, 0xf9, 0x13, 0xb3, 0x3d, 0x14, 0x91, 0x8a, 0x2f, 0xbf, 0x6e,
+  0x8c, 0x57, 0xf6, 0x8e, 0x32, 0xf2, 0xd3, 0xa5, 0x1b, 0x2b, 0xba, 0xc8,
+  0x0d, 0xa4, 0xd3, 0xc2, 0x16, 0x1f, 0x5f, 0xb6, 0x89, 0x77, 0xa9, 0xf3,
+  0x7b, 0xb8, 0x11, 0x23, 0x41, 0xd6, 0xe0, 0x47, 0x3c, 0x94, 0xe0, 0xed,
+  0xa9, 0xb1, 0x0e, 0x90, 0x38, 0xdd, 0x60, 0xcd, 0x75, 0x00, 0x36, 0x3a,
+  0x42, 0xbb, 0xfd, 0xd7, 0xc6, 0x16, 0x38, 0xb4, 0xc0, 0x1d, 0xb6, 0x46,
+  0x5c, 0x2f, 0x70, 0x95, 0x8d, 0x74, 0x68, 0xb2, 0xb5, 0xae, 0x73, 0x22,
+  0xa1, 0xca, 0x5d, 0xd4, 0x28, 0x1a, 0xd2, 0x19, 0x1c, 0x43, 0x5e, 0x12,
+  0x16, 0x15, 0xb4, 0x97, 0x64, 0x10, 0x07, 0x48, 0xf8, 0xe3, 0xfb, 0x3e,
+  0xa5, 0x05, 0xcd, 0xc1, 0x29, 0xf0, 0x67, 0xb7, 0x24, 0x02, 0xac, 0x76,
+  0x91, 0x64, 0x63, 0x46, 0xfb, 0xfd, 0xaa, 0x5b, 0x3f, 0xeb, 0xe0, 0xb2,
+  0x5a, 0x8d, 0xde, 0xdc, 0x92, 0x0c, 0x1e, 0xfc, 0x82, 0x55, 0xc7, 0x8a,
+  0xe3, 0x28, 0x57, 0xfe, 0x10, 0xe1, 0xa3, 0x5a, 0x9e, 0x67, 0x86, 0xf4,
+  0xa5, 0xf5, 0xa0, 0xbd, 0xa4, 0x3c, 0xda, 0xf3, 0x83, 0x27, 0x2f, 0x55,
+  0x73, 0xb6, 0x74, 0x3e, 0xd3, 0xc9, 0x84, 0x1d, 0xff, 0x61, 0x01, 0x56,
+  0x30, 0x2a, 0x23, 0x57, 0xbc, 0x88, 0xa7, 0x2f, 0x6f, 0x95, 0x91, 0x4e,
+  0x5b, 0x41, 0xd9, 0x95, 0x1f, 0x09, 0x95, 0x79, 0x36, 0xe3, 0x7f, 0xbd,
+  0x4b, 0x09, 0x4e, 0x7f, 0x6a, 0x58, 0x6e, 0xd0, 0x60, 0xaf, 0xf1, 0x8f,
+  0x4c, 0xc5, 0x5a, 0x5c, 0xb7, 0x74, 0x83, 0x3c, 0xb3, 0x7e, 0xdc, 0x76,
+  0x89, 0xa5, 0xca, 0xd7, 0x75, 0x35, 0xb2, 0x4c, 0x0a, 0x67, 0x2b, 0x7a,
+  0xe8, 0xac, 0x9e, 0x26, 0xa3, 0xae, 0x87, 0x66, 0x12, 0x4e, 0x74, 0xc8,
+  0xd8, 0x6d, 0x89, 0x9c, 0x34, 0x63, 0x61, 0x33, 0x1b, 0x6a, 0x78, 0x7f,
+  0x2f, 0xa7, 0x9b, 0xe7, 0x42, 0x0d, 0xcb, 0xc9, 0xf0, 0xa6, 0xb5, 0x38,
+  0x66, 0x80, 0xca, 0x7a, 0xa9, 0xe4, 0x93, 0xe3, 0xfc, 0x7d, 0x38, 0x7d,
+  0x7a, 0x2c, 0x03, 0xb4, 0x35, 0xde, 0x1b, 0x2e, 0x29, 0x24, 0x40, 0x93,
+  0x6c, 0x52, 0x21, 0xd6, 0x70, 0x88, 0xfd, 0xc7, 0x5c, 0x94, 0x95, 0xc0,
+  0x03, 0xce, 0x1b, 0xb3, 0x0e, 0x87, 0xac, 0xa0, 0x88, 0xcd, 0x20, 0x3d,
+  0x88, 0x6f, 0xac, 0x29, 0x2e, 0xcc, 0x7d, 0xa7, 0x09, 0x16, 0xc0, 0xcc,
+  0x55, 0x43, 0x19, 0xdc, 0x5e, 0xc4, 0xe5, 0x7c, 0xfb, 0x50, 0x01, 0x41,
+  0xe1, 0x70, 0x84, 0x3e, 0x60, 0x88, 0x05, 0x27, 0x4b, 0x6c, 0x59, 0x9a,
+  0x01, 0x50, 0xec, 0x74, 0x6a, 0x98, 0x57, 0xfe, 0xf5, 0x63, 0xc3, 0x60,
+  0x55, 0x23, 0x33, 0xf9, 0x2d, 0xf0, 0x68, 0xff, 0xad, 0x61, 0xdb, 0x5e,
+  0xdb, 0x0c, 0x54, 0x68, 0x8c, 0x4b, 0x64, 0x94, 0x3c, 0xa8, 0xb1, 0x31,
+  0x61, 0xf3, 0xb3, 0xed, 0x8f, 0xd5, 0x07, 0x27, 0xbf, 0xa3, 0xa2, 0x42,
+  0x4a, 0xa1, 0x5e, 0xc9, 0xb3, 0x9a, 0x0f, 0xbb, 0xf7, 0xc7, 0x4d, 0x0b,
+  0xee, 0xbd, 0xce, 0x9e, 0x8c, 0x14, 0x7e, 0x06, 0x6e, 0x6d, 0x9b, 0xdd,
+  0x22, 0xc6, 0xc2, 0x62, 0xa5, 0x45, 0xc1, 0xe1, 0x97, 0xe2, 0x50, 0x25,
+  0xcc, 0x9b, 0xc4, 0x5d, 0x2d, 0x45, 0x10, 0xad, 0xa8, 0x4f, 0x27, 0xc3,
+  0x1a, 0x2c, 0xef, 0x38, 0x2d, 0xa7, 0xaf, 0xe5, 0x23, 0x7a, 0x8f, 0xbf,
+  0x9c, 0xd0, 0xb6, 0x31, 0x5c, 0xaa, 0xd2, 0x8c, 0xd8, 0x91, 0x00, 0xa1,
+  0x8b, 0x4d, 0x3e, 0x27, 0x22, 0x6c, 0x0f, 0x64, 0x95, 0x89, 0xa6, 0x29,
+  0x90, 0xf9, 0xa9, 0x24, 0x24, 0xb8, 0x71, 0x56, 0x7a, 0xc5, 0xa9, 0x26,
+  0x9f, 0xf6, 0x2a, 0xa6, 0xf1, 0xca, 0x2a, 0x17, 0x14, 0x8c, 0x8d, 0xf2,
+  0x44, 0x7d, 0x49, 0x4e, 0x9b, 0x4f, 0xef, 0x72, 0x7e, 0xe8, 0x0f, 0x45,
+  0xb3, 0x3d, 0x61, 0xf5, 0x9d, 0x3f, 0x9a, 0xe3, 0x93, 0xdd, 0x3d, 0x02,
+  0x84, 0x7d, 0xd4, 0x84, 0xa8, 0x23, 0xe9, 0x43, 0xb6, 0x66, 0xf2, 0xb7,
+  0x35, 0xcf, 0xa3, 0x2f, 0xbe, 0x48, 0x0e, 0xaa, 0xfe, 0xe9, 0x7e, 0xb0,
+  0x4d, 0xb3, 0x6b, 0x69, 0xdc, 0xef, 0x20, 0xec, 0xce, 0x6c, 0xad, 0x7a,
+  0x20, 0x35, 0xf2, 0xfd, 0x09, 0xe1, 0xdb, 0xca, 0x2a, 0x55, 0xf7, 0x60,
+  0xca, 0xf3, 0x85, 0x12, 0xe6, 0x05, 0x4f, 0xc8, 0x6e, 0x76, 0xda, 0x5f,
+  0x45, 0x1e, 0xed, 0xdf, 0x57, 0x4c, 0xeb, 0x7e, 0x28, 0xf7, 0x39, 0xc4,
+  0xd0, 0x10, 0x32, 0xa9, 0xcc, 0x25, 0xd9, 0x0b, 0x8c, 0x8a, 0xf6, 0x6c,
+  0x84, 0xde, 0x09, 0x8c, 0xf6, 0xa4, 0x95, 0xb3, 0x65, 0x5e, 0x49, 0x36,
+  0x8c, 0x51, 0x85, 0x62, 0xcc, 0xe6, 0x2a, 0x3d, 0xdc, 0x68, 0x08, 0x41,
+  0x73, 0x18, 0x74, 0x10, 0xe5, 0x18, 0xfa, 0xbe, 0x2f, 0xaa, 0x98, 0x3c,
+  0x7c, 0x44, 0x43, 0x3f, 0xd6, 0x27, 0xd3, 0x28, 0xf0, 0x2b, 0xeb, 0xf2,
+  0x46, 0xfc, 0xf6, 0x3f, 0xc7, 0xa8, 0xc0, 0xf0, 0x17, 0xef, 0x35, 0xde,
+  0x55, 0x30, 0xef, 0xf7, 0x7b, 0x57, 0xf3, 0x9f, 0x00, 0xb5, 0x49, 0x1e,
+  0xc4, 0x6a, 0xea, 0x0e, 0x40, 0x95, 0x47, 0x55, 0x32, 0x4f, 0x4f, 0x24,
+  0x5a, 0x10, 0xaa, 0x1f, 0x5b, 0x9b, 0xc1, 0xb3, 0xaa, 0xa3, 0x40, 0x32,
+  0x56, 0x80, 0xbf, 0x38, 0xbc, 0x89, 0xad, 0xa8, 0x0e, 0x8f, 0x8e, 0x14,
+  0x17, 0x5a, 0x9b, 0x25, 0x85, 0x85, 0xa7, 0x43, 0xc8, 0x19, 0x21, 0xf9,
+  0xa3, 0xdc, 0xb9, 0xc8, 0x70, 0x7b, 0xc8, 0x42, 0x38, 0x50, 0xb9, 0xcf,
+  0x90, 0x6e, 0x88, 0x7f, 0x5a, 0x56, 0xc8, 0xd7, 0x84, 0x7b, 0x69, 0xe1,
+  0x31, 0x6d, 0xe9, 0xc7, 0x7f, 0x39, 0x78, 0x52, 0xa2, 0x0c, 0xc7, 0x3b,
+  0x89, 0x05, 0x9d, 0x66, 0xc6, 0xea, 0x48, 0x75, 0xa5, 0xd6, 0x89, 0x8e,
+  0x47, 0xdf, 0x81, 0x28, 0x94, 0xc7, 0x98, 0xd4, 0x1c, 0x6f, 0x95, 0xdd,
+  0x20, 0x74, 0xe9, 0xde, 0xb5, 0x3b, 0x87, 0xa1, 0x1a, 0x1e, 0xee, 0xc7,
+  0xbc, 0xa4, 0x12, 0x30, 0x92, 0x60, 0x9f, 0x0d, 0x4d, 0x23, 0x1f, 0xa0,
+  0xea, 0x07, 0x84, 0x10, 0xb3, 0xd3, 0x2a, 0x2f, 0x27, 0xdb, 0x27, 0x76,
+  0xb8, 0x43, 0xe2, 0x9a, 0xfc, 0x9b, 0x81, 0x43, 0xd2, 0xbc, 0xc2, 0xbb,
+  0x40, 0xbd, 0xe8, 0x10, 0xd5, 0xca, 0xd2, 0x10, 0x5e, 0x18, 0xfe, 0x45,
+  0x1d, 0xc2, 0xf9, 0x99, 0x50, 0xbe, 0x7e, 0xca, 0x1a, 0x45, 0x17, 0x99,
+  0x03, 0x9d, 0x2b, 0x68, 0xb7, 0x76, 0x3e, 0x68, 0x41, 0x81, 0x6d, 0xe3,
+  0x77, 0xbe, 0x4e, 0xc9, 0x41, 0xb7, 0x8a, 0xb7, 0xa7, 0x59, 0xfa, 0x04,
+  0x7b, 0xde, 0xd0, 0x3f, 0x7a, 0x57, 0xa3, 0xf1, 0x9e, 0x0a, 0x66, 0x98,
+  0xb0, 0xc1, 0xc2, 0xb4, 0x7a, 0x3b, 0x2f, 0x54, 0x3b, 0x66, 0xe6, 0x6b,
+  0xc5, 0x2c, 0xa1, 0xb1, 0xd2, 0xee, 0xd8, 0x30, 0xf3, 0xa9, 0x2f, 0xe8,
+  0xf0, 0x3e, 0xd8, 0x2b, 0x9a, 0x75, 0x58, 0x59, 0xc7, 0x3a, 0x39, 0xa1,
+  0x58, 0x19, 0x87, 0x3f, 0x90, 0xe5, 0xb3, 0xb6, 0xfe, 0x39, 0x34, 0xc8,
+  0x4c, 0x21, 0x7b, 0x96, 0x9e, 0x3e, 0x38, 0x48, 0x3e, 0xaa, 0x0b, 0x1b,
+  0xbf, 0xa9, 0x45, 0x83, 0x8e, 0x38, 0xf3, 0x96, 0xb8, 0x24, 0x23, 0xc1,
+  0xd3, 0x5c, 0x77, 0xeb, 0x6f, 0xf8, 0x16, 0xa8, 0x94, 0xbc, 0xab, 0x2a,
+  0x20, 0x52, 0xec, 0x9a, 0x5c, 0xd9, 0x99, 0xb4, 0x84, 0x50, 0x90, 0xbb,
+  0xf7, 0x80, 0x51, 0x61, 0x95, 0x61, 0xaa, 0x03, 0xd6, 0xd4, 0xa9, 0x73,
+  0x86, 0x3b, 0xf1, 0x7e, 0xca, 0x7c, 0xfb, 0xf9, 0x33, 0xe6, 0x96, 0x66,
+  0x13, 0x7a, 0x35, 0xae, 0x71, 0xcc, 0x13, 0x4b, 0x5e, 0x73, 0xbd, 0xf8,
+  0xf2, 0x5e, 0x51, 0x5c, 0x50, 0x09, 0x3c, 0x59, 0xfa, 0xd0, 0xd4, 0x8e,
+  0xe0, 0x21, 0xb4, 0x97, 0xa4, 0x7d, 0xeb, 0x17, 0xef, 0x4c, 0xf4, 0xd0,
+  0x0b, 0xf5, 0x42, 0xaf, 0x07, 0x8e, 0xe9, 0x5f, 0x2b, 0xce, 0xb4, 0xf9,
+  0x17, 0xea, 0x9e, 0x83, 0x94, 0xf5, 0x1d, 0x49, 0x91, 0x42, 0x65, 0x84,
+  0x77, 0x56, 0xc0, 0x4f, 0x67, 0x37, 0xed, 0xa3, 0x18, 0x22, 0x69, 0xd7,
+  0x40, 0xfb, 0x39, 0xfd, 0xc2, 0x37, 0x68, 0x98, 0x30, 0x6a, 0x33, 0xad,
+  0x2f, 0xf2, 0x3d, 0x5c, 0xe0, 0x4a, 0x29, 0x38, 0xe5, 0xe0, 0x5c, 0xb3,
+  0x79, 0xd5, 0x8c, 0xcd, 0x25, 0xad, 0xab, 0xd3, 0x75, 0x2f, 0x54, 0x3a,
+  0xfe, 0x8e, 0x0d, 0x3f, 0xfa, 0x6e, 0xcc, 0x80, 0x26, 0x08, 0x7f, 0xa3,
+  0x9e, 0xba, 0x80, 0x4c, 0x36, 0x4c, 0x4d, 0x74, 0xc0, 0x3f, 0xd1, 0xb3,
+  0xad, 0xa3, 0xc8, 0xcf, 0x7a, 0x73, 0xb7, 0x09, 0x67, 0x3b, 0xf8, 0x6f,
+  0x7a, 0x26, 0x57, 0x65, 0x83, 0xcf, 0x18, 0x3c, 0x86, 0x2c, 0xb4, 0xcd,
+  0xe8, 0x74, 0xfa, 0x63, 0xd4, 0xb4, 0x36, 0x36, 0xd9, 0xb0, 0xeb, 0x29,
+  0xe3, 0x3a, 0x7f, 0x06, 0x80, 0x29, 0x4c, 0x86, 0x94, 0x49, 0x42, 0x22,
+  0x57, 0x0c, 0x4f, 0xfa, 0x08, 0xb5, 0x12, 0xbe, 0x76, 0xf5, 0x52, 0x10,
+  0x47, 0x48, 0x1f, 0xbd, 0x87, 0x51, 0xd1, 0x39, 0xc8, 0x50, 0x7c, 0xfa,
+  0x92, 0xe7, 0xea, 0x40, 0x55, 0xf7, 0x61, 0x9f, 0x19, 0xc2, 0x65, 0x23,
+  0x6d, 0xe0, 0x41, 0xb9, 0x5b, 0xb7, 0x8c, 0x9a, 0xee, 0x50, 0x53, 0xa6,
+  0xe8, 0x80, 0x14, 0x8c, 0xeb, 0x2a, 0xc1, 0x44, 0xda, 0x6d, 0x90, 0x96,
+  0xb8, 0xf1, 0xc4, 0x0d, 0xf1, 0xd8, 0x8e, 0xd0, 0xb4, 0x73, 0x49, 0xe5,
+  0x34, 0xab, 0x00, 0x0f, 0x0b, 0x7b, 0xc3, 0x7d, 0x53, 0x1d, 0x75, 0xef,
+  0x27, 0xfb, 0xdf, 0x29, 0xfd, 0x61, 0xb3, 0x71, 0x25, 0xac, 0x62, 0x2d,
+  0xaa, 0x1a, 0x2a, 0x55, 0x6e, 0x11, 0x50, 0x4b, 0x2c, 0x3d, 0xd8, 0x8d,
+  0xb9, 0xcb, 0xc2, 0x21, 0x77, 0x4e, 0x40, 0x56, 0x45, 0xc1, 0x07, 0x79,
+  0xdb, 0x66, 0x2f, 0x6d, 0x4d, 0xac, 0x2b, 0x2d, 0x29, 0xff, 0xa1, 0x79,
+  0x10, 0x03, 0x72, 0x09, 0xe8, 0xe9, 0x31, 0xd5, 0x6f, 0x42, 0x97, 0x3e,
+  0x09, 0xf0, 0x4a, 0xb5, 0xe6, 0x73, 0x94, 0xc1, 0xb4, 0x94, 0xa1, 0xd9,
+  0x44, 0xe8, 0x50, 0xe2, 0x6c, 0x82, 0xea, 0x89, 0x06, 0xd6, 0x44, 0xe9,
+  0x53, 0xd0, 0x5c, 0xcf, 0x0a, 0x3b, 0x89, 0x50, 0x8d, 0x1e, 0x44, 0xbd,
+  0xb2, 0xb6, 0x68, 0xf4, 0xbb, 0x2d, 0x65, 0x95, 0x5c, 0xb5, 0xdc, 0xe2,
+  0xb7, 0x70, 0x86, 0xfd, 0x5b, 0xcc, 0x99, 0x41, 0x5d, 0x22, 0x11, 0xa8,
+  0x22, 0x8c, 0xc1, 0x73, 0x70, 0x5b, 0x31, 0x11, 0xc3, 0xdb, 0x7f, 0xca,
+  0x2b, 0xcb, 0xeb, 0x7d, 0x2b, 0xd1, 0x32, 0xe6, 0xf8, 0x22, 0x22, 0x69,
+  0xea, 0xb7, 0xcd, 0x25, 0x22, 0x33, 0x2f, 0x83, 0x3f, 0xb7, 0x2d, 0x22,
+  0x61, 0x24, 0x01, 0xb3, 0xe9, 0xd0, 0xf6, 0x21, 0xe6, 0x2d, 0xea, 0x0e,
+  0x53, 0x7a, 0x97, 0xcd, 0xcf, 0x6c, 0xe2, 0xd5, 0x8b, 0xdc, 0xe9, 0xe0,
+  0xfd, 0xd0, 0xa0, 0xbf, 0xa5, 0x39, 0x7e, 0xd4, 0xdd, 0xfe, 0x1a, 0xce,
+  0xb0, 0x85, 0x8e, 0xc1, 0x05, 0x36, 0xf9, 0xd3, 0x6a, 0x35, 0xab, 0x53,
+  0x1d, 0xc2, 0xa0, 0xfa, 0xc2, 0x6b, 0x8b, 0x8c, 0x2d, 0x5d, 0x5f, 0xb8,
+  0x18, 0x43, 0x53, 0xb9, 0x5d, 0x08, 0x07, 0xd1, 0x8f, 0xc6, 0xe9, 0xef,
+  0xaf, 0x3b, 0xbb, 0x60, 0xaa, 0x28, 0xac, 0x4c, 0x03, 0x5d, 0xc8, 0x05,
+  0xba, 0x82, 0x5c, 0xcb, 0xc6, 0x2a, 0x13, 0xf6, 0xfc, 0x54, 0xf3, 0xea,
+  0x20, 0xce, 0xcf, 0x05, 0x00, 0xb9, 0x98, 0x0b, 0x9f, 0x96, 0xe0, 0x7b,
+  0x85, 0x8e, 0x43, 0xbd, 0xf2, 0x3e, 0x17, 0x19, 0x8d, 0x23, 0x72, 0x85,
+  0x93, 0xdf, 0x3a, 0x21, 0x94, 0x34, 0x32, 0x53, 0x02, 0xba, 0x34, 0xba,
+  0xa5, 0x2e, 0x5c, 0x0b, 0x1e, 0x3f, 0xa9, 0x83, 0x92, 0x63, 0x0b, 0x12,
+  0xc9, 0xf8, 0x35, 0xef, 0x78, 0xa0, 0xee, 0xc0, 0xbb, 0x14, 0xd4, 0x68,
+  0x39, 0xa0, 0x00, 0x38, 0x77, 0x1e, 0xfc, 0x94, 0xb4, 0xd4, 0xc1, 0x98,
+  0xe1, 0x43, 0x8e, 0xc6, 0xa7, 0x58, 0x33, 0x1b, 0xa3, 0x73, 0xf7, 0x4c,
+  0x49, 0x9d, 0xc0, 0xb8, 0xbf, 0x30, 0x84, 0x2e, 0x5a, 0x8b, 0x6c, 0xa5,
+  0xde, 0xb5, 0x6a, 0x79, 0x67, 0x54, 0xe7, 0x8c, 0x3c, 0xf3, 0x70, 0x1b,
+  0x3d, 0x35, 0x23, 0x65, 0x17, 0xc9, 0x74, 0x11, 0x0b, 0xb1, 0x64, 0xc0,
+  0x65, 0xa3, 0x9e, 0x5a, 0x7b, 0xa2, 0xda, 0xe1, 0xf4, 0xeb, 0xb8, 0x13,
+  0x90, 0x30, 0xc1, 0x72, 0x6a, 0x2a, 0x13, 0xe3, 0x36, 0xe1, 0x05, 0x47,
+  0x56, 0x42, 0xf2, 0x59, 0x44, 0x12, 0x23, 0x27, 0xe4, 0xfe, 0xae, 0x83,
+  0x39, 0x0f, 0x4c, 0x85, 0x3f, 0xaf, 0x97, 0x2e, 0xae, 0x3c, 0x12, 0x0e,
+  0xfd, 0x5b, 0xfd, 0x8e, 0x58, 0x58, 0x4a, 0xbd, 0x05, 0x98, 0x6b, 0x82,
+  0x03, 0x02, 0x0a, 0x2d, 0x1c, 0x19, 0x0f, 0x95, 0x12, 0x5d, 0x8c, 0x1e,
+  0x7b, 0x49, 0xbb, 0x83, 0xe2, 0xd2, 0x53, 0x60, 0xe1, 0xab, 0xd2, 0x8b,
+  0x02, 0xeb, 0x49, 0x27, 0xd7, 0xda, 0x22, 0xd3, 0x26, 0x6f, 0x3e, 0x5b,
+  0x3f, 0x33, 0xcb, 0xa8, 0x08, 0x98, 0xa6, 0xc5, 0x35, 0xc1, 0x81, 0xc1,
+  0xd6, 0x28, 0xe5, 0xba, 0x50, 0xe9, 0x14, 0x1a, 0x0b, 0x0a, 0x8a, 0x9e,
+  0xa3, 0xaa, 0xbc, 0x3b, 0x38, 0x5b, 0xe0, 0x1f, 0xf6, 0xb8, 0x95, 0x79,
+  0xa4, 0x45, 0x5f, 0xc4, 0x63, 0x86, 0xd0, 0x15, 0xe0, 0x25, 0x6e, 0x5f,
+  0x8d, 0x75, 0x25, 0x67, 0xea, 0xf3, 0x92, 0x33, 0xd1, 0x07, 0xf3, 0x43,
+  0x21, 0x42, 0x40, 0x70, 0x9b, 0x8e, 0x0b, 0x41, 0x54, 0x30, 0x73, 0xd0,
+  0x49, 0xe4, 0x70, 0xf6, 0xd3, 0x7d, 0x59, 0xd6, 0x1f, 0x06, 0xfc, 0x12,
+  0x89, 0x9f, 0x26, 0x09, 0x34, 0xf6, 0x64, 0x56, 0x37, 0x68, 0x59, 0x33,
+  0x9c, 0xa0, 0xfa, 0x65, 0x70, 0xb3, 0xe1, 0x29, 0xd1, 0x5b, 0xaf, 0xe7,
+  0xa5, 0x39, 0x64, 0x38, 0x8b, 0xb1, 0xd6, 0xce, 0xa4, 0xb4, 0xb6, 0xdb,
+  0x01, 0xb4, 0xf9, 0xb7, 0x1f, 0x8f, 0xcd, 0x28, 0xe6, 0x27, 0x47, 0xf2,
+  0x53, 0x1d, 0xea, 0xb4, 0x53, 0xfa, 0xe0, 0x22, 0xea, 0xc5, 0xd2, 0xfc,
+  0x4e, 0x45, 0xcf, 0xef, 0xaa, 0xea, 0xaf, 0x7e, 0x77, 0xe2, 0x39, 0x1c,
+  0x5d, 0x9c, 0x77, 0x7b, 0x71, 0xb5, 0x11, 0xef, 0xc7, 0xf8, 0xba, 0x2b,
+  0x7b, 0x15, 0xfa, 0x2d, 0xd5, 0xd8, 0xe0, 0xee, 0xbe, 0x10, 0xd6, 0xdb,
+  0x47, 0xf1, 0x11, 0xcc, 0x35, 0x4c, 0x2d, 0xa8, 0x12, 0x12, 0x23, 0x78,
+  0x0b, 0xd3, 0xb8, 0x90, 0x8a, 0x1d, 0xc4, 0x90, 0x4b, 0x7e, 0x35, 0xb9,
+  0x9f, 0x5b, 0x68, 0x97, 0x9c, 0x09, 0xc3, 0x0d, 0x0a, 0x20, 0xd9, 0x25,
+  0x07, 0xeb, 0x56, 0xb5, 0xd6, 0x93, 0x31, 0x3d, 0x71, 0x7c, 0x0f, 0x48,
+  0x26, 0x32, 0x0f, 0x1b, 0x43, 0x75, 0xc2, 0xcd, 0xf6, 0xaa, 0x88, 0x38,
+  0x7b, 0xe9, 0xc0, 0x98, 0x51, 0xa4, 0x06, 0x15, 0x7f, 0x11, 0x0b, 0x91,
+  0xcb, 0x59, 0x92, 0x1c, 0xa1, 0x44, 0x63, 0xa4, 0x3a, 0xad, 0xd7, 0x1d,
+  0x9e, 0x63, 0xfb, 0xb9, 0x7d, 0x43, 0x80, 0x79, 0xe8, 0x01, 0xba, 0x08,
+  0x47, 0x78, 0x57, 0xd6, 0x0b, 0x38, 0x94, 0x64, 0xac, 0x64, 0x77, 0xdc,
+  0xb8, 0xa9, 0xa5, 0xa2, 0x62, 0x70, 0x36, 0x4f, 0x39, 0xd9, 0xae, 0x2f,
+  0x15, 0xd3, 0x07, 0xc4, 0x01, 0x03, 0x96, 0x5e, 0x51, 0xa7, 0x15, 0x2a,
+  0x9d, 0x22, 0x74, 0xae, 0x8a, 0xd4, 0xb9, 0x91, 0xed, 0xad, 0xa7, 0x76,
+  0xad, 0x38, 0x33, 0xef, 0x3c, 0xe4, 0xd0, 0x7c, 0x6e, 0x53, 0xae, 0x0c,
+  0x7a, 0xdf, 0x2c, 0x18, 0xeb, 0xc4, 0x8c, 0xfe, 0xab, 0x10, 0xcd, 0xaf,
+  0x8f, 0x88, 0x3f, 0xac, 0xe3, 0x20, 0xed, 0x0c, 0x62, 0x81, 0x2e, 0x12,
+  0xa9, 0xa5, 0xe7, 0xd5, 0x3a, 0xef, 0x40, 0xb4, 0x91, 0x52, 0x4c, 0xfd,
+  0xd5, 0xb8, 0x98, 0x19, 0xcd, 0x1b, 0xa9, 0x17, 0xe7, 0x9a, 0xda, 0x8a,
+  0xb4, 0x8f, 0x1a, 0x5c, 0x78, 0xd2, 0x28, 0x7a, 0xb6, 0x66, 0xac, 0x73,
+  0xd4, 0x11, 0xc0, 0x81, 0xff, 0x71, 0x57, 0x4c, 0x23, 0x90, 0x2a, 0xd8,
+  0x67, 0x7a, 0x6a, 0x58, 0xb7, 0x5b, 0xbe, 0x80, 0x62, 0x17, 0x10, 0x90,
+  0xc1, 0xb7, 0x2c, 0xbe, 0xbe, 0x97, 0x2e, 0x85, 0x36, 0x07, 0x8e, 0x63,
+  0xfc, 0x38, 0xc5, 0x66, 0x20, 0x33, 0x2b, 0xe8, 0x25, 0x25, 0xc1, 0x11,
+  0xba, 0x5b, 0x12, 0xd9, 0x06, 0x4d, 0xfc, 0x49, 0x20, 0x27, 0x6b, 0x79,
+  0x92, 0x8b, 0xde, 0x22, 0x39, 0xf9, 0x2e, 0xc9, 0x1b, 0xb9, 0x97, 0x2f,
+  0xc3, 0x37, 0xf5, 0xa3, 0x6b, 0xd3, 0x3b, 0x94, 0xa5, 0x56, 0xb7, 0x81,
+  0x7c, 0x9d, 0x28, 0xff, 0x57, 0xe7, 0x02, 0xa1, 0xd1, 0x3a, 0x3d, 0xac,
+  0x74, 0x45, 0xb3, 0xab, 0x95, 0xec, 0x68, 0x8a, 0x9c, 0xf7, 0x43, 0xa4,
+  0x14, 0x0d, 0x68, 0x40, 0x5f, 0x7e, 0x25, 0x8a, 0x47, 0x3f, 0x9c, 0xaf,
+  0x88, 0x0b, 0x4a, 0xc0, 0x98, 0xc2, 0x57, 0xf4, 0xde, 0x04, 0x09, 0x37,
+  0x9c, 0x87, 0x83, 0xb6, 0xa5, 0xa8, 0x5e, 0xc4, 0xec, 0x2e, 0xfd, 0xc9,
+  0xf3, 0x85, 0x4f, 0x7d, 0xb8, 0xba, 0x6e, 0x6d, 0xc0, 0xd2, 0x37, 0xb2,
+  0xba, 0x17, 0xad, 0x29, 0xf8, 0x71, 0x74, 0x0c, 0x93, 0x1e, 0x07, 0x34,
+  0xec, 0xc3, 0x5f, 0x15, 0x21, 0x49, 0x0f, 0xa7, 0x7e, 0x72, 0x79, 0x66,
+  0xfd, 0x3e, 0x29, 0xce, 0x12, 0xeb, 0x57, 0x88, 0xd8, 0xcc, 0x14, 0x96,
+  0x33, 0x44, 0x64, 0x6c, 0x34, 0x55, 0xb3, 0x76, 0xc9, 0xa7, 0x3f, 0x7b,
+  0x16, 0x9d, 0x7e, 0x95, 0x4c, 0xfa, 0xc9, 0x46, 0x17, 0x18, 0x18, 0x78,
+  0xe7, 0xfb, 0x6b, 0x86, 0xf4, 0x25, 0x3a, 0x0b, 0x4a, 0xcd, 0x1a, 0x51,
+  0xde, 0xa4, 0x45, 0xdd, 0xdb, 0xc9, 0x9f, 0xa9, 0xc3, 0x58, 0xb2, 0x43,
+  0x90, 0x8b, 0xc1, 0x59, 0x47, 0x1a, 0x89, 0xcb, 0x9c, 0x6d, 0x46, 0x1f,
+  0x0d, 0xe9, 0xfa, 0xd8, 0xe9, 0xde, 0xdb, 0xf5, 0x22, 0x9b, 0xe3, 0xef,
+  0xb4, 0x0c, 0xc7, 0x34, 0xd0, 0x2a, 0x0f, 0x0b, 0x8e, 0x11, 0x88, 0x91,
+  0xb7, 0xce, 0x92, 0xf2, 0x83, 0x3c, 0xd2, 0xf8, 0x42, 0x32, 0x82, 0x48,
+  0xad, 0x67, 0x44, 0x45, 0x59, 0xac, 0x57, 0xb7, 0x7e, 0x1b, 0xce, 0xca,
+  0x51, 0xfb, 0x1b, 0x12, 0x39, 0xaf, 0xe4, 0xfb, 0xdb, 0xc5, 0xb7, 0xcc,
+  0x4a, 0x5d, 0xc4, 0xa6, 0x95, 0xaf, 0x5b, 0x39, 0x4e, 0x47, 0xc5, 0x50,
+  0x67, 0x92, 0x84, 0x62, 0xeb, 0x81, 0x77, 0x24, 0xda, 0x27, 0x64, 0xfe,
+  0xe4, 0x83, 0x40, 0x33, 0xc8, 0xb1, 0xaa, 0xbb, 0xbf, 0x13, 0xc3, 0x18,
+  0x9a, 0x24, 0x06, 0xbd, 0x0a, 0x07, 0xa3, 0xd6, 0xd8, 0x38, 0x32, 0x73,
+  0x8d, 0x40, 0x5f, 0xc2, 0x3f, 0xeb, 0xd2, 0x0e, 0x3d, 0x6d, 0xf5, 0x72,
+  0x5a, 0xa6, 0x56, 0x22, 0x41, 0xe5, 0x0c, 0xb5, 0x0c, 0xda, 0xcd, 0x46,
+  0xbc, 0xd7, 0x98, 0x89, 0x5e, 0x97, 0x54, 0x4f, 0x4b, 0xc0, 0x27, 0x51,
+  0x0d, 0x20, 0x3f, 0x55, 0x78, 0xdc, 0x5a, 0x79, 0x08, 0xed, 0xd3, 0xaa,
+  0x9c, 0xc3, 0x7d, 0x75, 0x76, 0x81, 0xa4, 0xe0, 0xfc, 0x90, 0x6a, 0x83,
+  0x37, 0x53, 0xb8, 0xb5, 0xd9, 0x7a, 0xd9, 0x7d, 0xeb, 0x50, 0x72, 0xd3,
+  0x5d, 0xed, 0x22, 0xfb, 0x6e, 0x67, 0x79, 0x9c, 0xb9, 0xea, 0xac, 0xc1,
+  0x6d, 0x68, 0xf5, 0x12, 0xaa, 0x54, 0x90, 0xd8, 0x7f, 0xe0, 0xf4, 0xdd,
+  0x3b, 0x88, 0xe3, 0xec, 0x7f, 0x1c, 0x2b, 0x08, 0x32, 0xc6, 0x05, 0x53,
+  0xae, 0xa4, 0x46, 0xa7, 0xf3, 0xe6, 0xcb, 0xe7, 0x04, 0xc1, 0x52, 0xa7,
+  0xfe, 0x68, 0x55, 0xc1, 0x91, 0xb2, 0x9a, 0x3b, 0x05, 0xc6, 0xae, 0x15,
+  0x89, 0xdc, 0xb2, 0x0b, 0xeb, 0x19, 0x96, 0x62, 0xe3, 0x67, 0xc5, 0xdc,
+  0xf5, 0xe8, 0xbe, 0x16, 0xbe, 0xf6, 0xe4, 0x0b, 0xeb, 0x99, 0x82, 0x65,
+  0x0a, 0x97, 0xf5, 0xc2, 0x19, 0x1c, 0x1e, 0xa1, 0xf1, 0x75, 0x06, 0xa7,
+  0xdb, 0x97, 0x68, 0x94, 0x0b, 0xea, 0xc4, 0xda, 0x70, 0x72, 0x3e, 0x9f,
+  0xfc, 0x20, 0x4e, 0x54, 0xfb, 0x18, 0x01, 0x74, 0x9a, 0x24, 0x1d, 0x20,
+  0x3a, 0x25, 0xe1, 0xd8, 0xaf, 0xe3, 0x76, 0xe0, 0x47, 0x53, 0x86, 0xd9,
+  0x3f, 0xc2, 0x46, 0x4a, 0x02, 0x05, 0xaf, 0xbf, 0x49, 0x12, 0x22, 0x66,
+  0x81, 0xf5, 0x9d, 0xdd, 0xae, 0x7f, 0xf5, 0x99, 0x2b, 0x89, 0xa6, 0x25,
+  0x30, 0xd6, 0xb3, 0x00, 0xa4, 0x62, 0xd2, 0xb3, 0x8e, 0xdd, 0xc2, 0x04,
+  0x62, 0x17, 0x44, 0xa3, 0x62, 0xf7, 0x8c, 0x56, 0x00, 0x4f, 0x98, 0xfe,
+  0x7a, 0xdf, 0x9d, 0x47, 0xab, 0xc9, 0xb7, 0x0e, 0x0d, 0x02, 0x54, 0x6a,
+  0xab, 0xf9, 0x22, 0xb9, 0x11, 0xb3, 0xec, 0x17, 0xb9, 0xc9, 0x86, 0xf6,
+  0x66, 0x97, 0x1f, 0xa9, 0x38, 0xd8, 0x66, 0x8e, 0x41, 0xd9, 0x9a, 0x35,
+  0xfd, 0x19, 0x64, 0xcb, 0x1e, 0x77, 0x80, 0xd4, 0x6d, 0xea, 0x00, 0xf5,
+  0x9b, 0xc9, 0x55, 0xef, 0x80, 0x14, 0x79, 0xab, 0xf5, 0x5e, 0xb0, 0x4b,
+  0x73, 0x52, 0x17, 0x2a, 0xd7, 0x68, 0x79, 0x6a, 0xf1, 0xc0, 0x04, 0xce,
+  0x33, 0xd2, 0x18, 0xad, 0x39, 0x4d, 0xda, 0x40, 0x49, 0xce, 0x00, 0xca,
+  0x89, 0xf3, 0xbd, 0x13, 0xe5, 0x7a, 0x03, 0x99, 0xa3, 0x4b, 0x29, 0xcd,
+  0x18, 0xbd, 0xc8, 0xd7, 0x30, 0xcd, 0x4f, 0x65, 0xdc, 0xca, 0xc2, 0x9f,
+  0x84, 0x2d, 0x83, 0xf6, 0x69, 0x0d, 0x55, 0x08, 0x5b, 0x6c, 0x87, 0x53,
+  0xda, 0x13, 0x2a, 0x34, 0xf7, 0xea, 0x13, 0xec, 0x14, 0x90, 0xe8, 0x94,
+  0xdc, 0xa6, 0xcf, 0xe9, 0x9b, 0x99, 0x63, 0x48, 0xf3, 0x34, 0xac, 0xf2,
+  0x78, 0x76, 0x90, 0x46, 0xd8, 0x7d, 0x2b, 0xc1, 0xd2, 0xdd, 0xf1, 0xda,
+  0x23, 0xc8, 0x3c, 0xd6, 0x58, 0x2e, 0xaf, 0x2c, 0xf6, 0x8a, 0xb3, 0x93,
+  0x0e, 0x4f, 0x82, 0x7e, 0x26, 0x88, 0x0b, 0x3b, 0xe4, 0xe9, 0x85, 0x2b,
+  0x99, 0xca, 0xdc, 0xad, 0x84, 0x26, 0xee, 0x35, 0x6a, 0x50, 0xc4, 0xae,
+  0x95, 0x30, 0x0d, 0x09, 0xef, 0xdb, 0x4b, 0x4c, 0x9b, 0x0f, 0x04, 0x0a,
+  0x6e, 0xf0, 0x92, 0x43, 0x06, 0xb9, 0x73, 0x16, 0x79, 0x15, 0x3f, 0x08,
+  0xcc, 0x78, 0x2b, 0x35, 0x8c, 0xa3, 0x2a, 0x6e, 0xf6, 0x5c, 0x61, 0xf3,
+  0xc6, 0x4b, 0x8a, 0xbc, 0x75, 0x1f, 0x4a, 0x00, 0x4e, 0x5f, 0x9e, 0x24,
+  0x03, 0x2d, 0x86, 0x26, 0xa7, 0x78, 0xb7, 0xc3, 0x6f, 0x74, 0x6d, 0x32,
+  0x34, 0xcd, 0x37, 0x42, 0x56, 0x24, 0x83, 0x7f, 0xa8, 0x1b, 0x9b, 0xae,
+  0x97, 0x55, 0x2d, 0xba, 0x67, 0x75, 0x67, 0xca, 0xa5, 0xd1, 0x6e, 0xd6,
+  0x48, 0xaf, 0xeb, 0x71, 0xdc, 0x31, 0xfb, 0x3b, 0xe3, 0x7c, 0x64, 0x9d,
+  0xe5, 0x5a, 0xe4, 0x87, 0x6e, 0xed, 0xed, 0xca, 0xb6, 0x51, 0xfd, 0x73,
+  0xef, 0x7c, 0xbc, 0x15, 0x69, 0xfd, 0x9f, 0x1f, 0x0f, 0x17, 0x1a, 0x8d,
+  0x73, 0x61, 0x7d, 0xf1, 0x09, 0x97, 0x06, 0xbe, 0x90, 0x38, 0xdf, 0xac,
+  0xfd, 0xe2, 0x87, 0xe8, 0xc1, 0xc3, 0x9b, 0x83, 0x79, 0xa6, 0xdd, 0x6d,
+  0x58, 0x4d, 0x03, 0x26, 0x99, 0x1d, 0x2e, 0x47, 0xb0, 0x20, 0x3f, 0x84,
+  0xaf, 0xfa, 0xf9, 0xf1, 0x62, 0xd5, 0x80, 0xb8, 0x6e, 0x69, 0x7e, 0x53,
+  0x80, 0x05, 0xc4, 0x2f, 0xba, 0xed, 0x0d, 0x75, 0xca, 0x01, 0xde, 0x6e,
+  0xf0, 0xd3, 0x23, 0x9b, 0x1e, 0xae, 0x02, 0x57, 0xeb, 0x40, 0xf2, 0x55,
+  0x89, 0xd7, 0x70, 0xd6, 0x45, 0xe7, 0x67, 0xd3, 0x3e, 0x21, 0xda, 0xb6,
+  0xae, 0xe5, 0xe6, 0x82, 0x0c, 0x3e, 0x3e, 0xe8, 0xbe, 0x85, 0x3d, 0x79,
+  0x75, 0x90, 0x9b, 0x9c, 0x01, 0x88, 0x8d, 0x5a, 0x34, 0x1d, 0x10, 0x83,
+  0x85, 0x08, 0xea, 0x88, 0x51, 0x29, 0xea, 0x95, 0x40, 0x2f, 0x16, 0x90,
+  0xec, 0x1b, 0xb7, 0x22, 0x81, 0xcb, 0x1b, 0x8c, 0xf5, 0xe2, 0xfd, 0xcb,
+  0x1f, 0xe7, 0xb0, 0x4b, 0x4d, 0x7c, 0x7d, 0x11, 0x17, 0x20, 0x89, 0x8b,
+  0x4a, 0x80, 0xa3, 0x10, 0x6f, 0x68, 0x09, 0x01, 0x68, 0x86, 0x3b, 0x2a,
+  0xfb, 0x48, 0x80, 0xa0, 0xd1, 0xdb, 0x3f, 0x91, 0x44, 0x58, 0x83, 0xc6,
+  0x85, 0x77, 0x6b, 0xb1, 0x35, 0x4a, 0x03, 0xa2, 0xcf, 0x2f, 0xbd, 0xcd,
+  0x4b, 0xfa, 0x5a, 0x5e, 0x8f, 0x8b, 0x95, 0x62, 0xaa, 0xe7, 0x3b, 0x54,
+  0xb1, 0xec, 0xd5, 0x85, 0x4f, 0xd9, 0x59, 0x56, 0xb4, 0xec, 0xc1, 0x21,
+  0xc5, 0xa6, 0x35, 0x1d, 0x7b, 0x60, 0xe1, 0xb1, 0x7c, 0x8f, 0x47, 0xa1,
+  0xf1, 0x13, 0x4b, 0xaf, 0x23, 0xcb, 0x5e, 0xe2, 0x74, 0x16, 0x16, 0x96,
+  0x3b, 0xff, 0xbf, 0x26, 0x5f, 0x68, 0xd5, 0x64, 0xc6, 0x62, 0xaf, 0x4a,
+  0xfc, 0x0f, 0x27, 0x3e, 0x96, 0x5b, 0x7c, 0xeb, 0x78, 0x81, 0x3c, 0x0a,
+  0x63, 0xd5, 0x6b, 0x3c, 0xa9, 0xd4, 0x37, 0x03, 0x3b, 0x5c, 0x62, 0x7a,
+  0xd5, 0x69, 0xbe, 0x44, 0x50, 0xab, 0x0a, 0x54, 0x31, 0x5c, 0x44, 0x52,
+  0xfe, 0xde, 0xbb, 0x10, 0x80, 0x79, 0xb2, 0x69, 0xc5, 0x75, 0x8b, 0xba,
+  0x1d, 0x4d, 0x2d, 0xfa, 0xc8, 0x0e, 0xc0, 0xaf, 0xc2, 0x31, 0xa1, 0x53,
+  0xc7, 0x9f, 0x3e, 0x1f, 0x38, 0x8c, 0x1e, 0x00, 0x78, 0x76, 0xb6, 0xb5,
+  0x68, 0xa4, 0x68, 0xe9, 0xba, 0xda, 0x97, 0xca, 0x16, 0xde, 0xba, 0xa1,
+  0xb7, 0x17, 0x26, 0xb3, 0x4b, 0x4b, 0x4e, 0x21, 0x9c, 0xaf, 0xce, 0xf0,
+  0x52, 0x41, 0x13, 0x87, 0x75, 0xc4, 0xd7, 0x34, 0x0c, 0x2d, 0xfe, 0xc1,
+  0xb6, 0x60, 0x84, 0xd2, 0x57, 0xc2, 0xb2, 0x6c, 0xa6, 0x97, 0x51, 0xea,
+  0x49, 0x07, 0x7d, 0xac, 0x15, 0x75, 0x71, 0x67, 0x2c, 0xdf, 0x09, 0x0c,
+  0x63, 0x38, 0x6a, 0x25, 0xf3, 0x9b, 0x5d, 0x5d, 0x63, 0xe7, 0x20, 0xa3,
+  0xf5, 0x6f, 0x8c, 0x77, 0x91, 0xb0, 0x6d, 0xad, 0x01, 0x1d, 0x40, 0x65,
+  0xcd, 0x31, 0xbf, 0xb2, 0x0a, 0x1f, 0xf9, 0xb0, 0x34, 0x7f, 0x6a, 0xfe,
+  0xca, 0x2e, 0x28, 0xc4, 0x5b, 0xdb, 0xa9, 0xd4, 0xdc, 0xe6, 0x3a, 0x0a,
+  0xeb, 0xe2, 0xc5, 0xb8, 0xbe, 0xad, 0x8d, 0x7d, 0xa2, 0x5e, 0x88, 0xad,
+  0xb8, 0xda, 0x41, 0x12, 0x1f, 0xc5, 0x85, 0xa1, 0x83, 0x3d, 0xc7, 0xbb,
+  0x6d, 0x55, 0x63, 0xd0, 0x8b, 0x06, 0x76, 0x96, 0xf5, 0x0b, 0xd9, 0x2f,
+  0x45, 0xf4, 0x9b, 0xc8, 0x18, 0xba, 0xbd, 0x30, 0xdc, 0x4d, 0x47, 0xde,
+  0xbc, 0xc0, 0xc0, 0xca, 0x9f, 0xd7, 0xda, 0xcb, 0xd8, 0xdd, 0x7e, 0x98,
+  0x25, 0xfd, 0x9f, 0xa4, 0x22, 0x5d, 0x4b, 0x63, 0x1b, 0xfa, 0x78, 0xdb,
+  0x3d, 0x39, 0xcc, 0x26, 0x00, 0x70, 0x0e, 0xac, 0xf7, 0x30, 0xc0, 0x8c,
+  0x97, 0xbe, 0x57, 0xeb, 0x1a, 0xc0, 0xfd, 0x4c, 0x81, 0x69, 0x54, 0x1b,
+  0xd4, 0x8c, 0xb2, 0xe7, 0xf0, 0x5f, 0x0e, 0x46, 0x95, 0x7a, 0x2b, 0x0c,
+  0x69, 0x37, 0x89, 0x45, 0x6a, 0xb2, 0x9f, 0xa8, 0x99, 0xd2, 0x6c, 0xa0,
+  0x9d, 0xc0, 0x36, 0x65, 0x2f, 0x37, 0xe3, 0xc8, 0xba, 0x4f, 0xd2, 0x4c,
+  0x69, 0x2e, 0x15, 0x2c, 0x92, 0x13, 0x44, 0x96, 0xa5, 0xe9, 0x90, 0x24,
+  0x0a, 0x94, 0x44, 0x16, 0x6a, 0x8e, 0x4a, 0x7b, 0xf4, 0x65, 0x41, 0xd0,
+  0x4e, 0xf3, 0xf2, 0x6d, 0x8e, 0xc0, 0x70, 0xdf, 0x56, 0x2f, 0x11, 0x80,
+  0x03, 0x42, 0xb5, 0x9c, 0x59, 0xea, 0xe1, 0x2d, 0xc7, 0xd1, 0x29, 0x4a,
+  0xce, 0x78, 0x83, 0x8f, 0x9b, 0xd4, 0x6b, 0x91, 0xd8, 0x7b, 0xd1, 0x03,
+  0xc1, 0xe8, 0x84, 0xbc, 0xca, 0x64, 0xdd, 0xac, 0xdd, 0x39, 0xaf, 0x7c,
+  0x5d, 0x7a, 0x5f, 0xc3, 0x8b, 0x0f, 0xd7, 0x18, 0x43, 0x4a, 0x8e, 0x3f,
+  0x2f, 0x02, 0x91, 0xa2, 0xdc, 0x3e, 0x2c, 0x9c, 0x3b, 0x3c, 0xe3, 0xd4,
+  0x9a, 0xb3, 0x59, 0x43, 0xd4, 0x75, 0x1c, 0x4b, 0x0b, 0xad, 0x84, 0x2d,
+  0xbd, 0x05, 0x66, 0xdb, 0x0a, 0xda, 0x77, 0x75, 0x46, 0x78, 0x99, 0x44,
+  0xdf, 0x12, 0x58, 0xa9, 0x3a, 0x5f, 0x04, 0x18, 0x81, 0xa2, 0x2d, 0xcf,
+  0x9c, 0x35, 0x8d, 0x67, 0x73, 0x9e, 0x8d, 0xe4, 0xc9, 0x9d, 0x15, 0x80,
+  0xe3, 0x36, 0xf9, 0xbd, 0xf2, 0x65, 0xb2, 0x10, 0xa9, 0xe8, 0x2a, 0x03,
+  0x9d, 0x03, 0x11, 0xe5, 0xcc, 0x32, 0x12, 0xef, 0xee, 0x22, 0xa3, 0x0c,
+  0x35, 0x28, 0xc0, 0x17, 0x9b, 0x43, 0x75, 0x5f, 0x2c, 0xbf, 0xeb, 0xc4,
+  0xf2, 0xa0, 0x6e, 0xcb, 0x06, 0x1c, 0x5c, 0xd9, 0xe8, 0x56, 0xaf, 0xe4,
+  0x2c, 0x6a, 0x8a, 0x9e, 0xea, 0x34, 0x60, 0x09, 0x94, 0xe7, 0xb2, 0x50,
+  0x4b, 0xc9, 0xeb, 0xce, 0xd2, 0x7f, 0x1d, 0xc1, 0x22, 0xe1, 0x71, 0x1f,
+  0xac, 0xb7, 0xb9, 0x5c, 0x8e, 0x44, 0xe9, 0x51, 0x58, 0x5c, 0x0e, 0x12,
+  0x34, 0xb5, 0xab, 0xa1, 0x0d, 0xf1, 0xc6, 0x71, 0xf0, 0x51, 0x6f, 0xa8,
+  0x72, 0xde, 0xad, 0x42, 0xe6, 0x39, 0x28, 0xb0, 0x66, 0xf8, 0xcb, 0x09,
+  0xb2, 0x82, 0x5a, 0x02, 0x15, 0xca, 0x17, 0xa9, 0x63, 0xd8, 0xac, 0x18,
+  0x49, 0xf7, 0xfa, 0x6d, 0xad, 0x3f, 0xf5, 0x2a, 0xd2, 0x1a, 0x9e, 0x4f,
+  0xdc, 0xb1, 0xb5, 0x5b, 0x93, 0x59, 0x44, 0x72, 0x0c, 0xf4, 0x7e, 0xe4,
+  0x62, 0x10, 0x64, 0xad, 0x2d, 0xb0, 0x2e, 0xcb, 0xf8, 0xd9, 0xbb, 0xf9,
+  0xfc, 0xc5, 0xe1, 0x31, 0x6e, 0x0e, 0x8b, 0x12, 0x62, 0x25, 0x92, 0xd6,
+  0xb0, 0x0d, 0x78, 0x7e, 0x03, 0x13, 0x65, 0xe0, 0xa3, 0x5d, 0x33, 0xc7,
+  0x04, 0x8b, 0xe7, 0x45, 0xa8, 0x9f, 0xd1, 0x70, 0x27, 0x32, 0x6e, 0x50,
+  0x48, 0x6a, 0xd3, 0x32, 0xcb, 0xca, 0xd5, 0xcd, 0xd4, 0x0a, 0x76, 0x8e,
+  0x6b, 0xb1, 0x73, 0x68, 0x38, 0xf5, 0x73, 0xb2, 0x46, 0x7a, 0xb5, 0xff,
+  0xea, 0x52, 0xc9, 0x5b, 0x56, 0xff, 0xf0, 0x35, 0x4b, 0xae, 0x88, 0x61,
+  0x8a, 0x3c, 0xb9, 0x78, 0x1c, 0x51, 0xaa, 0x5d, 0xaf, 0xe0, 0xe7, 0x8c,
+  0x03, 0x85, 0x6a, 0x1f, 0xca, 0xb9, 0x8c, 0xf4, 0x37, 0xea, 0xae, 0x54,
+  0xf1, 0xb8, 0x4c, 0x94, 0x42, 0xcf, 0x2a, 0x8d, 0x13, 0xef, 0x66, 0xf8,
+  0x1b, 0xbe, 0x5d, 0x9a, 0x24, 0x12, 0xb5, 0xe8, 0xe8, 0x44, 0x6b, 0x95,
+  0xd6, 0xed, 0x98, 0xd8, 0x10, 0xeb, 0x19, 0xe5, 0x42, 0x01, 0xaa, 0x1c,
+  0x6a, 0x62, 0xd2, 0xf0, 0xc3, 0x33, 0x4d, 0xf0, 0x3e, 0x76, 0x8d, 0xec,
+  0xbb, 0xb9, 0xeb, 0x14, 0x77, 0x02, 0x39, 0xb7, 0x75, 0x21, 0x3a, 0xa5,
+  0xef, 0x04, 0xb3, 0x20, 0x50, 0xaf, 0xed, 0x99, 0x0b, 0xec, 0x12, 0x6d,
+  0xad, 0x9f, 0x23, 0x02, 0xc0, 0x01, 0x5a, 0xfe, 0xfc, 0xee, 0xa9, 0xc1,
+  0x23, 0x51, 0x71, 0xb0, 0xe6, 0xee, 0xcc, 0xcd, 0x6a, 0x59, 0xcf, 0xad,
+  0xff, 0x4b, 0x36, 0xbf, 0x2a, 0xaf, 0x56, 0xae, 0xd7, 0x35, 0x47, 0xc4,
+  0x11, 0xef, 0x66, 0x18, 0xd1, 0xec, 0x2a, 0x5c, 0xca, 0xfe, 0x8f, 0x8b,
+  0xa2, 0x80, 0x57, 0x42, 0xe5, 0xa5, 0xb4, 0x7a, 0x34, 0xd0, 0x1b, 0xca,
+  0xb3, 0x7f, 0x2c, 0x54, 0x47, 0x50, 0xf0, 0xdd, 0xde, 0x87, 0xc0, 0x8f,
+  0x3a, 0x79, 0x49, 0x50, 0xe9, 0x4a, 0xe2, 0x74, 0x08, 0x18, 0x61, 0xaa,
+  0x17, 0xe4, 0x44, 0xdf, 0xeb, 0xf8, 0x2f, 0x5f, 0x06, 0x19, 0x06, 0x13,
+  0xec, 0x14, 0x47, 0x04, 0x51, 0x03, 0x55, 0x62, 0x78, 0x73, 0x7d, 0xe9,
+  0x15, 0xff, 0xd3, 0xb2, 0x5c, 0x54, 0x79, 0xca, 0x58, 0x10, 0x86, 0x66,
+  0x4d, 0x6a, 0x73, 0x13, 0x20, 0x60, 0xd1, 0xaa, 0x54, 0xa8, 0xf3, 0x45,
+  0x1c, 0x02, 0x23, 0xc6, 0x43, 0xee, 0xb4, 0xf4, 0xed, 0xa3, 0x59, 0xb7,
+  0xb3, 0x4e, 0xda, 0xdf, 0x5f, 0x12, 0xed, 0xb0, 0x03, 0x93, 0xc7, 0xb7,
+  0xa9, 0x52, 0xdb, 0x91, 0x39, 0x4f, 0x0d, 0x6d, 0x31, 0x08, 0xf5, 0x91,
+  0x90, 0xe5, 0x11, 0xbf, 0x33, 0x4d, 0x3f, 0x7b, 0xc8, 0x46, 0xbf, 0x8f,
+  0x27, 0x61, 0xc3, 0x6c, 0xea, 0xfa, 0xaf, 0xeb, 0x92, 0xd1, 0x86, 0xb4,
+  0x50, 0x64, 0x6c, 0xba, 0xdf, 0x1f, 0xe9, 0xc6, 0x2f, 0xad, 0x8d, 0x95,
+  0xe7, 0xfe, 0xcb, 0xbf, 0xcc, 0xba, 0xbd, 0xcc, 0x62, 0x85, 0x62, 0x7a,
+  0x96, 0x85, 0x02, 0x1c, 0xc1, 0x8f, 0x4b, 0xfc, 0x4f, 0xea, 0x69, 0x8b,
+  0x1c, 0x83, 0x81, 0x34, 0x15, 0x12, 0x16, 0x6f, 0x9c, 0x0e, 0xa4, 0x83,
+  0xb6, 0x28, 0x2f, 0xd7, 0x6d, 0x2e, 0x98, 0x6a, 0xe7, 0x6f, 0x53, 0x83,
+  0x18, 0x43, 0x75, 0x25, 0x97, 0x14, 0x15, 0x8d, 0x2f, 0x7f, 0x72, 0x1a,
+  0x07, 0x42, 0x2a, 0x7a, 0xe4, 0x7e, 0xc4, 0x7a, 0x6a, 0xc9, 0x0f, 0xeb,
+  0x4b, 0x60, 0x56, 0x15, 0x51, 0x23, 0x5d, 0xfa, 0x0e, 0x56, 0x06, 0x35,
+  0x89, 0x89, 0x77, 0x55, 0xd3, 0xd7, 0x22, 0x2f, 0x41, 0xc5, 0x70, 0x3f,
+  0x57, 0x80, 0xc6, 0xab, 0x30, 0x7e, 0xd8, 0x2b, 0xd2, 0xd2, 0xa2, 0xfc,
+  0xf9, 0x32, 0x22, 0x9e, 0x63, 0x67, 0x8a, 0x55, 0xac, 0x4e, 0x66, 0x98,
+  0xe6, 0x20, 0xea, 0xbd, 0x64, 0xe9, 0xd5, 0x06, 0x33, 0x33, 0xbf, 0xe2,
+  0x89, 0x49, 0x91, 0x92, 0x4e, 0xf9, 0xcc, 0x23, 0xad, 0x26, 0x1a, 0xb1,
+  0x01, 0x40, 0x9b, 0x3f, 0x30, 0x5c, 0x88, 0xaf, 0xce, 0x83, 0xc3, 0x45,
+  0x90, 0xdc, 0xa6, 0x20, 0x3e, 0x15, 0x96, 0x25, 0xdf, 0xe1, 0xa6, 0xd6,
+  0x78, 0xaf, 0xda, 0xc0, 0x0c, 0xf1, 0x21, 0x03, 0xf9, 0x7f, 0xb5, 0xfd,
+  0x59, 0x20, 0x3d, 0x73, 0xad, 0xfb, 0x2b, 0x5f, 0x88, 0xbc, 0x17, 0xaf,
+  0x1c, 0xaa, 0x5d, 0x17, 0x8f, 0xb7, 0x60, 0x9c, 0xc7, 0xc4, 0xe4, 0xf4,
+  0xdb, 0xa9, 0x39, 0xb0, 0xd1, 0xb4, 0x6b, 0x4b, 0x20, 0xaf, 0xd5, 0xcc,
+  0xd9, 0x68, 0x17, 0x4c, 0x9a, 0xd4, 0x35, 0x25, 0x17, 0x3b, 0xc3, 0x41,
+  0x7b, 0x05, 0xe9, 0xe8, 0xdd, 0x02, 0x9d, 0x0f, 0x6a, 0xd7, 0xf5, 0xfa,
+  0xae, 0xf2, 0x5b, 0xfe, 0xc4, 0x44, 0x62, 0xd6, 0xc4, 0x8e, 0x4b, 0x28,
+  0x6a, 0x87, 0x3c, 0xe3, 0xf8, 0x01, 0xb5, 0xf9, 0x77, 0x4e, 0x07, 0x8f,
+  0x40, 0x02, 0x72, 0x81, 0xa9, 0x6e, 0xa8, 0x84, 0x1f, 0xfe, 0x2e, 0x06,
+  0x83, 0xb8, 0x14, 0x2b, 0xf8, 0x6e, 0x8b, 0xb2, 0xed, 0xff, 0xc5, 0x90,
+  0x09, 0x86, 0xef, 0xe7, 0x64, 0xb3, 0x3f, 0x10, 0xe1, 0x47, 0xff, 0x4f,
+  0xac, 0x76, 0x45, 0xa8, 0xba, 0xac, 0xab, 0x82, 0x07, 0x86, 0x8a, 0x24,
+  0xf5, 0xc0, 0x01, 0x5f, 0x54, 0x8b, 0xdc, 0xbd, 0xd6, 0x28, 0x05, 0x56,
+  0xfd, 0x13, 0xdf, 0x93, 0x9b, 0x68, 0x03, 0x90, 0x2c, 0x08, 0xcc, 0x0b,
+  0xf9, 0x14, 0x44, 0x84, 0x79, 0x15, 0xab, 0xbc, 0x54, 0x1b, 0x76, 0xe3,
+  0xfa, 0xf8, 0x32, 0xab, 0xf2, 0xcd, 0xed, 0x04, 0x15, 0x94, 0xb4, 0xb3,
+  0xcc, 0x09, 0xf1, 0xb2, 0x35, 0x60, 0x0b, 0x05, 0xa1, 0x31, 0xd6, 0x6d,
+  0xc6, 0x46, 0x6d, 0xe4, 0xe7, 0xbc, 0x5f, 0x3a, 0x72, 0xfd, 0x42, 0xb0,
+  0x0e, 0xbb, 0xd2, 0xeb, 0x50, 0x26, 0x60, 0x38, 0xd6, 0x96, 0x1b, 0x5b,
+  0x9d, 0xcc, 0xb4, 0x98, 0x9f, 0xe8, 0xf2, 0x95, 0xa3, 0x11, 0x9a, 0xcb,
+  0x6d, 0x56, 0x87, 0x4b, 0x95, 0xb9, 0x41, 0xa3, 0x89, 0x2d, 0x2c, 0x29,
+  0xe8, 0x29, 0x86, 0x47, 0x3e, 0x91, 0x2a, 0x59, 0x7d, 0x9c, 0x03, 0x9d,
+  0x2d, 0xff, 0x05, 0x50, 0x21, 0x88, 0x12, 0x55, 0x2b, 0x25, 0x0c, 0x0c,
+  0x59, 0xa9, 0x1f, 0xbd, 0x1c, 0xa0, 0xf9, 0xc2, 0x23, 0x4b, 0xaa, 0xbe,
+  0x10, 0x4f, 0xf7, 0x5a, 0x25, 0x49, 0xb2, 0xc8, 0xdc, 0xf7, 0xb1, 0x45,
+  0xdf, 0xbb, 0x15, 0xd9, 0x48, 0x49, 0x01, 0x27, 0xf6, 0xdc, 0x59, 0x48,
+  0xb7, 0xd7, 0x5e, 0x46, 0xde, 0x2c, 0x27, 0x64, 0xf9, 0xc2, 0xc5, 0x37,
+  0x21, 0x9a, 0xbf, 0x62, 0x14, 0xdd, 0x13, 0x26, 0x9f, 0x62, 0x65, 0x55,
+  0xe8, 0xd7, 0x6f, 0x10, 0x5c, 0xd7, 0x19, 0x16, 0x1b, 0x87, 0xd3, 0x74,
+  0xd2, 0x8a, 0x89, 0x15, 0x17, 0xd8, 0x83, 0x8f, 0x3f, 0x38, 0x98, 0x9b,
+  0x25, 0x03, 0xc7, 0x7c, 0x35, 0x88, 0x53, 0x48, 0xca, 0xd6, 0x4d, 0x20,
+  0x23, 0x54, 0x15, 0x51, 0xda, 0xfb, 0x7e, 0x41, 0xbc, 0x88, 0xf5, 0x53,
+  0xf6, 0xe2, 0x54, 0xe6, 0xa8, 0xb1, 0x04, 0xac, 0xd1, 0xd6, 0x37, 0xd2,
+  0xa9, 0x6f, 0x96, 0xc0, 0x6a, 0xb1, 0xd4, 0xcf, 0x1e, 0xda, 0xda, 0x72,
+  0x43, 0xaa, 0x7b, 0x7d, 0x39, 0x19, 0x11, 0x06, 0x2a, 0x73, 0x87, 0xe6,
+  0xdb, 0x8a, 0xcf, 0x66, 0xf2, 0x77, 0xc9, 0x0a, 0xe2, 0x13, 0x90, 0xd6,
+  0x1b, 0xa6, 0xfb, 0xfd, 0xda, 0x63, 0x80, 0x81, 0x55, 0x7a, 0x4b, 0xea,
+  0x79, 0x4d, 0xa9, 0x46, 0x2b, 0xb1, 0xa5, 0x98, 0x8d, 0x34, 0x32, 0x07,
+  0xc6, 0xff, 0x98, 0x17, 0xd1, 0x55, 0x85, 0xc6, 0x8d, 0x0a, 0x3b, 0x58,
+  0x1e, 0x82, 0x24, 0xa2, 0xef, 0x83, 0xed, 0xf6, 0xe2, 0x79, 0x1b, 0x2b,
+  0x46, 0x7e, 0x94, 0x5b, 0xc8, 0x5a, 0x93, 0xef, 0xca, 0x76, 0xc7, 0xef,
+  0x71, 0xce, 0x15, 0x33, 0x91, 0xef, 0x46, 0xa9, 0x58, 0xd8, 0x6d, 0xa9,
+  0x47, 0x45, 0x35, 0xbb, 0xce, 0x96, 0xb7, 0x44, 0xd4, 0x7a, 0x90, 0xd4,
+  0xcb, 0x18, 0xbc, 0x7b, 0x64, 0xf3, 0x8e, 0xf5, 0xd5, 0xf7, 0x82, 0xdb,
+  0xff, 0xd6, 0x50, 0x17, 0xdf, 0x9a, 0x11, 0x75, 0x85, 0x36, 0xc8, 0x0c,
+  0x44, 0xcc, 0xdc, 0x76, 0xfc, 0x9f, 0x3e, 0x84, 0x8f, 0xea, 0xc6, 0xb1,
+  0xfa, 0x97, 0x75, 0x31, 0xe8, 0xc2, 0x81, 0x7b, 0x39, 0x14, 0xad, 0xdf,
+  0x67, 0xf2, 0x44, 0xe0, 0xc4, 0x7a, 0x21, 0x63, 0x74, 0x73, 0x41, 0xf4,
+  0xb5, 0xbd, 0x87, 0x36, 0xd0, 0x64, 0xb6, 0x8e, 0x98, 0xd2, 0x79, 0x5f,
+  0x4d, 0x22, 0x8c, 0xc1, 0x41, 0x4c, 0xea, 0xb7, 0xab, 0x4b, 0x2e, 0xca,
+  0x35, 0x14, 0xd3, 0x90, 0x9e, 0xd6, 0x94, 0x3e, 0x7e, 0xe4, 0x57, 0x09,
+  0x22, 0x3c, 0xe6, 0xbe, 0x04, 0x95, 0x75, 0xf8, 0xe0, 0x42, 0xe9, 0xe2,
+  0x5e, 0x2e, 0x2a, 0xc6, 0x48, 0x55, 0x42, 0x39, 0xc4, 0x81, 0x6a, 0xc6,
+  0x19, 0xea, 0x4c, 0x63, 0x60, 0x11, 0xdf, 0xe7, 0xde, 0x4d, 0x0f, 0xec,
+  0x0c, 0x8f, 0x21, 0xe7, 0x94, 0x72, 0x24, 0x4d, 0xc0, 0x44, 0x30, 0x63,
+  0x18, 0x06, 0x9b, 0xb9, 0x63, 0xc2, 0x94, 0x6d, 0x78, 0xba, 0x36, 0x58,
+  0xe3, 0x07, 0x0f, 0xd4, 0x16, 0xe5, 0xc7, 0x58, 0xb1, 0x5e, 0x96, 0x25,
+  0x80, 0xc0, 0x0c, 0x4d, 0xf1, 0xda, 0x8b, 0xc6, 0x66, 0x56, 0x1e, 0x7c,
+  0x64, 0x6b, 0x2c, 0xb2, 0x8c, 0xed, 0x07, 0xa7, 0x52, 0x70, 0xbd, 0x68,
+  0xd3, 0x48, 0x18, 0x38, 0xa6, 0x60, 0x18, 0x97, 0x4a, 0xd0, 0x88, 0xed,
+  0x4c, 0x99, 0xad, 0x88, 0x56, 0xec, 0x2b, 0xd7, 0xb4, 0xd6, 0xc6, 0x43,
+  0x58, 0xf6, 0x9b, 0xfb, 0x28, 0xa7, 0xb4, 0xaa, 0x61, 0xc4, 0x09, 0x0b,
+  0xa7, 0x51, 0x7a, 0xd3, 0x2f, 0x84, 0xeb, 0x9e, 0xc9, 0xc9, 0xac, 0x7e,
+  0x80, 0x2e, 0xa6, 0x88, 0x84, 0xd2, 0x54, 0xca, 0xe6, 0xf1, 0x7c, 0x97,
+  0x7c, 0x8a, 0x8a, 0x66, 0x7f, 0x00, 0x4b, 0x73, 0x3f, 0x2e, 0xfb, 0xcc,
+  0xe5, 0x07, 0xe6, 0x4e, 0xa1, 0x8e, 0xfc, 0x62, 0xb7, 0xd7, 0xbe, 0xa4,
+  0x4a, 0x65, 0xd7, 0xe2, 0xaa, 0x0c, 0xdd, 0x93, 0x93, 0x63, 0x56, 0x46,
+  0xe5, 0xe5, 0xf5, 0x47, 0xb1, 0xe4, 0x4e, 0x60, 0x97, 0x83, 0x82, 0x23,
+  0x84, 0x37, 0x20, 0xbd, 0xb5, 0x8b, 0x9d, 0x5d, 0xc8, 0xca, 0xe1, 0xa8,
+  0x5a, 0xc4, 0xaa, 0xe2, 0x79, 0xda, 0x1d, 0x48, 0x60, 0x4c, 0x2e, 0x06,
+  0x95, 0xb4, 0x76, 0x42, 0xa0, 0x6e, 0x52, 0x52, 0x0f, 0xf8, 0x24, 0x81,
+  0x21, 0x6f, 0x67, 0x27, 0x9e, 0xe5, 0xf9, 0x9b, 0x8c, 0x82, 0x90, 0x90,
+  0xdd, 0xe7, 0xd4, 0x24, 0x54, 0xa7, 0x26, 0x41, 0xd2, 0x54, 0x50, 0x6a,
+  0x66, 0xf0, 0xd5, 0x68, 0xaf, 0xd1, 0xd2, 0x00, 0x66, 0xa1, 0x9e, 0x1b,
+  0xab, 0xe6, 0x43, 0xa2, 0xb8, 0x05, 0x2f, 0xae, 0x9b, 0xce, 0x15, 0xa2,
+  0x5b, 0xd1, 0xb5, 0x53, 0x66, 0x6e, 0xc9, 0x44, 0x7b, 0x8c, 0x5d, 0x94,
+  0x63, 0x3c, 0xa5, 0xc5, 0x81, 0x48, 0xd7, 0x98, 0x6b, 0xb7, 0xce, 0xe4,
+  0xd9, 0xaf, 0x1c, 0xa9, 0x76, 0x8c, 0x1b, 0x4b, 0x5c, 0x1e, 0x9c, 0x98,
+  0xef, 0x74, 0x40, 0xe3, 0xf1, 0x48, 0x8c, 0x14, 0x66, 0xe4, 0x7d, 0xbd,
+  0xff, 0xcf, 0xae, 0xf8, 0x36, 0x79, 0x83, 0x76, 0xe7, 0x66, 0x36, 0x12,
+  0x60, 0x17, 0x2f, 0xb0, 0x2f, 0x22, 0x32, 0x4b, 0x42, 0x65, 0xed, 0x76,
+  0x6e, 0x4c, 0x9d, 0xb9, 0x54, 0x9b, 0x98, 0x8b, 0x79, 0x8b, 0x0e, 0xaf,
+  0x9c, 0x8c, 0xa9, 0x58, 0xaa, 0xa2, 0xde, 0x1a, 0x9b, 0x6d, 0x75, 0x0f,
+  0xd2, 0xd4, 0x28, 0xdc, 0xca, 0xcd, 0x91, 0x66, 0xd0, 0xd9, 0xab, 0x3c,
+  0x22, 0x55, 0x36, 0x87, 0x4f, 0x41, 0x24, 0x5c, 0xee, 0x5a, 0x54, 0x1a,
+  0xe0, 0xf5, 0x2c, 0x01, 0x98, 0xa3, 0x54, 0x6e, 0x6f, 0xdc, 0x88, 0xf7,
+  0x86, 0xba, 0xe2, 0x8d, 0x84, 0x95, 0x78, 0x84, 0x8c, 0xc1, 0xae, 0x8c,
+  0x7f, 0xa7, 0x91, 0xbc, 0x6d, 0x3b, 0x48, 0x7a, 0x42, 0xa0, 0xc0, 0x0a,
+  0xfe, 0xda, 0xbc, 0xe7, 0xa6, 0x76, 0xcb, 0xca, 0x68, 0xb0, 0xda, 0xb3,
+  0x2e, 0x4c, 0x57, 0x50, 0xeb, 0xbb, 0x0a, 0x35, 0x94, 0x80, 0xab, 0xcf,
+  0xa7, 0xdc, 0xab, 0x31, 0x54, 0xef, 0xe0, 0x77, 0xa5, 0x7e, 0x9e, 0x76,
+  0x96, 0x62, 0x92, 0x25, 0xf1, 0xa1, 0xa5, 0x91, 0x06, 0x9e, 0x2f, 0x81,
+  0xd8, 0x5f, 0x2e, 0xe4, 0xe8, 0xda, 0x9f, 0xe1, 0x62, 0xe1, 0x30, 0xd0,
+  0x16, 0x02, 0xc6, 0xeb, 0x3a, 0x43, 0x4e, 0x64, 0x07, 0x77, 0xf2, 0xda,
+  0x0d, 0xf5, 0xd3, 0x1c, 0x26, 0x4c, 0xcd, 0xa4, 0xb3, 0xc5, 0xd6, 0x73,
+  0xb4, 0xbc, 0xc0, 0x07, 0x64, 0x98, 0xfb, 0xf6, 0x32, 0xe4, 0xe1, 0xca,
+  0x74, 0x4c, 0x64, 0xad, 0x04, 0x53, 0x1b, 0x99, 0x24, 0x7b, 0x2e, 0xd7,
+  0x3e, 0x07, 0xba, 0x7a, 0x08, 0x7b, 0xb1, 0xb0, 0x11, 0x3f, 0x4e, 0x66,
+  0xd8, 0xa5, 0x4e, 0x72, 0x67, 0xa6, 0xbe, 0x38, 0x76, 0xcf, 0x72, 0x07,
+  0x9a, 0x57, 0x2f, 0x29, 0x6d, 0x55, 0xcd, 0x69, 0xed, 0xcf, 0x59, 0x5e,
+  0xd9, 0xe5, 0x29, 0x5b, 0xd0, 0x4d, 0x85, 0xea, 0x44, 0x0c, 0xac, 0x2d,
+  0x76, 0x28, 0x65, 0x39, 0x2a, 0xfc, 0x9f, 0xe8, 0xd8, 0xce, 0x5c, 0x56,
+  0xc0, 0x33, 0xa4, 0xcc, 0x32, 0xa6, 0x00, 0xd8, 0x9d, 0x9d, 0x0a, 0x28,
+  0x27, 0x15, 0x42, 0x8e, 0xeb, 0xb0, 0xef, 0x6f, 0xb8, 0x93, 0xe2, 0xdf,
+  0x6e, 0x17, 0x46, 0x67, 0x59, 0x05, 0x92, 0xad, 0x87, 0xc6, 0x06, 0x35,
+  0xc8, 0x4c, 0x05, 0x1c, 0x9f, 0xf4, 0xa4, 0xa4, 0xa1, 0x8d, 0x11, 0xc7,
+  0xab, 0x4b, 0x9b, 0x3a, 0x71, 0xcb, 0x2d, 0x1f, 0xec, 0x61, 0xa0, 0x66,
+  0x5f, 0x3d, 0xa3, 0x95, 0x39, 0x7f, 0x98, 0x34, 0x79, 0x32, 0x15, 0x94,
+  0xa0, 0x16, 0xa4, 0xf3, 0x45, 0x7b, 0x31, 0xfe, 0xf2, 0xe3, 0x65, 0x01,
+  0xc1, 0xf7, 0xcd, 0xcb, 0x59, 0x52, 0xbb, 0xf6, 0xa4, 0x12, 0x22, 0x9e,
+  0x5f, 0xd0, 0x50, 0x8a, 0x43, 0x62, 0xfd, 0x22, 0x21, 0xfb, 0xae, 0x08,
+  0x57, 0xc7, 0x00, 0xa6, 0x48, 0x2e, 0xcb, 0x0b, 0x76, 0x08, 0xf9, 0xd4,
+  0x14, 0x9a, 0xb5, 0xcd, 0xb8, 0x33, 0xc3, 0x0d, 0x2a, 0x3a, 0xf0, 0xe2,
+  0x5f, 0x0e, 0x1f, 0xa1, 0x1c, 0x71, 0x38, 0x2e, 0x8e, 0x93, 0x13, 0x27,
+  0xa2, 0x4a, 0xdc, 0x95, 0x1e, 0x26, 0x30, 0x5f, 0xdd, 0xc4, 0x15, 0x8e,
+  0xa8, 0xfd, 0x80, 0xf4, 0x9e, 0x31, 0x80, 0xc9, 0xa0, 0xf7, 0x61, 0xb5,
+  0x55, 0x40, 0xb4, 0x7f, 0xd8, 0xb2, 0x6b, 0x58, 0xba, 0x34, 0xba, 0x78,
+  0xa0, 0xee, 0xa2, 0xc4, 0x73, 0x19, 0xc7, 0xdf, 0x1b, 0x46, 0x3c, 0xe0,
+  0x7c, 0xb3, 0xf9, 0x7c, 0x35, 0xd5, 0xf0, 0xbf, 0x2c, 0xed, 0xa4, 0x20,
+  0x95, 0x0b, 0x05, 0x7a, 0xce, 0xdc, 0x81, 0x95, 0xf3, 0x12, 0x8a, 0x7f,
+  0xcb, 0xa8, 0xdc, 0x77, 0xbf, 0x8b, 0xdf, 0xf6, 0xb0, 0xce, 0xce, 0x0b,
+  0xdf, 0xe9, 0xcf, 0x92, 0x02, 0x20, 0x82, 0x81, 0x9c, 0x03, 0x72, 0xe8,
+  0x41, 0x6b, 0xbe, 0xb6, 0x87, 0x8b, 0xf9, 0x9e, 0x49, 0x77, 0xc5, 0xcf,
+  0x73, 0x9d, 0xf6, 0x1c, 0x42, 0x7c, 0xa8, 0xbb, 0xe3, 0x24, 0x70, 0x9f,
+  0xef, 0x28, 0xce, 0x45, 0x13, 0x13, 0x5f, 0xad, 0x02, 0x2a, 0xb4, 0x14,
+  0x80, 0x66, 0xe1, 0x6b, 0x29, 0x72, 0x77, 0xa3, 0x04, 0x36, 0x28, 0x8d,
+  0xc6, 0x39, 0xa3, 0x29, 0x59, 0xbf, 0x1e, 0x69, 0xcc, 0x8f, 0x25, 0x28,
+  0xb8, 0x24, 0x7c, 0xea, 0xe9, 0x4c, 0x43, 0x6e, 0x6c, 0x7b, 0x1d, 0x41,
+  0x7f, 0xd9, 0xd9, 0x59, 0x1e, 0x45, 0x76, 0xcc, 0x26, 0x6e, 0xe1, 0x80,
+  0x73, 0x4d, 0x79, 0x3c, 0x5c, 0x1d, 0x78, 0xf3, 0xf9, 0x75, 0x2c, 0x9d,
+  0x9d, 0x8e, 0x90, 0x23, 0xf3, 0xf9, 0xd7, 0x68, 0x14, 0xf3, 0x09, 0x2f,
+  0xa1, 0x86, 0xb1, 0x9d, 0xe2, 0x3c, 0xd3, 0x16, 0xc4, 0xdf, 0x7c, 0xcf,
+  0xc5, 0xf2, 0x3e, 0x67, 0x8b, 0xc8, 0x3e, 0x23, 0x17, 0xbf, 0x75, 0x1e,
+  0xf3, 0x35, 0xee, 0x9f, 0x14, 0xae, 0xc1, 0x5b, 0xe7, 0x92, 0x68, 0xb8,
+  0x0f, 0x95, 0x67, 0x1b, 0x55, 0xe7, 0x90, 0x6f, 0x72, 0xa0, 0x78, 0xd2,
+  0x57, 0xca, 0x0a, 0x92, 0x62, 0x8d, 0x20, 0x52, 0x84, 0xb3, 0xae, 0x8e,
+  0x22, 0x3d, 0x36, 0x3a, 0xfe, 0x68, 0x2d, 0x89, 0x8f, 0x51, 0x5b, 0x87,
+  0x87, 0x21, 0x69, 0x1a, 0x90, 0x97, 0x9e, 0x2f, 0x91, 0xae, 0x32, 0x17,
+  0x08, 0x0b, 0x3e, 0x65, 0x8a, 0xaa, 0x8e, 0xf3, 0x7b, 0x43, 0xc4, 0x2d,
+  0x05, 0xac, 0x7a, 0xd9, 0x29, 0x41, 0xf8, 0x80, 0x64, 0x99, 0x98, 0xc3,
+  0xb8, 0x4b, 0x4a, 0x4b, 0x48, 0x2a, 0xbd, 0x38, 0x42, 0x3a, 0xf1, 0x67,
+  0x03, 0x1d, 0xd8, 0x00, 0x50, 0xc9, 0xce, 0x3a, 0x34, 0xe5, 0xac, 0x5f,
+  0x36, 0x55, 0xf4, 0xf2, 0xa6, 0x09, 0x04, 0x20, 0x64, 0x56, 0xa1, 0x15,
+  0x65, 0x4d, 0x07, 0x7e, 0x47, 0xf7, 0x34, 0x30, 0x3a, 0xbe, 0x49, 0xc1,
+  0x75, 0xa3, 0x7d, 0xe5, 0x0e, 0xba, 0xdf, 0x81, 0xc0, 0x94, 0xf8, 0xec,
+  0x1d, 0x81, 0x63, 0x48, 0x12, 0x16, 0x82, 0x12, 0x8b, 0x2a, 0xf7, 0x6e,
+  0x23, 0xa4, 0x11, 0x8b, 0x70, 0xb3, 0x8a, 0xce, 0xd0, 0xdf, 0xc4, 0x6f,
+  0x65, 0x01, 0xe4, 0x6e, 0x61, 0x58, 0x78, 0x2a, 0x4b, 0x9a, 0x1b, 0x65,
+  0x94, 0xc4, 0xc5, 0x9d, 0x95, 0xc6, 0x12, 0x6f, 0xfc, 0x8a, 0x5e, 0x7f,
+  0xc8, 0xbe, 0xa9, 0xf0, 0x65, 0xb9, 0xa7, 0xe5, 0xa9, 0x39, 0xc3, 0x7a,
+  0x79, 0x05, 0x72, 0x77, 0x1f, 0xf7, 0x2b, 0x29, 0xf5, 0xb9, 0xce, 0x20,
+  0x82, 0x01, 0x21, 0xa0, 0x0c, 0xd5, 0x7c, 0x7b, 0xe5, 0x9a, 0xea, 0xdb,
+  0x71, 0xa6, 0xef, 0x57, 0xca, 0x0d, 0x55, 0x3e, 0x3c, 0x9e, 0xac, 0x6c,
+  0x18, 0x4e, 0xe9, 0xc4, 0x67, 0x00, 0x1d, 0xc3, 0xf6, 0x88, 0x9d, 0xd5,
+  0xb4, 0x1a, 0xa8, 0xde, 0xfa, 0x8c, 0xe8, 0xb5, 0x8a, 0xec, 0x6c, 0x94,
+  0x62, 0x63, 0x00, 0xaf, 0x8a, 0x91, 0x4b, 0x1b, 0x01, 0x90, 0x72, 0xa5,
+  0x0a, 0x03, 0x50, 0xc7, 0x0d, 0x66, 0xaf, 0xca, 0xae, 0xe5, 0x7f, 0x00,
+  0x00, 0x01, 0x0a
+};
+
+void
+h264_get_video_info (VideoDecodeInfo * info)
+{
+  info->profile = GST_VAAPI_PROFILE_H264_MAIN;
+  info->width = H264_CLIP_WIDTH;
+  info->height = H264_CLIP_HEIGHT;
+  info->data = h264_clip;
+  info->data_size = H264_CLIP_DATA_SIZE;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-h264.h b/subprojects/gstreamer-vaapi/tests/internal/test-h264.h
new file mode 100644 (file)
index 0000000..d94df4e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  test-h264.h - H.264 test data
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_H264_H
+#define TEST_H264_H
+
+#include <glib.h>
+#include "test-decode.h"
+
+void h264_get_video_info(VideoDecodeInfo *info);
+
+#endif /* TEST_H264_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-jpeg.c b/subprojects/gstreamer-vaapi/tests/internal/test-jpeg.c
new file mode 100644 (file)
index 0000000..f3bd4a1
--- /dev/null
@@ -0,0 +1,2082 @@
+/*
+ *  test-jpeg.c - JPEG test data
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "test-jpeg.h"
+
+#define JPEG_CLIP_WIDTH            320
+#define JPEG_CLIP_HEIGHT           240
+#define JPEG_CLIP_DATA_SIZE      24481
+
+/* Data dump of a 320x240 VC-1 video clip (jpeg.raw), it has a single frame */
+static const guchar jpeg_clip[JPEG_CLIP_DATA_SIZE] = {
+  0xff, 0xd8, 0xff, 0xe0, 0x00, 0x10, 0x4a, 0x46, 0x49, 0x46, 0x00, 0x01,
+  0x01, 0x01, 0x00, 0x48, 0x00, 0x48, 0x00, 0x00, 0xff, 0xdb, 0x00, 0x43,
+  0x00, 0x05, 0x03, 0x04, 0x04, 0x04, 0x03, 0x05, 0x04, 0x04, 0x04, 0x05,
+  0x05, 0x05, 0x06, 0x07, 0x0c, 0x08, 0x07, 0x07, 0x07, 0x07, 0x0f, 0x0b,
+  0x0b, 0x09, 0x0c, 0x11, 0x0f, 0x12, 0x12, 0x11, 0x0f, 0x11, 0x11, 0x13,
+  0x16, 0x1c, 0x17, 0x13, 0x14, 0x1a, 0x15, 0x11, 0x11, 0x18, 0x21, 0x18,
+  0x1a, 0x1d, 0x1d, 0x1f, 0x1f, 0x1f, 0x13, 0x17, 0x22, 0x24, 0x22, 0x1e,
+  0x24, 0x1c, 0x1e, 0x1f, 0x1e, 0xff, 0xdb, 0x00, 0x43, 0x01, 0x05, 0x05,
+  0x05, 0x07, 0x06, 0x07, 0x0e, 0x08, 0x08, 0x0e, 0x1e, 0x14, 0x11, 0x14,
+  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+  0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e, 0x1e,
+  0x1e, 0x1e, 0xff, 0xc0, 0x00, 0x11, 0x08, 0x00, 0xf0, 0x01, 0x40, 0x03,
+  0x01, 0x22, 0x00, 0x02, 0x11, 0x01, 0x03, 0x11, 0x01, 0xff, 0xc4, 0x00,
+  0x1d, 0x00, 0x00, 0x02, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x05, 0x03, 0x06, 0x07, 0x02,
+  0x08, 0x01, 0x00, 0x09, 0xff, 0xc4, 0x00, 0x43, 0x10, 0x00, 0x02, 0x01,
+  0x03, 0x02, 0x04, 0x04, 0x05, 0x02, 0x04, 0x03, 0x07, 0x03, 0x04, 0x03,
+  0x01, 0x01, 0x02, 0x03, 0x04, 0x05, 0x11, 0x00, 0x21, 0x06, 0x12, 0x31,
+  0x41, 0x13, 0x22, 0x51, 0x61, 0x07, 0x14, 0x32, 0x71, 0x81, 0x91, 0xa1,
+  0x15, 0x23, 0x42, 0xb1, 0x52, 0xc1, 0xd1, 0x08, 0x24, 0x33, 0x62, 0xe1,
+  0xf0, 0xf1, 0x16, 0x43, 0x72, 0x25, 0x26, 0x34, 0x82, 0x17, 0x53, 0x83,
+  0x93, 0xff, 0xc4, 0x00, 0x19, 0x01, 0x00, 0x02, 0x03, 0x01, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x03,
+  0x00, 0x01, 0x04, 0x05, 0xff, 0xc4, 0x00, 0x2b, 0x11, 0x00, 0x02, 0x02,
+  0x01, 0x04, 0x02, 0x02, 0x02, 0x01, 0x03, 0x05, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x01, 0x02, 0x11, 0x03, 0x04, 0x12, 0x21, 0x31, 0x22, 0x41,
+  0x13, 0x32, 0x05, 0x51, 0x14, 0x23, 0x42, 0x61, 0x33, 0x52, 0x91, 0xb1,
+  0xc1, 0xff, 0xda, 0x00, 0x0c, 0x03, 0x01, 0x00, 0x02, 0x11, 0x03, 0x11,
+  0x00, 0x3f, 0x00, 0xcc, 0xb8, 0xce, 0xf5, 0x70, 0x83, 0x8b, 0x2f, 0x40,
+  0x79, 0xe2, 0x4b, 0x8c, 0xe8, 0x17, 0xd8, 0x48, 0xdf, 0xe9, 0xa8, 0x2d,
+  0xbc, 0x52, 0xa1, 0xb3, 0x2d, 0x34, 0xa8, 0x00, 0xc1, 0xc2, 0x67, 0x6f,
+  0x5f, 0xdb, 0x53, 0xf1, 0x9d, 0x08, 0x97, 0x8b, 0xef, 0x72, 0x0d, 0xc7,
+  0xcf, 0xcf, 0xb7, 0x4f, 0xfd, 0xc3, 0xa4, 0x33, 0x47, 0x15, 0x0d, 0x1c,
+  0xac, 0x55, 0x89, 0x70, 0x42, 0xb7, 0x4c, 0x1c, 0xf4, 0xd6, 0x13, 0x97,
+  0x3f, 0xb3, 0x2d, 0x74, 0xfc, 0x6f, 0xc3, 0xe1, 0xc2, 0xbd, 0x4c, 0x8a,
+  0x71, 0x82, 0x5a, 0x3c, 0x63, 0x56, 0x4b, 0x1f, 0x10, 0xf0, 0xfd, 0x7b,
+  0xaa, 0x0b, 0xa5, 0x2a, 0xf3, 0x79, 0x40, 0x69, 0x00, 0x39, 0xfc, 0xeb,
+  0x13, 0xf0, 0x62, 0x7e, 0x5e, 0x65, 0x00, 0xb6, 0xdb, 0x6b, 0xa1, 0x48,
+  0x88, 0x4a, 0x82, 0x36, 0xf6, 0xd4, 0xb7, 0xec, 0x1d, 0x87, 0xa5, 0xae,
+  0x57, 0x24, 0x8b, 0x84, 0x2a, 0x28, 0x28, 0xcd, 0x34, 0x8a, 0xb3, 0x2b,
+  0x19, 0xe3, 0x91, 0x5c, 0x91, 0x83, 0xb6, 0xdd, 0x35, 0x41, 0xba, 0xd7,
+  0x25, 0x35, 0xbe, 0x69, 0xb0, 0x43, 0x46, 0xa4, 0xe7, 0x3e, 0xc7, 0x59,
+  0xcf, 0x0d, 0x41, 0x39, 0xba, 0x2c, 0x71, 0xd4, 0xcb, 0x1c, 0x64, 0x67,
+  0x0a, 0xdb, 0x67, 0x3e, 0x9a, 0x7f, 0x7c, 0xba, 0x25, 0x45, 0x9a, 0xb2,
+  0xdf, 0x24, 0x85, 0x6a, 0xb2, 0x10, 0x77, 0xe7, 0x5c, 0xf5, 0x3e, 0x9d,
+  0x34, 0x8d, 0x9f, 0x17, 0x3f, 0xb2, 0x64, 0x85, 0xd3, 0x33, 0xfa, 0xd9,
+  0xcd, 0x5d, 0x4b, 0xd4, 0x33, 0x12, 0xd2, 0x31, 0x6e, 0xbe, 0xa7, 0x3a,
+  0x6b, 0xc3, 0x7c, 0x9f, 0xf0, 0xd9, 0xca, 0x9e, 0x6c, 0xfd, 0xf4, 0x0b,
+  0xdb, 0xe6, 0x4f, 0x30, 0x4d, 0xb3, 0xd3, 0x4d, 0xf8, 0x76, 0x13, 0x1c,
+  0xab, 0x24, 0x83, 0x03, 0x9f, 0x97, 0xec, 0x74, 0x68, 0x7a, 0xe8, 0xbc,
+  0xd8, 0x69, 0xa9, 0xa3, 0x9c, 0x9d, 0x98, 0x95, 0x07, 0x61, 0x81, 0xbe,
+  0xfd, 0x34, 0xf2, 0xa9, 0x20, 0x82, 0x21, 0x24, 0xd8, 0x8c, 0x75, 0x43,
+  0x8c, 0xef, 0xdb, 0x48, 0xa8, 0x9d, 0x92, 0xea, 0xaa, 0x47, 0x2a, 0x34,
+  0x60, 0x07, 0xf5, 0x20, 0x7a, 0x6a, 0xc5, 0x27, 0x87, 0x24, 0x2f, 0x05,
+  0x41, 0xcc, 0x6c, 0x31, 0xd3, 0x4e, 0x42, 0x19, 0x58, 0xbe, 0xc5, 0x35,
+  0x5c, 0x6b, 0x24, 0xbc, 0xde, 0x2c, 0x24, 0xb2, 0x8c, 0x90, 0x0f, 0xb6,
+  0xda, 0x87, 0x83, 0x2e, 0xa2, 0x5b, 0x8c, 0x94, 0xd2, 0xc9, 0xbb, 0x6d,
+  0x8c, 0x6c, 0xac, 0x31, 0xb0, 0xd3, 0xca, 0xea, 0x4e, 0x68, 0x1f, 0xc2,
+  0x66, 0x78, 0xd4, 0x1f, 0x38, 0x19, 0x03, 0xd8, 0xea, 0x92, 0xb4, 0xb2,
+  0xd3, 0x5f, 0x84, 0xb1, 0x1e, 0x53, 0xf5, 0x67, 0xdc, 0x77, 0xd5, 0x9a,
+  0xb1, 0x3d, 0xd1, 0xda, 0x5d, 0x38, 0xc4, 0xc1, 0x1d, 0x8a, 0xa4, 0xd4,
+  0xc5, 0xe2, 0xa0, 0x1d, 0x39, 0x72, 0x47, 0xb8, 0xf7, 0xd5, 0x52, 0x86,
+  0xd7, 0x6e, 0x8e, 0x18, 0xea, 0xa0, 0xb9, 0x20, 0x9a, 0x51, 0x85, 0xa7,
+  0x64, 0x6e, 0x6f, 0x5d, 0xfd, 0x35, 0x77, 0x85, 0xc5, 0x5d, 0x2a, 0x3b,
+  0x90, 0x4b, 0x27, 0xf3, 0x36, 0xf6, 0xd6, 0x69, 0x55, 0x55, 0x24, 0xb7,
+  0x29, 0x62, 0x81, 0x3f, 0x9b, 0x03, 0x98, 0x99, 0xf9, 0x80, 0x07, 0x07,
+  0x18, 0xfb, 0x9c, 0x6a, 0x07, 0x81, 0x26, 0x9c, 0x18, 0xc9, 0x6a, 0x39,
+  0xeb, 0xa3, 0x82, 0x86, 0x6f, 0x1a, 0x76, 0x7e, 0x54, 0x0a, 0xb8, 0xdf,
+  0xed, 0xab, 0x5d, 0x3d, 0x38, 0xa1, 0x52, 0xe6, 0xa6, 0x29, 0x2e, 0x52,
+  0x0c, 0x73, 0xf2, 0x73, 0x01, 0x26, 0x73, 0x80, 0x7d, 0x14, 0x6f, 0xf8,
+  0xd7, 0x1c, 0x23, 0x6d, 0x82, 0x0a, 0x46, 0xa8, 0xa7, 0xa7, 0xcd, 0x5c,
+  0x91, 0xff, 0x00, 0x31, 0x07, 0xd4, 0x89, 0xb6, 0xd9, 0xec, 0x31, 0xd4,
+  0xf7, 0xd4, 0xf4, 0xd5, 0x4d, 0x15, 0x73, 0xd4, 0x49, 0x1a, 0xd5, 0x33,
+  0x29, 0x8d, 0x40, 0x5c, 0x0f, 0xfe, 0x2a, 0xbb, 0xe3, 0xef, 0xdf, 0x03,
+  0x52, 0x97, 0xa1, 0xeb, 0x0c, 0x62, 0x2b, 0x96, 0x2a, 0x98, 0xea, 0x2a,
+  0x4c, 0x93, 0x4b, 0x3b, 0x2a, 0x33, 0x4c, 0x4b, 0x60, 0x06, 0x3f, 0x4f,
+  0x31, 0xf5, 0x39, 0xce, 0x3b, 0x69, 0x61, 0x3e, 0x74, 0xa8, 0x8f, 0x0c,
+  0x8a, 0x70, 0x37, 0xc7, 0x37, 0xdb, 0xdb, 0x53, 0xde, 0xc4, 0xbc, 0xe5,
+  0xa4, 0x51, 0x0c, 0x21, 0xcf, 0x88, 0x13, 0xe9, 0x5c, 0x12, 0x06, 0x74,
+  0x38, 0x65, 0x91, 0x55, 0xa2, 0x45, 0x58, 0x97, 0x60, 0x1b, 0xea, 0xfb,
+  0x0f, 0x6c, 0xff, 0x00, 0xa6, 0xa0, 0xcd, 0xa0, 0xb5, 0x28, 0xd3, 0x32,
+  0xac, 0x3c, 0xa5, 0xe4, 0x7c, 0x28, 0x0b, 0xe6, 0xc9, 0xd7, 0x70, 0xc6,
+  0x60, 0x79, 0x21, 0x90, 0xf3, 0xf8, 0x7f, 0x4b, 0x0e, 0x80, 0xff, 0x00,
+  0xde, 0xfa, 0xea, 0xb4, 0x55, 0x53, 0xd7, 0x37, 0x38, 0x0a, 0xe1, 0x41,
+  0x1c, 0xbe, 0x50, 0xb9, 0xdf, 0x61, 0xa8, 0x22, 0xcc, 0x91, 0xba, 0x9d,
+  0x98, 0xb9, 0x63, 0xef, 0xbe, 0xa1, 0x36, 0x8e, 0xf8, 0x5a, 0x08, 0xaa,
+  0xee, 0x71, 0xa5, 0x6c, 0xf2, 0x45, 0x4e, 0x5c, 0xb4, 0x92, 0x20, 0x04,
+  0xa8, 0x03, 0x3b, 0x0f, 0xbe, 0x34, 0xce, 0xb5, 0x6c, 0x86, 0xa9, 0x84,
+  0x92, 0x48, 0xa8, 0xe3, 0x9c, 0x4a, 0xa3, 0x94, 0x31, 0xef, 0xb7, 0xf9,
+  0xe9, 0x47, 0x0b, 0xc6, 0x2a, 0x0d, 0x42, 0x24, 0xca, 0xb2, 0x02, 0x07,
+  0x23, 0x6d, 0x90, 0x3b, 0xe7, 0x4e, 0xe7, 0xa2, 0xf0, 0xe8, 0x5a, 0xa2,
+  0xa4, 0x0e, 0x48, 0xce, 0xc0, 0xf5, 0x3f, 0x6d, 0x26, 0x53, 0x51, 0x97,
+  0x26, 0x1c, 0xb1, 0x79, 0x1f, 0x04, 0x7c, 0x35, 0x4d, 0x40, 0x2f, 0x52,
+  0x34, 0x51, 0xc8, 0xcb, 0xe1, 0x16, 0x46, 0x77, 0xc8, 0x27, 0x9b, 0x6d,
+  0xbf, 0x1a, 0xb0, 0x52, 0xda, 0xcd, 0x69, 0x92, 0xae, 0xb7, 0x3e, 0x00,
+  0x25, 0x82, 0xe3, 0xf7, 0xd5, 0x52, 0xdb, 0x71, 0x88, 0xcc, 0x4c, 0x50,
+  0xb4, 0x2a, 0xad, 0xb4, 0x85, 0xb7, 0x1e, 0xf8, 0xd5, 0x8e, 0xa6, 0xf3,
+  0x5e, 0xd6, 0x7a, 0x81, 0x4a, 0x91, 0xc8, 0xdc, 0xbc, 0x85, 0x97, 0xfa,
+  0x57, 0xa1, 0x3a, 0xc1, 0x9b, 0x0e, 0x4c, 0xb2, 0xdd, 0x01, 0x19, 0x31,
+  0xc9, 0x3a, 0xa1, 0x35, 0xc6, 0xf9, 0x68, 0xfe, 0x16, 0xca, 0xb4, 0xfe,
+  0x13, 0xb4, 0x8d, 0xc9, 0x18, 0x39, 0x63, 0xd8, 0x12, 0x7b, 0x0c, 0x01,
+  0xaa, 0x25, 0x7d, 0x52, 0xb5, 0x67, 0x8e, 0xb1, 0x85, 0x93, 0x94, 0x28,
+  0x20, 0xe4, 0x80, 0x3a, 0x81, 0xa3, 0x2a, 0xa3, 0xa7, 0x2c, 0xdc, 0xa4,
+  0xb7, 0x2e, 0xd9, 0xf4, 0xf6, 0xd2, 0xba, 0x88, 0xcb, 0xca, 0xbc, 0x83,
+  0x7c, 0xe3, 0x5b, 0x63, 0x8f, 0x64, 0x52, 0xb0, 0x94, 0x47, 0x91, 0x99,
+  0xa8, 0x7c, 0x09, 0xa1, 0xa8, 0x61, 0x04, 0xe8, 0x32, 0xbf, 0xe1, 0xce,
+  0x08, 0x03, 0xdb, 0x56, 0x9a, 0x6a, 0x51, 0x53, 0x4a, 0x23, 0xa7, 0x5f,
+  0xe7, 0x8f, 0xe6, 0x28, 0x27, 0x0a, 0x70, 0x37, 0xcf, 0xbe, 0x33, 0xa0,
+  0xac, 0xd4, 0xf1, 0xf8, 0x54, 0xa9, 0x38, 0x60, 0xa2, 0x24, 0x0d, 0xca,
+  0x33, 0xd4, 0x01, 0x9d, 0x59, 0xb8, 0xd2, 0xd3, 0x45, 0xc3, 0x95, 0x74,
+  0xb0, 0xd0, 0xd7, 0x23, 0x89, 0x69, 0x23, 0x95, 0xd9, 0x58, 0x33, 0x07,
+  0x61, 0xb8, 0xdb, 0xfe, 0x9d, 0x74, 0xc2, 0xf7, 0x15, 0xc6, 0xc7, 0x55,
+  0x18, 0x53, 0xb8, 0x1e, 0x9e, 0xda, 0x1e, 0x3a, 0x5a, 0x58, 0xe6, 0x92,
+  0x72, 0xaa, 0xae, 0xf9, 0xe6, 0x62, 0x7a, 0x92, 0x73, 0xa9, 0xa3, 0xff,
+  0x00, 0x84, 0x06, 0x73, 0xe8, 0x71, 0xa1, 0xee, 0x0e, 0xb1, 0xdb, 0x65,
+  0x24, 0x02, 0x4b, 0x80, 0x06, 0xa7, 0x6e, 0x80, 0xa3, 0xae, 0x5c, 0x9f,
+  0x2e, 0x08, 0xf5, 0x07, 0x5f, 0x79, 0x0e, 0x71, 0xa5, 0xb4, 0x15, 0x92,
+  0x52, 0x55, 0x29, 0x18, 0xe4, 0x66, 0xc3, 0x7e, 0x74, 0xff, 0x00, 0xc1,
+  0x1e, 0x28, 0x65, 0x3d, 0x57, 0xa9, 0xef, 0xa7, 0x55, 0x3a, 0x0a, 0x82,
+  0x28, 0x61, 0x0f, 0x42, 0xfb, 0xf3, 0x1c, 0x15, 0x0b, 0xf8, 0xd2, 0xbf,
+  0xe1, 0x61, 0x79, 0x39, 0x0a, 0x1c, 0x80, 0x5c, 0xfa, 0x67, 0xb6, 0x9f,
+  0xdb, 0x14, 0xa5, 0x34, 0x9c, 0x87, 0x07, 0x7d, 0x72, 0x88, 0x42, 0xfb,
+  0xe9, 0x30, 0x7e, 0x4c, 0x18, 0xbe, 0x40, 0xa8, 0x69, 0x4a, 0x44, 0x63,
+  0x8d, 0x41, 0x39, 0x27, 0xf1, 0xa6, 0x56, 0xda, 0x39, 0x1a, 0x60, 0x3b,
+  0x91, 0x80, 0x35, 0x6d, 0xf8, 0x4d, 0x69, 0xb1, 0x5c, 0x78, 0xba, 0x2a,
+  0x6e, 0x21, 0x93, 0x92, 0x8e, 0x48, 0x5f, 0xff, 0x00, 0x73, 0xc3, 0x1c,
+  0xfb, 0x10, 0x0b, 0x7a, 0x75, 0xd6, 0x87, 0x3f, 0xc2, 0xca, 0xb8, 0xde,
+  0x6a, 0xeb, 0x40, 0x59, 0xa0, 0x8a, 0x46, 0x11, 0x46, 0xc7, 0xcc, 0xca,
+  0x0e, 0xc5, 0x4f, 0x7d, 0xb4, 0x53, 0x77, 0xe3, 0xfb, 0x2b, 0x63, 0x7d,
+  0x06, 0xfc, 0x2a, 0x5e, 0x1e, 0x6b, 0x3c, 0x34, 0x17, 0xaa, 0x01, 0xe2,
+  0x46, 0x00, 0xf9, 0x82, 0x4f, 0x2f, 0x41, 0xb1, 0xdf, 0x6d, 0x58, 0xef,
+  0x50, 0x7c, 0x36, 0x9a, 0x9a, 0x5a, 0x19, 0xe9, 0x12, 0x71, 0xbe, 0xf1,
+  0x46, 0xc5, 0x94, 0xf4, 0xc8, 0x27, 0xd3, 0xf3, 0xa5, 0x1c, 0x2d, 0x62,
+  0xa4, 0x7a, 0x29, 0x4d, 0xc6, 0xbe, 0x3b, 0x7f, 0x82, 0x71, 0x22, 0x49,
+  0x80, 0xd9, 0xea, 0x73, 0x9f, 0xce, 0x9e, 0xd2, 0xdd, 0x38, 0x0e, 0xd4,
+  0x04, 0x00, 0xa5, 0x5b, 0x05, 0xc3, 0x49, 0xe1, 0x19, 0x33, 0xf9, 0xc6,
+  0x3f, 0x4d, 0x66, 0xd3, 0xe3, 0xcd, 0x1b, 0x5b, 0x52, 0xff, 0x00, 0x23,
+  0x31, 0x6e, 0x4a, 0x9a, 0x46, 0x79, 0x71, 0xf8, 0x67, 0xc3, 0x55, 0xb0,
+  0x3d, 0x45, 0x97, 0x89, 0x54, 0xd4, 0xf5, 0x5a, 0x6a, 0xa5, 0x0a, 0x48,
+  0xf4, 0xc8, 0xef, 0xd3, 0x48, 0x2d, 0xdc, 0x05, 0x56, 0xd5, 0xb4, 0xf6,
+  0xea, 0x9a, 0x39, 0x56, 0x6a, 0x99, 0x00, 0x47, 0xe4, 0x21, 0x4a, 0xe7,
+  0xb1, 0xef, 0xb6, 0xb7, 0xbb, 0x47, 0x14, 0xf0, 0x9d, 0x64, 0x89, 0x47,
+  0x4d, 0x24, 0x30, 0x92, 0xdc, 0xa8, 0x92, 0x40, 0x10, 0x13, 0xe8, 0x36,
+  0xc6, 0x75, 0x64, 0x9c, 0x42, 0x90, 0x88, 0xcb, 0x47, 0x12, 0x9d, 0xb7,
+  0x20, 0x01, 0xae, 0x87, 0xc7, 0xb9, 0x72, 0x37, 0xe1, 0xbf, 0x67, 0xf3,
+  0x9f, 0x8a, 0x2a, 0x64, 0x8f, 0x8c, 0xb8, 0x82, 0x30, 0xfc, 0xa9, 0xfc,
+  0x4a, 0xa4, 0xed, 0xdc, 0xf8, 0xad, 0xa4, 0x97, 0x3a, 0xc7, 0x89, 0x92,
+  0x27, 0x84, 0x32, 0x32, 0x73, 0x37, 0x9b, 0x1b, 0x9e, 0x87, 0x56, 0xdb,
+  0xf5, 0xad, 0x62, 0xe2, 0xeb, 0xe5, 0x55, 0x44, 0x8c, 0xfe, 0x25, 0xc6,
+  0xa5, 0x95, 0x7b, 0x00, 0x64, 0x63, 0xaa, 0x1d, 0xd6, 0x56, 0x9e, 0xbe,
+  0x57, 0x41, 0xcc, 0x39, 0x88, 0x51, 0xe8, 0x35, 0x9c, 0xcd, 0x3f, 0xb3,
+  0x24, 0xa3, 0x2f, 0x35, 0x6a, 0x4b, 0x08, 0x29, 0xcb, 0xdf, 0xae, 0xfa,
+  0x26, 0xe0, 0xd1, 0x73, 0xaa, 0x02, 0x39, 0xb3, 0x83, 0x83, 0xfe, 0x5a,
+  0x5d, 0x12, 0x4a, 0x57, 0x94, 0x61, 0x79, 0x8f, 0x73, 0xa2, 0x23, 0x49,
+  0x04, 0xa2, 0x05, 0xf3, 0x3e, 0x36, 0x3f, 0xf5, 0xd4, 0x08, 0xb0, 0xf0,
+  0xcc, 0x4b, 0x4c, 0x79, 0xd8, 0x6d, 0x30, 0xc0, 0x3e, 0xfa, 0x87, 0x89,
+  0x68, 0xbc, 0x1b, 0x87, 0x88, 0xd1, 0xb0, 0xf1, 0x94, 0x30, 0x24, 0x75,
+  0xd4, 0x31, 0x5c, 0x66, 0xf1, 0xe1, 0xa1, 0x47, 0xc4, 0x68, 0x06, 0x40,
+  0x1d, 0x70, 0x37, 0xfd, 0x74, 0xc2, 0xfb, 0x4e, 0xe6, 0x18, 0xdf, 0x9d,
+  0x98, 0xc5, 0x91, 0xbf, 0xf8, 0x4e, 0x08, 0x1a, 0x0c, 0x9c, 0x2a, 0x2e,
+  0x5d, 0x08, 0xe0, 0x85, 0xe5, 0x90, 0xc2, 0xbb, 0x93, 0xd0, 0x68, 0x8a,
+  0x75, 0x64, 0xa6, 0x32, 0x28, 0xf3, 0x83, 0x8d, 0xba, 0x1f, 0x43, 0xa1,
+  0xe9, 0x25, 0x10, 0xdc, 0x12, 0x5c, 0xe0, 0x86, 0xf2, 0x9f, 0x7d, 0x3d,
+  0xa6, 0xa4, 0x92, 0x76, 0x03, 0x99, 0x10, 0xb6, 0xe4, 0x1f, 0x7d, 0x54,
+  0x45, 0xa0, 0x1a, 0x2a, 0x8a, 0x85, 0x98, 0x4c, 0x67, 0x22, 0x44, 0x3c,
+  0xc4, 0x9d, 0xf5, 0x75, 0xa3, 0xaf, 0x59, 0xa2, 0x8d, 0xe1, 0x95, 0x24,
+  0x57, 0x50, 0x7d, 0xc1, 0xf4, 0xc6, 0xab, 0xb2, 0x70, 0xed, 0xc3, 0xc4,
+  0x63, 0x17, 0x86, 0xc9, 0xca, 0x49, 0x3c, 0xdd, 0xb5, 0xf6, 0xcb, 0x47,
+  0x35, 0x34, 0xe9, 0x1a, 0x48, 0x4a, 0x44, 0xaf, 0xe2, 0xc6, 0xaf, 0x8d,
+  0xce, 0x0e, 0x7e, 0xda, 0x6f, 0xd4, 0xd0, 0xb1, 0x6f, 0xa4, 0x59, 0x12,
+  0xf7, 0x14, 0x15, 0x5e, 0x11, 0x3c, 0xc3, 0x18, 0x75, 0xec, 0x74, 0x6d,
+  0x96, 0x0a, 0x58, 0xee, 0xa6, 0x48, 0x54, 0x2c, 0x75, 0x28, 0x59, 0x73,
+  0xb8, 0xcf, 0x70, 0x74, 0x92, 0x8a, 0x4a, 0x0a, 0x8a, 0x59, 0x96, 0x7f,
+  0x0e, 0x9e, 0xad, 0xd8, 0xb4, 0x0f, 0xfe, 0x21, 0xfe, 0x1f, 0xef, 0xfa,
+  0x68, 0xae, 0x1a, 0x92, 0x49, 0xa8, 0xe5, 0x12, 0x48, 0xce, 0x12, 0x5f,
+  0x26, 0xfd, 0x0f, 0xa8, 0xd2, 0x66, 0xf7, 0x0b, 0x71, 0xae, 0x03, 0x78,
+  0x86, 0x9a, 0xa2, 0x9a, 0x17, 0xa5, 0xb5, 0x43, 0xfc, 0xc6, 0x89, 0xb9,
+  0x14, 0x1e, 0xe7, 0x7d, 0xbf, 0xd3, 0x59, 0xc5, 0x9a, 0x92, 0x15, 0xa7,
+  0x8e, 0x26, 0x86, 0x46, 0xac, 0xf1, 0x49, 0x98, 0xb6, 0xd8, 0x39, 0xdf,
+  0x27, 0xb6, 0x0f, 0x6d, 0x6c, 0x54, 0x6a, 0x95, 0x02, 0x29, 0x65, 0x24,
+  0xca, 0x23, 0xfa, 0x86, 0xc7, 0x39, 0xdf, 0xfb, 0x7e, 0xfa, 0xab, 0x71,
+  0x8d, 0x25, 0x35, 0x3d, 0xd1, 0xe7, 0x76, 0x31, 0xc1, 0x30, 0xf1, 0x58,
+  0x29, 0xfa, 0xe4, 0x1b, 0x15, 0xfc, 0xee, 0x7f, 0x1a, 0xac, 0x19, 0x29,
+  0xb1, 0xd8, 0x1f, 0x20, 0xaf, 0x5c, 0x69, 0x21, 0x45, 0x3e, 0x49, 0x1c,
+  0x0f, 0x0c, 0x46, 0xdb, 0x10, 0x47, 0x5c, 0x0c, 0x02, 0xc7, 0xae, 0x4f,
+  0x4d, 0x75, 0x44, 0xf1, 0x07, 0x0e, 0xc0, 0xa3, 0xa3, 0x06, 0x96, 0x51,
+  0x21, 0x27, 0x1f, 0xe0, 0x5f, 0xb9, 0xfe, 0xda, 0x46, 0x6a, 0x67, 0x92,
+  0x59, 0x26, 0xa7, 0x79, 0x23, 0x55, 0xd8, 0x21, 0xfa, 0x98, 0x74, 0xeb,
+  0x8d, 0x1d, 0x0d, 0x4c, 0x8a, 0x64, 0x91, 0x89, 0x42, 0x1b, 0x99, 0x54,
+  0x11, 0xb9, 0xfc, 0x7d, 0xf5, 0xa4, 0xdf, 0x10, 0x5b, 0xcc, 0x6a, 0x79,
+  0x1d, 0x97, 0x9a, 0x10, 0xac, 0x47, 0xaa, 0xef, 0xa5, 0xb4, 0xcc, 0xd2,
+  0x4a, 0x22, 0x2c, 0xa8, 0xe7, 0xb4, 0x87, 0x1b, 0x7a, 0xe7, 0x4d, 0x4c,
+  0xae, 0xf5, 0x45, 0x98, 0x02, 0x5c, 0x73, 0x1f, 0x4d, 0xf7, 0xd7, 0xeb,
+  0x7c, 0xd1, 0x2c, 0x35, 0x08, 0xd4, 0xc7, 0x92, 0x6c, 0x2b, 0x33, 0x0e,
+  0x60, 0xbb, 0xef, 0xbf, 0x6e, 0xdf, 0xa6, 0xa1, 0x05, 0xb2, 0x24, 0xb8,
+  0x25, 0xc9, 0x25, 0x8f, 0x36, 0xfa, 0x82, 0xae, 0xa5, 0x29, 0x60, 0x0c,
+  0x06, 0xe3, 0x1f, 0xae, 0x8d, 0xb8, 0x47, 0x1c, 0x55, 0x07, 0xc2, 0xa9,
+  0x2c, 0x87, 0x3c, 0xa7, 0xaa, 0x8f, 0x63, 0xe9, 0xa4, 0xb7, 0xa6, 0x32,
+  0x4e, 0x90, 0x73, 0x0c, 0x28, 0xe6, 0x38, 0xf5, 0xd4, 0x02, 0x7e, 0x28,
+  0xf9, 0x4b, 0x70, 0x9a, 0x9a, 0xbd, 0xaa, 0x11, 0xbc, 0x8d, 0x91, 0x8e,
+  0xc7, 0xef, 0xab, 0x62, 0x55, 0x25, 0xca, 0x89, 0x57, 0xc5, 0x63, 0x4e,
+  0x76, 0x92, 0x32, 0x7a, 0x7a, 0x7e, 0x87, 0x1a, 0xa4, 0x26, 0x54, 0x95,
+  0xd5, 0x9b, 0x85, 0xff, 0x00, 0xfc, 0x57, 0x1e, 0xa7, 0x4a, 0x66, 0x7c,
+  0x55, 0xbd, 0x26, 0x7e, 0xa9, 0x53, 0x4f, 0x51, 0x1c, 0x4a, 0xcc, 0x6a,
+  0x89, 0xdc, 0x93, 0x84, 0xe5, 0xf7, 0xd3, 0x2a, 0x74, 0x96, 0x4a, 0x69,
+  0x97, 0xc4, 0x09, 0x19, 0x19, 0x24, 0xf4, 0xeb, 0xa5, 0x15, 0x33, 0x78,
+  0x26, 0xbd, 0xa6, 0xe6, 0x66, 0x7c, 0x2a, 0x38, 0xfe, 0x91, 0xe9, 0xa6,
+  0x7e, 0x1b, 0x25, 0xa6, 0x09, 0x26, 0x24, 0x73, 0xa0, 0x0c, 0x73, 0xd7,
+  0x1f, 0xf8, 0xd1, 0x35, 0xd3, 0x1f, 0xac, 0xc7, 0xfd, 0x35, 0x21, 0x64,
+  0xe9, 0x0a, 0x8c, 0x46, 0x79, 0xc0, 0xdb, 0x9b, 0xdf, 0x51, 0x59, 0xe9,
+  0x7e, 0x66, 0xf5, 0x0a, 0x15, 0xca, 0x2b, 0x73, 0xb6, 0xfd, 0x86, 0x88,
+  0x48, 0x8c, 0xaa, 0x4c, 0x43, 0x2b, 0xbe, 0xda, 0x71, 0xc3, 0x76, 0xe9,
+  0x21, 0xfe, 0x7b, 0xaf, 0x99, 0xdb, 0x39, 0xf6, 0xd1, 0x98, 0x10, 0xe2,
+  0xa5, 0x39, 0xa5, 0x2c, 0xa7, 0xa0, 0x03, 0x41, 0xd5, 0x40, 0x85, 0x9e,
+  0x37, 0xce, 0x64, 0xe5, 0xc1, 0x27, 0xa1, 0x3a, 0x32, 0x5c, 0x78, 0x87,
+  0x1d, 0x73, 0xa8, 0xfe, 0x5c, 0xcd, 0x59, 0xe1, 0xc8, 0xab, 0x24, 0x52,
+  0x27, 0x9c, 0x1f, 0x4c, 0x63, 0x1f, 0xdb, 0x41, 0x3a, 0xf6, 0x00, 0x3d,
+  0x45, 0x24, 0x94, 0xf2, 0x98, 0x88, 0xc1, 0xf5, 0xd4, 0xd3, 0xda, 0xfc,
+  0x68, 0x52, 0x96, 0x45, 0x67, 0x86, 0x68, 0xc4, 0xa1, 0xb3, 0x83, 0xcd,
+  0xdc, 0x7d, 0x86, 0xa6, 0xb9, 0xd3, 0xc9, 0xcf, 0x12, 0xc0, 0xbe, 0x45,
+  0xc0, 0x03, 0xd1, 0x40, 0xe9, 0xa6, 0x75, 0x17, 0xa9, 0x85, 0x9e, 0x92,
+  0x8d, 0x59, 0x55, 0x0b, 0xb6, 0x58, 0x0d, 0x94, 0xf4, 0x0a, 0x4f, 0xed,
+  0xa4, 0x2c, 0x91, 0x95, 0x32, 0x14, 0xca, 0x5b, 0x44, 0x95, 0xf5, 0x1c,
+  0xbc, 0x8e, 0xa2, 0x36, 0xc1, 0x77, 0x1d, 0x48, 0xd5, 0xba, 0x9a, 0xdb,
+  0x24, 0x86, 0x2a, 0x68, 0x91, 0x9d, 0xdb, 0x08, 0x8b, 0xcb, 0xb9, 0x3e,
+  0x9a, 0x8e, 0x3a, 0xe9, 0xe1, 0x26, 0x07, 0x44, 0x56, 0x2d, 0x8c, 0x95,
+  0xdf, 0x4c, 0xa8, 0x3c, 0x29, 0x1a, 0x28, 0xea, 0x64, 0x78, 0xd9, 0x66,
+  0x59, 0x04, 0x88, 0x3a, 0x01, 0xdb, 0xef, 0xd3, 0xf4, 0xd3, 0x3e, 0x47,
+  0x77, 0x22, 0x16, 0x9b, 0x27, 0x04, 0x45, 0x2d, 0xbd, 0xda, 0x69, 0x2b,
+  0xe9, 0xeb, 0x60, 0x89, 0xd9, 0xa9, 0xa3, 0xa5, 0x32, 0xe4, 0x8c, 0xee,
+  0x4e, 0x40, 0x51, 0xb6, 0xa9, 0x74, 0xf4, 0xed, 0xcc, 0x55, 0xb1, 0xe5,
+  0xd6, 0xf3, 0x5b, 0x61, 0x9a, 0xff, 0x00, 0x60, 0xf9, 0xee, 0x1c, 0xe3,
+  0x79, 0x6a, 0x65, 0x31, 0x05, 0x96, 0x92, 0x47, 0x11, 0x07, 0x00, 0x64,
+  0xae, 0x07, 0x43, 0xee, 0x73, 0x9c, 0x1d, 0xf5, 0x4b, 0xe0, 0x4b, 0x7d,
+  0x96, 0x3b, 0xe4, 0x53, 0xf1, 0x0d, 0x34, 0x86, 0x28, 0x58, 0x23, 0x44,
+  0x98, 0x0a, 0xc4, 0x11, 0xe6, 0x3e, 0xa3, 0xed, 0xff, 0x00, 0x4d, 0x0f,
+  0xd2, 0x7e, 0x5e, 0xca, 0xa6, 0x9a, 0xbf, 0x62, 0xab, 0x4f, 0x0f, 0x57,
+  0xc1, 0x43, 0x4b, 0x75, 0xaa, 0xa6, 0x78, 0xa9, 0xaa, 0x8f, 0x2d, 0x3c,
+  0xa4, 0xec, 0xe0, 0x75, 0xfd, 0xf5, 0xe8, 0xcf, 0x86, 0xb7, 0x29, 0x2b,
+  0xb8, 0x6e, 0x18, 0xa6, 0x6c, 0xcd, 0x4c, 0x04, 0x6d, 0xee, 0xb8, 0xf2,
+  0x9f, 0xd3, 0x4c, 0xab, 0xed, 0x96, 0xdb, 0xcd, 0x84, 0x51, 0xa2, 0x45,
+  0xf2, 0x92, 0xc4, 0xa6, 0x06, 0x88, 0x00, 0x14, 0x63, 0x2a, 0x57, 0x1d,
+  0x34, 0x2f, 0x06, 0xd9, 0xaa, 0x2c, 0xf4, 0xf3, 0x47, 0x55, 0x22, 0x49,
+  0x24, 0x8c, 0x30, 0xcb, 0xdd, 0x54, 0x60, 0x67, 0xdf, 0x1a, 0xd7, 0x8e,
+  0x1b, 0x65, 0xb8, 0xd7, 0x0c, 0x7b, 0x58, 0x48, 0xe1, 0xfb, 0x79, 0xbc,
+  0xcd, 0x72, 0x7a, 0x68, 0x24, 0x69, 0x54, 0x64, 0x32, 0x03, 0xca, 0xc3,
+  0xb8, 0xcf, 0xaf, 0xf9, 0x68, 0xf8, 0x68, 0x69, 0x61, 0x04, 0x45, 0x4d,
+  0x02, 0x02, 0x72, 0x71, 0x18, 0x19, 0x3a, 0x23, 0x7d, 0x55, 0x38, 0xeb,
+  0x8b, 0xa0, 0xe1, 0xe8, 0x8c, 0x08, 0x04, 0x95, 0xae, 0xb9, 0x44, 0xcf,
+  0xd2, 0x3d, 0x4e, 0x9d, 0x63, 0x5d, 0x25, 0x6c, 0x0f, 0x8e, 0x78, 0x6e,
+  0xeb, 0x53, 0x23, 0xd7, 0x58, 0xaa, 0x42, 0x54, 0x4a, 0x04, 0x6f, 0x0b,
+  0x72, 0x85, 0x2a, 0x06, 0xc5, 0x72, 0x30, 0x0e, 0x7b, 0xfb, 0xeb, 0x14,
+  0xe3, 0x19, 0x78, 0x8a, 0x9e, 0xe5, 0xf2, 0xf7, 0xa7, 0xaa, 0x15, 0x51,
+  0x6c, 0x04, 0xec, 0x58, 0x72, 0xf6, 0x03, 0x7c, 0x6a, 0xfd, 0x6e, 0xe2,
+  0x7f, 0x88, 0x57, 0x27, 0x15, 0x16, 0xda, 0x69, 0x6a, 0x62, 0x0f, 0xbf,
+  0xf2, 0x70, 0x9f, 0xf8, 0xd7, 0x5c, 0x6b, 0x6a, 0xe3, 0xae, 0x2e, 0xa4,
+  0xa3, 0x82, 0xb6, 0xcb, 0x49, 0x4f, 0xf2, 0xef, 0xce, 0x24, 0x59, 0x57,
+  0x3b, 0x8c, 0x1c, 0x8e, 0x62, 0x7d, 0xfa, 0x6a, 0xb7, 0x19, 0x9a, 0x8e,
+  0x4e, 0x8f, 0x34, 0x71, 0x50, 0xf1, 0x38, 0x92, 0xec, 0xb9, 0xc0, 0x35,
+  0x53, 0x2f, 0xea, 0xe7, 0x59, 0x84, 0x71, 0x73, 0x49, 0x22, 0xe7, 0x04,
+  0x31, 0xdf, 0x5a, 0x5f, 0x15, 0x48, 0xe9, 0xc4, 0xd7, 0x99, 0x1a, 0x36,
+  0x58, 0x23, 0xab, 0x97, 0x2c, 0x47, 0x52, 0x64, 0x3d, 0x35, 0x9f, 0x53,
+  0x52, 0xd4, 0x2d, 0x1b, 0xd6, 0x3a, 0xaa, 0xc5, 0x25, 0x43, 0x04, 0xf3,
+  0x79, 0xba, 0x9e, 0xda, 0xc9, 0x36, 0xab, 0x83, 0x3c, 0xfe, 0xcc, 0x85,
+  0x56, 0x35, 0x04, 0x18, 0xcb, 0x39, 0xdb, 0x39, 0xfd, 0xf5, 0x24, 0x23,
+  0xc3, 0x8d, 0x99, 0x8e, 0xfd, 0x0f, 0xbe, 0x88, 0x86, 0x9f, 0xc4, 0x26,
+  0x42, 0x3c, 0xa8, 0x32, 0x75, 0xc3, 0x46, 0x67, 0x94, 0x3b, 0x82, 0x91,
+  0x2f, 0x4d, 0xb3, 0xb6, 0x84, 0xa3, 0x9a, 0x05, 0x06, 0xba, 0x29, 0x58,
+  0x75, 0x70, 0x18, 0xfd, 0xce, 0xa7, 0xbf, 0x57, 0xbc, 0xd7, 0x45, 0x46,
+  0x93, 0x09, 0x0c, 0x62, 0x12, 0x40, 0xd8, 0x90, 0x49, 0xce, 0x84, 0xab,
+  0x7c, 0x05, 0xf0, 0xf6, 0x03, 0x6d, 0x07, 0x2e, 0x49, 0xcf, 0xeb, 0xa5,
+  0x86, 0xb8, 0x54, 0x4b, 0x3c, 0xb1, 0x4e, 0x08, 0x40, 0x4e, 0x07, 0x36,
+  0x74, 0xe7, 0x87, 0xa6, 0x9a, 0xa6, 0x9d, 0x8c, 0x7b, 0xc9, 0x4e, 0x07,
+  0x36, 0xfd, 0x06, 0x90, 0x40, 0xb8, 0x32, 0x30, 0xe8, 0x50, 0xff, 0x00,
+  0x96, 0xaf, 0x1c, 0x07, 0x4e, 0x23, 0xb4, 0xbc, 0xb2, 0x79, 0x44, 0x8d,
+  0x91, 0xb7, 0x5d, 0x1c, 0x08, 0x13, 0x41, 0x73, 0xe5, 0x0b, 0xce, 0xd8,
+  0xf3, 0x6c, 0x74, 0x25, 0x45, 0xc6, 0x9d, 0x24, 0xb8, 0xcf, 0x1c, 0x73,
+  0xc8, 0xd1, 0x48, 0xac, 0x44, 0x5d, 0x48, 0xd9, 0x48, 0xc7, 0xa0, 0x38,
+  0xd2, 0xcb, 0x95, 0x3c, 0xd4, 0xb7, 0x59, 0x24, 0x15, 0x29, 0x35, 0x20,
+  0x93, 0x9c, 0x28, 0x18, 0x3e, 0xbc, 0xb9, 0xec, 0x75, 0xfa, 0xd5, 0x5f,
+  0x25, 0x0c, 0x73, 0xac, 0x30, 0xa8, 0x59, 0xf7, 0x04, 0xef, 0x91, 0xe9,
+  0xa6, 0x3e, 0x43, 0x53, 0xa7, 0x63, 0x08, 0x2e, 0x10, 0x57, 0x94, 0x9a,
+  0x5a, 0x42, 0x7f, 0x9b, 0xc8, 0x5f, 0xc3, 0xce, 0xfe, 0xa7, 0xfd, 0x75,
+  0x6a, 0xb4, 0x52, 0xcf, 0x35, 0x72, 0x3a, 0x55, 0xf8, 0x74, 0xb1, 0x27,
+  0x99, 0x00, 0xc7, 0x30, 0xed, 0x8d, 0xf6, 0xd5, 0x0a, 0x20, 0x83, 0x3c,
+  0x9e, 0x54, 0x24, 0x92, 0x80, 0xec, 0x09, 0x39, 0x3a, 0xb8, 0x70, 0xf5,
+  0x47, 0x3d, 0x02, 0xc5, 0xcf, 0xba, 0x80, 0x31, 0xed, 0xdb, 0x48, 0x71,
+  0xe6, 0x8b, 0x94, 0xf7, 0x16, 0xd8, 0x04, 0xe0, 0xbb, 0xc2, 0x79, 0xe3,
+  0x62, 0x40, 0xef, 0x81, 0xe8, 0x75, 0xf1, 0xa9, 0x1e, 0x48, 0x8c, 0x35,
+  0x51, 0x2b, 0x21, 0x1f, 0x4b, 0x0c, 0x82, 0x34, 0x9a, 0xe6, 0x2e, 0x12,
+  0xd9, 0x8c, 0x56, 0xfa, 0xa6, 0x86, 0x74, 0xf3, 0x01, 0xda, 0x4f, 0xf9,
+  0x4f, 0xb7, 0x6d, 0x7d, 0xb1, 0x5c, 0xea, 0x2a, 0xad, 0xbe, 0x2c, 0x0e,
+  0x60, 0xa8, 0x21, 0x83, 0x20, 0x3d, 0x18, 0x1c, 0x11, 0xfa, 0xea, 0x2c,
+  0x39, 0x12, 0xab, 0x12, 0xa1, 0x6a, 0xc1, 0xae, 0xbc, 0x22, 0x99, 0xf1,
+  0x6d, 0x93, 0x78, 0x0c, 0x09, 0x26, 0x36, 0x3e, 0x56, 0x07, 0xa8, 0x1a,
+  0xac, 0xbc, 0x33, 0x51, 0xce, 0x52, 0x60, 0xd0, 0xbf, 0x39, 0x5f, 0x04,
+  0x8c, 0x96, 0x00, 0xf4, 0xfb, 0x1f, 0x5d, 0x5c, 0xe8, 0xb8, 0x88, 0x21,
+  0xf9, 0x6b, 0xcb, 0x2a, 0xcc, 0x84, 0xf8, 0xa0, 0x0c, 0xba, 0x8e, 0xcd,
+  0x8f, 0xea, 0x07, 0xae, 0xbe, 0x71, 0x9d, 0x95, 0x6f, 0xf6, 0xea, 0x5a,
+  0x9a, 0x09, 0xd7, 0xc7, 0x8b, 0x78, 0xa4, 0x4e, 0x92, 0x0f, 0x42, 0x7b,
+  0x68, 0xa3, 0x36, 0xbe, 0xcc, 0xd3, 0xa7, 0xc9, 0x2c, 0x7c, 0x48, 0xa2,
+  0xd6, 0xca, 0x5e, 0x4e, 0x45, 0x26, 0x08, 0x49, 0xca, 0xef, 0x9e, 0xfd,
+  0x34, 0x4d, 0xe7, 0xc3, 0xa7, 0xa5, 0x58, 0x39, 0xd5, 0xe4, 0x75, 0xc9,
+  0x03, 0x62, 0xbf, 0x8d, 0x09, 0x52, 0xe4, 0x43, 0x25, 0x1d, 0x50, 0x6f,
+  0x1a, 0x17, 0xc4, 0x6a, 0xe3, 0x0d, 0x11, 0x07, 0x7c, 0xff, 0x00, 0xae,
+  0xa0, 0xb9, 0x97, 0x79, 0x12, 0x69, 0x25, 0x67, 0x79, 0x06, 0x58, 0x9e,
+  0xb9, 0xd3, 0xce, 0x92, 0xe5, 0x59, 0x02, 0xb3, 0x3c, 0x8a, 0x07, 0xd3,
+  0xf4, 0x9c, 0xe8, 0x2a, 0xf4, 0x31, 0xb4, 0x8d, 0x9c, 0xef, 0x80, 0x71,
+  0xe9, 0xdb, 0x47, 0x40, 0xb9, 0x46, 0x61, 0xf5, 0x76, 0xd1, 0xf6, 0xdb,
+  0x1c, 0x97, 0xc9, 0x79, 0x96, 0x64, 0xa7, 0x8e, 0x22, 0x64, 0x9e, 0x46,
+  0xec, 0xa0, 0xe3, 0xf5, 0x3a, 0x19, 0xc9, 0x46, 0x2e, 0x4c, 0xc9, 0xa8,
+  0xe9, 0x15, 0xda, 0x0a, 0x67, 0xaa, 0x91, 0x55, 0x06, 0xed, 0xb9, 0x3e,
+  0x9a, 0xb9, 0x51, 0xdb, 0x65, 0x86, 0xdc, 0xa9, 0x19, 0x08, 0xc7, 0xbe,
+  0x3a, 0xe8, 0x8b, 0x6d, 0x3d, 0xb2, 0x28, 0xe6, 0x36, 0xb2, 0x1c, 0x09,
+  0x44, 0x63, 0xcd, 0x92, 0xd9, 0xd5, 0xda, 0xa6, 0xca, 0xd4, 0xfc, 0x25,
+  0x4a, 0xf2, 0x14, 0xf1, 0x9a, 0x56, 0xf2, 0xe7, 0x7c, 0xb6, 0xe3, 0x6f,
+  0xd7, 0x59, 0x33, 0x6a, 0x16, 0x2a, 0xbf, 0x62, 0x31, 0x64, 0x58, 0xe6,
+  0x9b, 0x33, 0x35, 0xa4, 0x96, 0x66, 0x82, 0x8d, 0x90, 0xb9, 0x33, 0x90,
+  0x40, 0xf4, 0xcf, 0xae, 0xae, 0x37, 0xdb, 0x34, 0xaf, 0x6a, 0xf9, 0x11,
+  0x16, 0x39, 0x23, 0x00, 0x7d, 0xc6, 0x35, 0x3a, 0x58, 0xea, 0x63, 0xf0,
+  0x2b, 0x17, 0xfe, 0x32, 0xb8, 0x21, 0x40, 0xdc, 0x6c, 0x7b, 0xfa, 0xfb,
+  0x6b, 0xb9, 0x78, 0x90, 0xd2, 0x31, 0xa7, 0xaf, 0xa7, 0x2f, 0x0c, 0x47,
+  0x1e, 0x2c, 0x6b, 0xe6, 0x66, 0x1e, 0xda, 0x44, 0xf3, 0x4b, 0x23, 0x4f,
+  0x13, 0xe8, 0x7f, 0xe4, 0x33, 0x47, 0x22, 0xac, 0x6e, 0xd0, 0x8e, 0x9e,
+  0xc9, 0xf2, 0x74, 0x86, 0x77, 0x41, 0x95, 0x19, 0x6d, 0xb7, 0xc7, 0xae,
+  0x8c, 0xa1, 0x96, 0x2f, 0x94, 0x59, 0x0b, 0x79, 0x1b, 0xa1, 0xc6, 0x98,
+  0x55, 0x5f, 0x53, 0xc2, 0x47, 0x36, 0xc9, 0x96, 0x49, 0x90, 0x98, 0xd2,
+  0x43, 0xca, 0x59, 0x7d, 0x4e, 0xda, 0x22, 0xc7, 0x60, 0xab, 0x9e, 0xde,
+  0x93, 0x25, 0x20, 0x82, 0x09, 0x14, 0x4a, 0xbc, 0xfe, 0x52, 0xca, 0x73,
+  0x83, 0x8e, 0xac, 0x36, 0x38, 0x3e, 0xc7, 0x5b, 0x74, 0xd3, 0x9c, 0xbe,
+  0xc6, 0x0c, 0x49, 0xfb, 0x2a, 0x95, 0xb7, 0xba, 0x6f, 0x9c, 0x6a, 0x3a,
+  0x5e, 0x71, 0x3f, 0xd2, 0x24, 0x65, 0xc2, 0x83, 0xdf, 0xef, 0xa6, 0x7c,
+  0x3c, 0x87, 0xe5, 0x5e, 0x49, 0x01, 0xf1, 0x41, 0xf3, 0x16, 0x18, 0x3c,
+  0xbd, 0x8e, 0x35, 0xdf, 0x11, 0xda, 0x61, 0xc1, 0x8a, 0x78, 0x44, 0xad,
+  0xcf, 0x91, 0x85, 0xc1, 0x23, 0xd3, 0x3a, 0xfa, 0x9e, 0x05, 0x02, 0x88,
+  0x69, 0xe5, 0xa9, 0x91, 0x7c, 0x24, 0x88, 0x09, 0x76, 0xe5, 0xee, 0x47,
+  0xe0, 0xe4, 0x68, 0xb5, 0x18, 0x9d, 0xd2, 0x18, 0xe2, 0xab, 0x83, 0xa9,
+  0xa6, 0x91, 0xe4, 0x25, 0x5f, 0xe9, 0xd9, 0x7d, 0xf1, 0xa6, 0x91, 0xd0,
+  0xd1, 0x85, 0x5a, 0x84, 0x60, 0x8b, 0x3e, 0x25, 0x0b, 0x9c, 0x05, 0x63,
+  0x8e, 0x6c, 0x67, 0xbe, 0x46, 0x92, 0x48, 0x09, 0xf2, 0x29, 0xc1, 0x03,
+  0x3a, 0x7d, 0x5f, 0x6b, 0xf0, 0x69, 0xe9, 0x92, 0xbe, 0x12, 0x95, 0x31,
+  0xc6, 0xac, 0x87, 0x39, 0xc0, 0x2a, 0x08, 0x3f, 0xbe, 0xb3, 0x4d, 0x52,
+  0xab, 0xa1, 0x32, 0x74, 0x45, 0xc4, 0x10, 0xd3, 0xb3, 0xc3, 0x55, 0x4d,
+  0x23, 0x4b, 0xcd, 0xb3, 0xf3, 0x30, 0x24, 0x37, 0x7c, 0xfe, 0x83, 0xf4,
+  0xd7, 0x74, 0x12, 0x52, 0xca, 0x82, 0x29, 0x1c, 0x09, 0x06, 0x06, 0xfd,
+  0x34, 0x2c, 0xce, 0xca, 0xe1, 0x0e, 0x32, 0x57, 0x25, 0xc0, 0xdd, 0xbd,
+  0x33, 0xa1, 0x95, 0x17, 0xc4, 0x75, 0x63, 0xb9, 0x39, 0x07, 0x53, 0x6e,
+  0xf8, 0x51, 0x1f, 0x45, 0xda, 0xc9, 0x6e, 0xa8, 0xa8, 0x12, 0xad, 0x2c,
+  0x4e, 0x59, 0x50, 0x15, 0x58, 0x50, 0xb9, 0x63, 0xef, 0x8e, 0x9d, 0x33,
+  0xa7, 0xb6, 0xae, 0x1f, 0xe2, 0x53, 0x22, 0x1a, 0x7b, 0x65, 0x53, 0x97,
+  0xc1, 0x52, 0xd1, 0x15, 0x18, 0xf7, 0x27, 0x4f, 0x7e, 0x0f, 0x71, 0x1c,
+  0x56, 0x9e, 0x12, 0xa8, 0xad, 0x8e, 0x8d, 0xdd, 0x68, 0xd9, 0x52, 0xb3,
+  0xc2, 0x4e, 0x63, 0xbe, 0x79, 0x5c, 0xfe, 0x32, 0x33, 0xdb, 0xf3, 0xab,
+  0xec, 0xdc, 0x61, 0x59, 0x3d, 0x96, 0x7a, 0xaa, 0x2a, 0x38, 0x9f, 0x9d,
+  0x39, 0xa0, 0x2d, 0x9c, 0x0d, 0xf0, 0x79, 0x94, 0xfe, 0x4e, 0x85, 0x69,
+  0xe3, 0x35, 0xcc, 0xa9, 0x95, 0xf1, 0xc2, 0xae, 0x4c, 0x17, 0x80, 0x38,
+  0xaa, 0x7a, 0x4b, 0x55, 0x35, 0x0d, 0xca, 0x95, 0x95, 0x10, 0x94, 0x12,
+  0x73, 0x67, 0x90, 0x0e, 0xc7, 0x6d, 0x68, 0xf0, 0xcb, 0x1c, 0xd1, 0x2c,
+  0xb1, 0x38, 0x74, 0x61, 0x95, 0x20, 0xec, 0x75, 0x90, 0xd0, 0xf1, 0x7d,
+  0xa9, 0x69, 0x4d, 0x15, 0x55, 0x15, 0x0b, 0xd4, 0x16, 0x69, 0x48, 0x4d,
+  0x83, 0x39, 0xea, 0x48, 0xc7, 0xa9, 0xd0, 0x75, 0x9c, 0x57, 0x79, 0x85,
+  0xfc, 0x6a, 0x6a, 0xd5, 0xa5, 0x45, 0x3b, 0x45, 0x1a, 0x0f, 0x0c, 0x7e,
+  0x3b, 0xf6, 0xd0, 0xad, 0x7c, 0x34, 0xbe, 0x32, 0x96, 0xe4, 0x37, 0x16,
+  0xad, 0x41, 0x53, 0x76, 0x6b, 0x37, 0x5b, 0xcd, 0xb6, 0x86, 0x51, 0x0d,
+  0x5c, 0xfe, 0x1b, 0x1d, 0xfe, 0x82, 0xd8, 0xfd, 0x3a, 0x69, 0x1d, 0xca,
+  0x8f, 0x82, 0x2b, 0xa9, 0xde, 0xef, 0x5c, 0xd4, 0x92, 0x2c, 0x6e, 0x26,
+  0x7a, 0x89, 0x1f, 0xcd, 0xb7, 0x62, 0x4e, 0xe4, 0x7f, 0xcb, 0xfb, 0x6a,
+  0x8b, 0x4f, 0x37, 0x13, 0xdd, 0x2a, 0x24, 0x28, 0x68, 0x9c, 0xcc, 0x7f,
+  0x99, 0x2b, 0xf3, 0x2f, 0x20, 0xc6, 0xf9, 0x1f, 0xa7, 0x7d, 0x2c, 0xb9,
+  0x5b, 0x28, 0x64, 0x95, 0xbf, 0x8f, 0xf1, 0x3d, 0x24, 0x4b, 0x8c, 0x98,
+  0xe9, 0x50, 0xcb, 0x8f, 0xf4, 0xd1, 0x43, 0xf2, 0x73, 0xc9, 0xcc, 0x63,
+  0xc0, 0x6f, 0x52, 0xdf, 0xa0, 0x8e, 0x30, 0xf8, 0x8d, 0x51, 0x24, 0x92,
+  0xd2, 0xda, 0xa5, 0x11, 0x52, 0xae, 0x52, 0x24, 0x89, 0x79, 0x7c, 0x9d,
+  0xbe, 0xdd, 0xb6, 0xd4, 0x7c, 0x03, 0x7d, 0xe2, 0xeb, 0xed, 0x44, 0x76,
+  0x5b, 0x4d, 0x5c, 0x54, 0x28, 0x01, 0x92, 0x59, 0x79, 0x01, 0x60, 0x32,
+  0x32, 0xc7, 0x3d, 0x7a, 0x8f, 0x4d, 0x65, 0x9c, 0x45, 0x76, 0xa2, 0xa4,
+  0xaa, 0x96, 0x2b, 0x7b, 0x3b, 0x53, 0x87, 0x22, 0x27, 0x91, 0x40, 0x76,
+  0x1d, 0xbe, 0xd9, 0xd1, 0xdc, 0x1f, 0xc5, 0xf7, 0xa5, 0x34, 0xb6, 0x4b,
+  0x2d, 0x33, 0x47, 0x3c, 0xf3, 0x79, 0x8d, 0x39, 0xc4, 0xb2, 0x92, 0x73,
+  0xe6, 0x6c, 0x74, 0x03, 0xdc, 0x0e, 0xa7, 0x4d, 0xc2, 0xf2, 0x39, 0xdb,
+  0x17, 0x8d, 0xc9, 0xca, 0xdb, 0x28, 0x1c, 0x62, 0x3c, 0x4b, 0xb5, 0xd9,
+  0x47, 0xd0, 0x2e, 0x13, 0x78, 0x8b, 0xdc, 0x8e, 0x73, 0xbe, 0x94, 0x5c,
+  0x62, 0xa1, 0xa3, 0x31, 0x3c, 0x71, 0x7f, 0xbb, 0xc8, 0xbf, 0xe2, 0xe8,
+  0x74, 0xc7, 0x89, 0xa1, 0xa9, 0x6e, 0x2a, 0xba, 0xf3, 0x30, 0x78, 0xcd,
+  0x74, 0xe7, 0x04, 0x63, 0x6e, 0x76, 0xdb, 0xf1, 0xa5, 0x35, 0x54, 0x72,
+  0x4c, 0xa2, 0x9c, 0x4a, 0xa4, 0x7d, 0x5c, 0xad, 0xb7, 0x4e, 0xc0, 0xe9,
+  0xf4, 0xfd, 0x03, 0x3f, 0xb3, 0x01, 0xe4, 0xf9, 0xa2, 0xb1, 0x44, 0x79,
+  0x63, 0xea, 0x7f, 0xe6, 0x3a, 0x31, 0x6d, 0x63, 0x90, 0xbc, 0x84, 0x72,
+  0x85, 0xc7, 0x36, 0x0e, 0xc3, 0xf1, 0xaf, 0x94, 0xf5, 0x46, 0x89, 0x92,
+  0x13, 0x44, 0xf1, 0xb1, 0x50, 0x57, 0xc4, 0xdb, 0x27, 0x44, 0x45, 0x77,
+  0xa2, 0x69, 0x58, 0xd4, 0x48, 0xef, 0x57, 0x1b, 0x7f, 0xc2, 0x44, 0xf2,
+  0xae, 0xff, 0x00, 0xf7, 0xbe, 0xaf, 0xc2, 0xae, 0x4c, 0x15, 0xd5, 0x95,
+  0xda, 0xdb, 0x5d, 0x5c, 0x6f, 0x98, 0xe2, 0x95, 0xd3, 0x19, 0x07, 0xc3,
+  0xc6, 0x47, 0xae, 0x35, 0x0d, 0x25, 0xb2, 0xba, 0xae, 0x46, 0x8a, 0x2a,
+  0x66, 0x2c, 0xa4, 0x73, 0x0c, 0x7d, 0x20, 0xf4, 0x27, 0x57, 0x19, 0x2b,
+  0x94, 0x4c, 0x2a, 0x15, 0x0c, 0x4e, 0xbb, 0x60, 0xff, 0x00, 0xa6, 0x99,
+  0x70, 0xa5, 0x31, 0x4a, 0x0a, 0xa9, 0xd4, 0x78, 0x93, 0xcd, 0x29, 0x76,
+  0xed, 0xb1, 0xd6, 0x5e, 0xdf, 0x03, 0x0a, 0xb4, 0x1c, 0x33, 0x24, 0x7c,
+  0xb4, 0x2b, 0x2a, 0x3d, 0x44, 0xaa, 0x64, 0x73, 0xd0, 0x2a, 0x82, 0x32,
+  0x3d, 0xfa, 0xeb, 0xbb, 0xb5, 0x49, 0xa5, 0x46, 0xa3, 0xa6, 0x99, 0xbc,
+  0x15, 0xc2, 0xe0, 0x1d, 0x89, 0x03, 0x1f, 0xa6, 0xac, 0x75, 0xee, 0xf4,
+  0xd5, 0xd2, 0xc9, 0x51, 0x1b, 0x20, 0x92, 0x97, 0x11, 0xb6, 0x36, 0xfa,
+  0xba, 0x67, 0xf1, 0xaa, 0x95, 0x73, 0x47, 0x33, 0x15, 0x41, 0xd3, 0xbf,
+  0xae, 0xb6, 0x6d, 0xa4, 0x40, 0x15, 0x12, 0x54, 0xcd, 0x1d, 0x3a, 0xe0,
+  0x07, 0x38, 0xc0, 0xe8, 0x34, 0xc5, 0xe0, 0x64, 0x41, 0x1b, 0x6c, 0x54,
+  0x6c, 0x3d, 0x34, 0xbe, 0xdd, 0xe2, 0x45, 0x71, 0x0e, 0x9f, 0x50, 0xdc,
+  0x1d, 0x3e, 0xf0, 0xe7, 0xa8, 0x4c, 0xcc, 0xc0, 0xef, 0xbe, 0xaa, 0x3d,
+  0x94, 0x28, 0x65, 0xc3, 0x6e, 0x37, 0xd3, 0x0b, 0x65, 0x63, 0xd2, 0xb2,
+  0xbc, 0x6f, 0xb8, 0x6c, 0x91, 0xed, 0xaf, 0xd2, 0xd0, 0xcb, 0xe1, 0xb1,
+  0x5c, 0x72, 0xaf, 0x56, 0x63, 0x80, 0x34, 0xbe, 0x17, 0x4e, 0x40, 0x7b,
+  0x8c, 0xfe, 0xfa, 0x94, 0x59, 0xa6, 0x50, 0xc8, 0x92, 0xa2, 0xcc, 0x87,
+  0xf9, 0x6e, 0x9c, 0xde, 0xb8, 0xd0, 0xf4, 0x94, 0xe9, 0x05, 0x75, 0x50,
+  0x0a, 0x02, 0xca, 0xc2, 0x55, 0xfb, 0x91, 0x83, 0xfd, 0xbf, 0x7d, 0x07,
+  0xc2, 0x12, 0x78, 0xb6, 0x7c, 0xe3, 0xfe, 0x1b, 0x60, 0x0f, 0x63, 0xa3,
+  0x2b, 0x65, 0x29, 0x71, 0xa7, 0x32, 0x48, 0xb1, 0xc4, 0x62, 0x39, 0x76,
+  0x3b, 0x64, 0x11, 0x81, 0xa9, 0x40, 0x47, 0xb1, 0x17, 0x18, 0x43, 0x3f,
+  0xf1, 0x9a, 0x0a, 0xda, 0x2a, 0x66, 0x91, 0xd5, 0x5c, 0x4e, 0x14, 0xee,
+  0xc1, 0x46, 0x41, 0xfd, 0xf5, 0x15, 0x92, 0xeb, 0x5d, 0x68, 0xa5, 0xf9,
+  0xb6, 0x71, 0x2b, 0x99, 0x83, 0xcb, 0x4e, 0xe7, 0x39, 0xce, 0x70, 0x40,
+  0xec, 0x71, 0xdf, 0x5f, 0xae, 0x55, 0x15, 0x17, 0xdb, 0x89, 0x96, 0xd9,
+  0x28, 0x86, 0x9e, 0x89, 0x49, 0x91, 0xe4, 0x7f, 0x0c, 0xc9, 0xb6, 0x4f,
+  0x2e, 0x77, 0xea, 0x31, 0xf8, 0xd0, 0x6f, 0x1a, 0xca, 0x6a, 0x24, 0x97,
+  0x2e, 0xae, 0xc1, 0x06, 0x5b, 0x3c, 0xc4, 0x75, 0x27, 0xd7, 0x52, 0x93,
+  0x54, 0xce, 0x8e, 0x2a, 0x9c, 0x29, 0xa3, 0x43, 0xab, 0xb3, 0x5a, 0x38,
+  0xae, 0x85, 0x2b, 0x56, 0x23, 0x1c, 0xc1, 0x7c, 0xb2, 0xa7, 0xd6, 0x87,
+  0xd0, 0xfa, 0x8d, 0x51, 0x78, 0xa3, 0x86, 0x2e, 0x16, 0xb8, 0xfc, 0x59,
+  0x23, 0x33, 0xc4, 0x36, 0x33, 0x46, 0x3f, 0x72, 0x3b, 0x6a, 0xcd, 0xc0,
+  0xb7, 0xe8, 0xa9, 0x7f, 0xfa, 0x7c, 0xbf, 0xcb, 0x5e, 0x63, 0xe1, 0x9c,
+  0xec, 0x3d, 0xb5, 0x7f, 0x0c, 0x93, 0x47, 0xb8, 0x0c, 0xa7, 0xa8, 0xd2,
+  0x37, 0x38, 0x3a, 0x7c, 0x99, 0xa7, 0x97, 0x26, 0x9d, 0xd7, 0xa3, 0xcf,
+  0xf6, 0xe0, 0xaf, 0x1c, 0xc3, 0x38, 0xe8, 0x41, 0xfb, 0x6d, 0xa6, 0xd6,
+  0x8a, 0x3a, 0x99, 0xec, 0xb5, 0x66, 0x2a, 0x81, 0x4e, 0xbb, 0x82, 0x4a,
+  0x92, 0x09, 0x2d, 0xd3, 0x6f, 0xb6, 0x8e, 0xf8, 0xad, 0x45, 0x4f, 0x6f,
+  0xe2, 0xaa, 0x24, 0xa3, 0x8c, 0x43, 0x1d, 0x54, 0x1c, 0xcd, 0x1a, 0x0c,
+  0x2f, 0x30, 0x27, 0xcd, 0xf7, 0xd7, 0x74, 0x73, 0x46, 0x6c, 0xc9, 0x47,
+  0x17, 0xf2, 0xf0, 0xdc, 0xcd, 0x8d, 0xf7, 0x3d, 0x75, 0x32, 0x4e, 0xe9,
+  0x0c, 0xcd, 0x3d, 0xf0, 0x8b, 0x06, 0xb1, 0xd3, 0xc9, 0x41, 0x6f, 0xf1,
+  0x50, 0xa8, 0x74, 0x97, 0x99, 0x64, 0xcf, 0x5d, 0xf3, 0xfa, 0xeb, 0x5e,
+  0xe1, 0xa5, 0x3c, 0x79, 0xf1, 0x16, 0x8a, 0x9a, 0xd1, 0x0d, 0x55, 0xae,
+  0x8d, 0x60, 0xe4, 0x90, 0xcd, 0x27, 0x3b, 0x04, 0x2b, 0xfc, 0xc2, 0x01,
+  0xff, 0x00, 0x10, 0x3f, 0xbe, 0xb3, 0x6b, 0x5f, 0x83, 0x15, 0x39, 0x12,
+  0x29, 0x2e, 0x58, 0x88, 0x80, 0xe8, 0x0f, 0xa9, 0x1a, 0x63, 0xc3, 0xb7,
+  0x4e, 0x29, 0xb4, 0xde, 0x3e, 0x6a, 0x82, 0xb1, 0xe2, 0x98, 0x73, 0x24,
+  0x6d, 0x1a, 0xe7, 0x00, 0xec, 0x40, 0xfc, 0x77, 0xd2, 0xf2, 0xe4, 0x86,
+  0xeb, 0x92, 0xe8, 0xcb, 0x29, 0xf2, 0x8b, 0xdd, 0xd1, 0x28, 0xed, 0xb7,
+  0xaa, 0x9b, 0x75, 0x2d, 0x4c, 0x6f, 0x0c, 0x32, 0xbc, 0x4a, 0x92, 0x1f,
+  0x3e, 0x15, 0xb1, 0xe6, 0x1e, 0xbb, 0x68, 0xde, 0x0b, 0xe0, 0xbe, 0x17,
+  0xe2, 0x0b, 0xdd, 0x7b, 0x5c, 0xe5, 0xa8, 0x89, 0xe3, 0x8b, 0xe6, 0xa1,
+  0x2b, 0x22, 0x88, 0x9b, 0x0a, 0x32, 0x47, 0xe7, 0x72, 0x35, 0x44, 0xe2,
+  0x5a, 0x49, 0xe4, 0xba, 0xc7, 0x70, 0x84, 0x08, 0xe6, 0x91, 0x33, 0x50,
+  0x06, 0xc0, 0x38, 0xeb, 0xb7, 0xbe, 0x73, 0xf7, 0xce, 0x9e, 0xf0, 0x7c,
+  0x52, 0xbd, 0xa1, 0x1e, 0x4d, 0xbc, 0x09, 0x48, 0x76, 0x0f, 0xe6, 0xf3,
+  0x6f, 0x9c, 0x7a, 0x7f, 0xd3, 0x5c, 0xb8, 0xe5, 0x58, 0x5b, 0xcb, 0x1e,
+  0x53, 0x33, 0xef, 0xa7, 0x67, 0xce, 0x0f, 0xf8, 0x75, 0x5d, 0xc5, 0x57,
+  0xab, 0x8d, 0x5b, 0xa1, 0x78, 0x69, 0xb9, 0x9d, 0xd8, 0x37, 0xd6, 0xd9,
+  0xf2, 0xa0, 0xf6, 0xc1, 0x3a, 0x9b, 0x8a, 0x6a, 0x20, 0xe1, 0xf4, 0x92,
+  0x89, 0xd4, 0xad, 0x74, 0x51, 0x08, 0x84, 0x6c, 0x30, 0xf1, 0xa0, 0xfa,
+  0x57, 0x1d, 0x80, 0xdf, 0x57, 0xee, 0x1b, 0xe2, 0xfa, 0x8a, 0x3b, 0x74,
+  0x96, 0xfa, 0x0a, 0x95, 0xa6, 0x09, 0x2f, 0x95, 0xd9, 0x72, 0x5d, 0xb1,
+  0xbe, 0x07, 0xa6, 0x4e, 0xaa, 0x3c, 0x6d, 0xc5, 0x7c, 0x41, 0x57, 0x53,
+  0x2a, 0x57, 0xdb, 0xed, 0x13, 0xa0, 0xc8, 0x69, 0x85, 0x0a, 0x17, 0x91,
+  0x7a, 0x0c, 0xb9, 0x05, 0x81, 0xe8, 0x76, 0x23, 0x5b, 0xf4, 0xb9, 0xf1,
+  0xea, 0x9d, 0xc1, 0xb5, 0x43, 0xa1, 0x35, 0x2e, 0x8c, 0xb5, 0x65, 0xa9,
+  0xaf, 0x97, 0xc4, 0xaa, 0x9d, 0xdc, 0x86, 0xca, 0xa3, 0x1c, 0x80, 0x3d,
+  0x46, 0x88, 0x58, 0x23, 0x07, 0x38, 0x27, 0xee, 0x74, 0xc6, 0xe3, 0x70,
+  0x8a, 0xa0, 0x08, 0x7e, 0x4a, 0x3a, 0x52, 0x3f, 0x98, 0x0a, 0x1e, 0xa3,
+  0xbe, 0x83, 0xe1, 0x4b, 0x8d, 0x9e, 0xe7, 0xc4, 0xb3, 0x59, 0xa7, 0x95,
+  0x48, 0x10, 0x12, 0x18, 0xb7, 0x2a, 0xb3, 0x02, 0x36, 0xfd, 0x37, 0xd6,
+  0xa6, 0xdd, 0xf2, 0xc2, 0xb3, 0xf2, 0x4f, 0x43, 0x44, 0x5a, 0xb2, 0xb2,
+  0x39, 0x5d, 0x62, 0x52, 0xd1, 0xac, 0x6a, 0x0f, 0xf3, 0x3f, 0xa7, 0x39,
+  0xfe, 0x9f, 0x5f, 0xd3, 0xbe, 0xad, 0x22, 0xf8, 0xfc, 0x4b, 0x6c, 0xa2,
+  0xb8, 0xcf, 0x6d, 0x7a, 0x3a, 0xaf, 0x07, 0xc2, 0x92, 0x45, 0x1f, 0xcb,
+  0x94, 0xaf, 0x42, 0x3d, 0x0e, 0x3b, 0x63, 0xfa, 0x75, 0x35, 0x87, 0x84,
+  0xc5, 0xf3, 0x88, 0x63, 0xb1, 0x59, 0x68, 0xe3, 0xa9, 0x9a, 0x37, 0x06,
+  0xb8, 0x01, 0x88, 0x69, 0xc7, 0xac, 0x87, 0xb1, 0x3e, 0x9d, 0x75, 0xe8,
+  0x7e, 0x1e, 0xf8, 0x79, 0x62, 0xb6, 0xf0, 0xf1, 0xb4, 0xc9, 0x09, 0x96,
+  0x39, 0x7c, 0xd2, 0xa8, 0x1c, 0xab, 0xcc, 0x7a, 0xf2, 0x81, 0xd3, 0xf5,
+  0xd1, 0x3d, 0x3a, 0xca, 0xa9, 0x85, 0x1c, 0x7f, 0x22, 0xb3, 0xcb, 0xf5,
+  0x34, 0xfc, 0xe3, 0x07, 0x63, 0xeb, 0xa1, 0x16, 0x90, 0xac, 0x98, 0x63,
+  0xbf, 0x5c, 0xe3, 0x5e, 0xac, 0x8f, 0xe1, 0x7f, 0x05, 0x2c, 0x85, 0xcd,
+  0xa8, 0xb0, 0x23, 0xe9, 0x69, 0xdc, 0x81, 0xf6, 0xdf, 0x5c, 0x5d, 0x7e,
+  0x16, 0x70, 0x75, 0x6d, 0x32, 0xc5, 0x15, 0xb8, 0xd1, 0xba, 0x7d, 0x32,
+  0xc0, 0xe4, 0x37, 0xe7, 0x3d, 0x46, 0x97, 0x0d, 0x16, 0x48, 0xaa, 0x6e,
+  0xcb, 0x8e, 0x96, 0x48, 0xc9, 0xfe, 0x09, 0xd8, 0xae, 0x37, 0x1a, 0x7b,
+  0xe8, 0xa2, 0xad, 0x6a, 0x4e, 0x7a, 0x5f, 0x08, 0x4a, 0x14, 0x15, 0x67,
+  0x24, 0x10, 0x18, 0x1e, 0xd8, 0x07, 0xa6, 0x94, 0xd1, 0x5c, 0xae, 0xf6,
+  0x5b, 0xe5, 0x6f, 0x0b, 0x5d, 0x29, 0x62, 0x47, 0x99, 0x4c, 0x4c, 0x40,
+  0xc0, 0x52, 0x08, 0xc3, 0x7b, 0x83, 0x8d, 0x7a, 0x0b, 0x82, 0xb8, 0x6a,
+  0x9b, 0x84, 0xec, 0xa6, 0x86, 0x12, 0x66, 0x2f, 0x33, 0x3b, 0x38, 0x5d,
+  0xdb, 0x24, 0xe3, 0x3f, 0x8c, 0x0d, 0x65, 0x9f, 0xed, 0x01, 0x62, 0x9a,
+  0xae, 0xb0, 0x5f, 0xe8, 0x23, 0xfe, 0x65, 0x2a, 0xac, 0x53, 0x28, 0x19,
+  0x66, 0xe6, 0x3b, 0x6d, 0xfa, 0x7e, 0xba, 0xbc, 0x9a, 0x5f, 0x15, 0x7d,
+  0x93, 0x26, 0x0e, 0x0a, 0x79, 0xb3, 0xc8, 0x6a, 0xd6, 0x38, 0xdc, 0x44,
+  0xec, 0xdf, 0x50, 0x1e, 0x51, 0x93, 0xad, 0x1f, 0x86, 0xb8, 0x56, 0x86,
+  0x8e, 0x96, 0x5a, 0x8b, 0xad, 0x6c, 0x75, 0xf7, 0x06, 0x24, 0x53, 0x25,
+  0x31, 0xe6, 0x55, 0x51, 0xd1, 0xbd, 0xf3, 0xfb, 0x67, 0x59, 0x9d, 0x82,
+  0xc9, 0x5f, 0x50, 0xcd, 0x4b, 0x77, 0xb9, 0xc9, 0x46, 0x01, 0xf3, 0x43,
+  0x19, 0x2c, 0xfd, 0x7e, 0x9d, 0xb6, 0x1e, 0xfd, 0x71, 0xe9, 0xad, 0x83,
+  0x82, 0xeb, 0xec, 0x7c, 0x2b, 0x42, 0x20, 0xac, 0x95, 0x90, 0x22, 0x05,
+  0xf1, 0xa5, 0x39, 0xe5, 0x03, 0xa0, 0x19, 0xdf, 0x03, 0x5c, 0xfd, 0x2e,
+  0x9a, 0x0a, 0x4d, 0x4d, 0x70, 0x2b, 0x0e, 0x15, 0x16, 0xdb, 0x14, 0xd4,
+  0xb5, 0x65, 0x65, 0x9a, 0xa2, 0x96, 0x24, 0x11, 0xc4, 0x1c, 0xe1, 0x10,
+  0x05, 0xe6, 0x8c, 0x1d, 0x83, 0x0c, 0xe7, 0x27, 0x62, 0x75, 0x50, 0xbc,
+  0x3c, 0x31, 0x40, 0x1a, 0xa9, 0xe3, 0x86, 0x28, 0xb2, 0xbb, 0x26, 0x02,
+  0xe4, 0xee, 0x4e, 0x37, 0x3b, 0xea, 0xdd, 0xc4, 0xfc, 0x5f, 0xc3, 0xb3,
+  0x55, 0xca, 0xd4, 0xa6, 0x59, 0x63, 0xa9, 0x1c, 0xa5, 0xd6, 0x12, 0xbc,
+  0x8c, 0x77, 0x27, 0x27, 0xec, 0x75, 0x97, 0xfc, 0x4c, 0xbd, 0xd2, 0x57,
+  0xc9, 0x45, 0x6b, 0xb5, 0xac, 0x92, 0xa1, 0x72, 0xd3, 0xc8, 0xfd, 0x5d,
+  0xb3, 0x85, 0xfc, 0x60, 0xe8, 0x73, 0x60, 0x59, 0x73, 0xa8, 0x63, 0x92,
+  0xa5, 0xd8, 0x39, 0x60, 0xb7, 0x70, 0xc4, 0x5c, 0x4d, 0x6b, 0xa2, 0x9e,
+  0xba, 0x13, 0x41, 0x72, 0x86, 0xe1, 0x55, 0x2b, 0xe3, 0xc2, 0x81, 0x58,
+  0xf8, 0x64, 0x9c, 0x2a, 0xef, 0x8d, 0xce, 0x75, 0xbd, 0x7c, 0x19, 0xf8,
+  0x6f, 0x6e, 0xe1, 0xbb, 0x5b, 0x54, 0xdd, 0x12, 0x9e, 0xaa, 0xf1, 0x3a,
+  0x7f, 0x3b, 0x1b, 0xf8, 0x00, 0xff, 0x00, 0x42, 0xff, 0x00, 0x99, 0xfb,
+  0x6a, 0x9b, 0xf0, 0xaf, 0x86, 0xe8, 0xa8, 0xab, 0x1e, 0xbe, 0xbd, 0x44,
+  0xd5, 0x2a, 0x02, 0xd3, 0x29, 0xc0, 0x45, 0x73, 0xd4, 0xe4, 0xfe, 0x9f,
+  0x9d, 0x69, 0xca, 0x12, 0x95, 0xa4, 0x96, 0xa6, 0x59, 0x10, 0xca, 0x87,
+  0xf9, 0x3c, 0xbb, 0x02, 0x3a, 0x01, 0xeb, 0xae, 0x9e, 0x1c, 0xf1, 0xde,
+  0xe1, 0x1e, 0x90, 0xec, 0x4e, 0x8f, 0x1f, 0x71, 0x08, 0xab, 0xa8, 0xe2,
+  0x6b, 0xba, 0x48, 0x42, 0xc2, 0x2b, 0xa6, 0x0b, 0xca, 0x30, 0x48, 0xe7,
+  0x6e, 0xfa, 0x56, 0x68, 0xd5, 0x7c, 0xb3, 0x4e, 0x52, 0x2e, 0x6c, 0x2a,
+  0x06, 0xc9, 0xfb, 0xea, 0xc1, 0xc4, 0x66, 0x25, 0xe2, 0x1b, 0x97, 0x8a,
+  0x55, 0x54, 0xd6, 0x4b, 0x82, 0x4f, 0x7e, 0x73, 0xa5, 0xcd, 0x5b, 0x68,
+  0x84, 0x34, 0x6f, 0x39, 0x72, 0x06, 0xea, 0x91, 0x13, 0xbf, 0xa6, 0x4e,
+  0x9e, 0x80, 0xdc, 0xb7, 0xbb, 0x42, 0xd9, 0x28, 0xa4, 0x69, 0x0c, 0x18,
+  0x0f, 0x01, 0xf3, 0x73, 0xc8, 0x7d, 0xfb, 0x77, 0xfd, 0x3f, 0x5d, 0x10,
+  0x94, 0x74, 0xb1, 0xc7, 0x35, 0x74, 0xd4, 0x08, 0xc8, 0x8f, 0xc8, 0x85,
+  0x48, 0xe6, 0x66, 0x3d, 0xcf, 0x36, 0x36, 0xf7, 0xc9, 0xd3, 0x4a, 0x29,
+  0x20, 0x92, 0x9d, 0x9c, 0x7c, 0xda, 0xc5, 0xc9, 0xe5, 0x0c, 0xa3, 0xcb,
+  0xb6, 0xc7, 0x19, 0xce, 0x34, 0x65, 0x0a, 0x2a, 0x70, 0x65, 0x5d, 0xa5,
+  0xed, 0xf4, 0x37, 0x25, 0xad, 0x71, 0x22, 0xcd, 0x3c, 0x38, 0x92, 0x26,
+  0x52, 0x30, 0x50, 0x9c, 0x15, 0x23, 0xef, 0x8c, 0x9d, 0x66, 0xcc, 0xd5,
+  0xd3, 0x1a, 0x8a, 0xbb, 0xc2, 0x22, 0x75, 0x3f, 0xfb, 0x7d, 0x31, 0xe8,
+  0x3f, 0xb6, 0xad, 0xd6, 0x3a, 0x8a, 0x51, 0x4d, 0x2b, 0x23, 0x72, 0xa2,
+  0x2a, 0xf3, 0x85, 0x3b, 0x92, 0x37, 0xd5, 0x6a, 0x4a, 0x79, 0x67, 0xaf,
+  0x58, 0x99, 0x8e, 0xc0, 0x02, 0x71, 0x8f, 0xce, 0xa1, 0xbd, 0x17, 0xb7,
+  0x57, 0xab, 0xd3, 0x33, 0x47, 0x95, 0x1e, 0x6c, 0xec, 0x40, 0x18, 0xdc,
+  0x69, 0x69, 0x50, 0x89, 0x21, 0xcf, 0x16, 0xd4, 0x51, 0x57, 0x33, 0x54,
+  0x5a, 0xe3, 0x96, 0x9a, 0x90, 0xb7, 0x86, 0x91, 0xbb, 0xf3, 0x90, 0x40,
+  0x01, 0x8e, 0x70, 0x3b, 0xe7, 0x1e, 0x9a, 0xa5, 0x5c, 0x33, 0x1a, 0x1f,
+  0x50, 0x71, 0x9f, 0x6d, 0x34, 0x8e, 0xea, 0x6a, 0x03, 0x25, 0x53, 0x20,
+  0x55, 0xc9, 0x18, 0x1f, 0x56, 0x7a, 0x69, 0x5d, 0x5f, 0x33, 0xc8, 0x59,
+  0x17, 0x2b, 0x9e, 0x50, 0xa7, 0xbe, 0x4e, 0xb7, 0x3a, 0xa5, 0x43, 0x10,
+  0x45, 0x86, 0xde, 0x64, 0x8b, 0xe6, 0x0a, 0x9e, 0x57, 0x3b, 0x9f, 0x5e,
+  0xe7, 0x47, 0x5c, 0x2e, 0x73, 0xd1, 0x8f, 0x06, 0x9e, 0x34, 0x03, 0xa2,
+  0x67, 0xaa, 0xfb, 0xfb, 0xe9, 0xc5, 0x24, 0x42, 0x1b, 0x4c, 0x54, 0xa5,
+  0x70, 0xc1, 0x41, 0x03, 0x3d, 0xf1, 0xbe, 0xab, 0xf7, 0x57, 0x57, 0x06,
+  0x1e, 0x5c, 0x31, 0x38, 0x07, 0x3d, 0x3b, 0x1d, 0x13, 0xe1, 0x10, 0x29,
+  0x6e, 0x8a, 0x38, 0x42, 0xa2, 0x9e, 0x62, 0x7e, 0x7e, 0x69, 0x79, 0x5d,
+  0xf1, 0xf5, 0xab, 0x0c, 0xfe, 0x31, 0xb6, 0xab, 0xa1, 0x82, 0x46, 0x00,
+  0x19, 0xc6, 0xda, 0x7b, 0xc4, 0xd5, 0x14, 0x4c, 0x29, 0x61, 0xa3, 0x62,
+  0xea, 0xb1, 0x00, 0x77, 0xd8, 0x10, 0x31, 0xa4, 0x72, 0xe0, 0x81, 0xeb,
+  0xd7, 0x48, 0x28, 0x69, 0xc3, 0x17, 0x7a, 0xa8, 0xae, 0x94, 0x74, 0x11,
+  0x95, 0x58, 0x4c, 0x86, 0x46, 0x23, 0xea, 0x27, 0x38, 0xc6, 0x7d, 0x37,
+  0xd3, 0x7f, 0x88, 0x52, 0x98, 0xea, 0xad, 0x92, 0x54, 0x42, 0x66, 0xa5,
+  0xf1, 0x5c, 0x4b, 0xca, 0x3a, 0x74, 0xc7, 0xe9, 0xa4, 0x1c, 0x3f, 0x02,
+  0xa7, 0x10, 0x51, 0xd5, 0xce, 0x00, 0x8c, 0x2f, 0x2c, 0x67, 0xd5, 0xb2,
+  0x3f, 0xeb, 0xa6, 0xff, 0x00, 0x11, 0x24, 0x35, 0x37, 0x33, 0x42, 0x8c,
+  0x24, 0x8e, 0x0a, 0x6f, 0x17, 0x38, 0xc6, 0x0f, 0x36, 0xff, 0x00, 0xd8,
+  0x69, 0xa9, 0x9a, 0xa2, 0x9d, 0xc6, 0x8e, 0xed, 0xd1, 0xd2, 0x55, 0xdc,
+  0xeb, 0xa1, 0xf9, 0x8a, 0x9a, 0x87, 0x34, 0xab, 0x94, 0xc6, 0x59, 0x90,
+  0x6f, 0x93, 0xbf, 0xb8, 0x3b, 0x76, 0x07, 0x3a, 0x86, 0xbe, 0x99, 0x60,
+  0xa2, 0x8a, 0x51, 0x3a, 0x48, 0x5d, 0x1b, 0x1c, 0x9b, 0x80, 0x01, 0xd8,
+  0x7e, 0x9a, 0x67, 0xf0, 0xfe, 0xe5, 0x4e, 0xb5, 0xe2, 0x09, 0x56, 0x34,
+  0x9a, 0xa9, 0x42, 0x2b, 0x9f, 0xeb, 0x5c, 0x12, 0xc8, 0x7d, 0x71, 0xb6,
+  0x89, 0xbe, 0x51, 0xd3, 0x43, 0xc3, 0x6f, 0x14, 0x14, 0xfe, 0x1c, 0xb5,
+  0x35, 0xd2, 0x95, 0x2b, 0xf4, 0x80, 0x0f, 0xfd, 0x3f, 0x7d, 0x18, 0x70,
+  0x96, 0xdc, 0x8e, 0x25, 0x66, 0xdf, 0x50, 0x94, 0xce, 0xd8, 0x3c, 0x8c,
+  0xe8, 0xbc, 0xad, 0xff, 0x00, 0x31, 0x1a, 0xd2, 0xf8, 0x2a, 0xfa, 0x95,
+  0x51, 0x0a, 0x3a, 0x89, 0x57, 0xc7, 0x85, 0x54, 0x33, 0x67, 0xeb, 0xf7,
+  0xc6, 0xb3, 0x14, 0x12, 0x47, 0x2a, 0x4b, 0x9e, 0x56, 0x55, 0xc7, 0x4f,
+  0xdf, 0x47, 0xdb, 0xe9, 0xdc, 0x89, 0x24, 0x8e, 0x69, 0x3c, 0x58, 0xc0,
+  0x20, 0xe7, 0x7d, 0x23, 0x24, 0x2c, 0x76, 0xa3, 0x12, 0xcb, 0x1a, 0x63,
+  0x5f, 0x8b, 0x8d, 0x2c, 0x7c, 0x65, 0x6b, 0x95, 0xc7, 0x3c, 0x26, 0x9b,
+  0xc9, 0xf6, 0xe6, 0x20, 0xe9, 0xcf, 0x0e, 0xdb, 0x79, 0x28, 0xe9, 0xeb,
+  0x4c, 0x69, 0x53, 0x12, 0x02, 0x15, 0x17, 0x62, 0x8d, 0xd8, 0xe4, 0x63,
+  0x3d, 0x08, 0xdf, 0x3d, 0x75, 0x56, 0xe2, 0x4a, 0xa9, 0xae, 0x94, 0xb6,
+  0xea, 0xa9, 0x9d, 0x9a, 0x5a, 0x34, 0x31, 0xb0, 0x27, 0x24, 0x8d, 0x59,
+  0xb8, 0x3e, 0xfb, 0x4d, 0x05, 0xa4, 0xc7, 0xe2, 0x10, 0x00, 0xcf, 0xeb,
+  0xac, 0xba, 0xcd, 0xff, 0x00, 0x12, 0x94, 0x7f, 0x66, 0x5c, 0xf8, 0x9c,
+  0x31, 0xa4, 0xbd, 0x0b, 0xae, 0x94, 0xf5, 0x35, 0x57, 0x24, 0x9c, 0x2a,
+  0xd2, 0x4a, 0xbb, 0xa2, 0xc6, 0xb8, 0x52, 0x77, 0xd8, 0x8f, 0x5e, 0xbb,
+  0xea, 0xe7, 0xc0, 0x33, 0x4b, 0x5e, 0xcd, 0x6f, 0xa6, 0xa0, 0x98, 0x56,
+  0x49, 0x11, 0x90, 0x2f, 0x3a, 0x9e, 0x60, 0x33, 0xcd, 0xbf, 0xdc, 0x77,
+  0xd2, 0x9a, 0xea, 0xda, 0x4b, 0x8d, 0xb8, 0xd5, 0xd3, 0xef, 0x24, 0x4d,
+  0xfc, 0xc0, 0x3b, 0x80, 0x0e, 0xfa, 0xe3, 0xfd, 0x9f, 0xa6, 0xa9, 0x8f,
+  0x8d, 0xe3, 0x7a, 0x58, 0x64, 0x92, 0x94, 0xb3, 0x78, 0xf2, 0xe3, 0xca,
+  0x85, 0x81, 0x3f, 0xe5, 0xfb, 0xe9, 0x2b, 0x4d, 0x1d, 0x42, 0x70, 0x97,
+  0x4c, 0xcb, 0x8b, 0x1a, 0xcb, 0x3d, 0xac, 0x86, 0xff, 0x00, 0x59, 0x70,
+  0x8e, 0xb8, 0xc9, 0xc8, 0xb1, 0x78, 0x2c, 0x47, 0x29, 0x52, 0x1e, 0x33,
+  0xbe, 0xcf, 0x9e, 0xfa, 0xfb, 0xc3, 0x3c, 0x45, 0xf2, 0x97, 0x07, 0xaa,
+  0xaa, 0xa7, 0x6a, 0x88, 0x79, 0x1a, 0x29, 0x23, 0x56, 0xe5, 0x3b, 0xff,
+  0x00, 0x50, 0x3e, 0xda, 0xf4, 0x9d, 0xc7, 0xe1, 0x87, 0x09, 0x71, 0xc5,
+  0x44, 0x57, 0x1b, 0xe5, 0xba, 0x4f, 0x1a, 0x35, 0x18, 0x96, 0x39, 0x0c,
+  0x52, 0x3f, 0xff, 0x00, 0x2c, 0x75, 0x03, 0xb6, 0x7a, 0x6a, 0x7a, 0xcf,
+  0x84, 0x1c, 0x0b, 0x47, 0x69, 0x31, 0x52, 0xd9, 0xe4, 0xfe, 0x5e, 0x09,
+  0x26, 0xa5, 0xcf, 0x3e, 0x3f, 0xc5, 0x93, 0xbe, 0xb5, 0xc7, 0xf1, 0xca,
+  0x0a, 0xa0, 0xcd, 0x0f, 0x48, 0xa3, 0xd3, 0x3c, 0xf1, 0x76, 0xe2, 0x2b,
+  0xd4, 0x42, 0xa2, 0xec, 0xb6, 0xf8, 0x3f, 0x85, 0x48, 0xe9, 0x4f, 0x13,
+  0xc9, 0x4f, 0xcf, 0x18, 0x20, 0x79, 0x4a, 0xbe, 0xc7, 0x9b, 0x6c, 0xed,
+  0x8d, 0xf4, 0xca, 0xdf, 0x52, 0xf7, 0x38, 0x17, 0x99, 0x05, 0x4f, 0x24,
+  0x79, 0x76, 0x07, 0x00, 0x1f, 0x5d, 0x6b, 0x7c, 0x75, 0xc1, 0x75, 0x1c,
+  0x69, 0xc3, 0x27, 0x86, 0xed, 0x2b, 0x4b, 0x4b, 0x0c, 0x72, 0x46, 0xf9,
+  0x71, 0xca, 0xaa, 0x17, 0xd9, 0x47, 0xbe, 0xa4, 0xb6, 0xfc, 0x19, 0x16,
+  0xfb, 0x04, 0x74, 0x34, 0xf7, 0x58, 0xc4, 0xf8, 0xe5, 0x92, 0x4f, 0x00,
+  0xe1, 0x86, 0x37, 0xfe, 0xad, 0x36, 0x1a, 0x79, 0x63, 0xfa, 0x93, 0x26,
+  0x99, 0xc1, 0xd2, 0xe4, 0xf2, 0xa7, 0x19, 0x54, 0xc8, 0x95, 0x55, 0x12,
+  0x42, 0x39, 0x49, 0x52, 0x83, 0x7e, 0x8b, 0xd3, 0x1a, 0x6f, 0xf0, 0x5b,
+  0xe1, 0x07, 0x11, 0xf1, 0xb5, 0xca, 0x1a, 0xc3, 0x1c, 0xf6, 0xdb, 0x42,
+  0x38, 0xf1, 0x2b, 0xdc, 0x63, 0x98, 0x67, 0xa4, 0x7f, 0xe2, 0x6f, 0xed,
+  0xaf, 0x57, 0xf0, 0x2f, 0xc2, 0x2e, 0x18, 0xe1, 0xe0, 0x2a, 0xeb, 0x28,
+  0xa9, 0xee, 0x97, 0x2e, 0x6e, 0x6f, 0x98, 0xa8, 0x8f, 0x98, 0x27, 0xb2,
+  0xa9, 0xd8, 0x7d, 0xfa, 0xea, 0xf4, 0xf8, 0xa7, 0x41, 0x1c, 0x68, 0xa8,
+  0x8b, 0xb0, 0x54, 0x18, 0x03, 0xf1, 0xad, 0x31, 0x80, 0xd5, 0x8b, 0x81,
+  0x67, 0x06, 0x70, 0xb5, 0x9f, 0x84, 0xac, 0xd1, 0xda, 0xec, 0xb4, 0xa2,
+  0x18, 0x86, 0xf2, 0x3b, 0x79, 0xa4, 0x99, 0xfb, 0xbb, 0xb7, 0x56, 0x27,
+  0x4f, 0x34, 0x2a, 0x4a, 0x09, 0xeb, 0x83, 0xa9, 0x1a, 0x42, 0xcb, 0x82,
+  0x34, 0xc4, 0x86, 0x25, 0x47, 0x53, 0x49, 0xc8, 0xa4, 0x8e, 0xb8, 0xce,
+  0xa0, 0xa0, 0xac, 0x4a, 0x99, 0x5c, 0x67, 0x74, 0x38, 0x23, 0x5c, 0xd5,
+  0x49, 0x88, 0xcf, 0xdb, 0x1a, 0x4d, 0x6b, 0x99, 0xe3, 0xba, 0x4a, 0xc4,
+  0xe1, 0x1d, 0xb1, 0xfa, 0x77, 0xd5, 0xd1, 0x76, 0x3c, 0xbe, 0xb4, 0xd1,
+  0xda, 0x2a, 0xa4, 0xa6, 0xe6, 0xf1, 0x92, 0x26, 0x64, 0x55, 0xea, 0xc4,
+  0x02, 0x70, 0x3d, 0xcf, 0xe7, 0x59, 0x27, 0x0d, 0xdc, 0xe9, 0xaf, 0xfc,
+  0x3f, 0x70, 0x14, 0x37, 0xea, 0x5b, 0x6c, 0xaf, 0x2f, 0x8d, 0x53, 0x1c,
+  0xc9, 0x99, 0xe3, 0x20, 0x8c, 0x0f, 0x36, 0x01, 0xf7, 0x6d, 0xfa, 0x0d,
+  0x6c, 0xaa, 0x43, 0x2e, 0x7a, 0x8d, 0x79, 0x63, 0xe3, 0x1c, 0x6f, 0x07,
+  0xc4, 0xab, 0xbc, 0x64, 0x15, 0xcb, 0xab, 0xa6, 0xfb, 0x10, 0xca, 0x0f,
+  0xfd, 0xfd, 0xf5, 0x8f, 0x59, 0xe3, 0x14, 0xc4, 0x67, 0x7c, 0x07, 0x3d,
+  0x86, 0xae, 0xa6, 0xf1, 0xf2, 0xc6, 0x76, 0xf1, 0x5c, 0xb3, 0x25, 0x64,
+  0x47, 0x21, 0x80, 0x04, 0xe7, 0x23, 0x6d, 0xfd, 0x06, 0xa6, 0x58, 0x6e,
+  0xb6, 0x8b, 0x85, 0x3f, 0xf1, 0xa8, 0x12, 0xbe, 0x87, 0xc4, 0x1b, 0xcd,
+  0x1f, 0x37, 0x32, 0xfb, 0x6f, 0xb6, 0x46, 0xaa, 0xdc, 0x1d, 0x7a, 0xac,
+  0xb3, 0x5e, 0xa9, 0xe5, 0x49, 0x0f, 0x82, 0xf2, 0x72, 0xcc, 0xa4, 0xed,
+  0xca, 0x7a, 0x9c, 0x7e, 0x9a, 0xd9, 0xb8, 0x9a, 0x4b, 0x5c, 0xf6, 0xb8,
+  0xd2, 0x3a, 0x87, 0xa8, 0xe6, 0x41, 0x18, 0x43, 0x16, 0x39, 0x97, 0xa8,
+  0xdf, 0x3d, 0x80, 0xd7, 0x2b, 0x0e, 0x24, 0xed, 0x27, 0xc9, 0x96, 0x00,
+  0x97, 0x3e, 0x1b, 0xe1, 0x3b, 0x85, 0xbd, 0x6a, 0xa8, 0x2d, 0xa1, 0x15,
+  0x9d, 0x9d, 0x0d, 0x3b, 0x91, 0x90, 0x47, 0x42, 0x0e, 0x40, 0x3e, 0xda,
+  0xce, 0xab, 0xb8, 0x52, 0x25, 0xbf, 0x41, 0x55, 0x43, 0x89, 0xd2, 0x22,
+  0xee, 0x61, 0x99, 0x72, 0xcb, 0xb1, 0x23, 0x3e, 0xa0, 0x6a, 0xdf, 0x6b,
+  0x35, 0x34, 0xa1, 0xe9, 0xe9, 0x29, 0x66, 0x78, 0x26, 0x3c, 0xd0, 0xb4,
+  0x9f, 0x48, 0x1d, 0xf7, 0xef, 0xbe, 0x35, 0xfa, 0x0a, 0x86, 0xc4, 0x93,
+  0xff, 0x00, 0x0a, 0x32, 0xd6, 0x73, 0xf8, 0x11, 0xc9, 0x10, 0xc1, 0x1b,
+  0xf4, 0xc7, 0x7e, 0x9a, 0xd9, 0x87, 0x0b, 0x4b, 0x73, 0x8d, 0x30, 0xc9,
+  0x78, 0x2a, 0xba, 0xae, 0x59, 0x05, 0xbe, 0xaa, 0x99, 0x24, 0xab, 0x8d,
+  0x1b, 0xc3, 0x90, 0x30, 0x5f, 0x10, 0x0f, 0xe9, 0xdf, 0x62, 0x71, 0xd3,
+  0xed, 0xae, 0xb8, 0x8b, 0x88, 0xa9, 0x25, 0xa6, 0xf9, 0x95, 0x72, 0xf0,
+  0x42, 0x07, 0x8d, 0x86, 0xc4, 0x91, 0x63, 0xa8, 0xc1, 0xed, 0x9d, 0xb4,
+  0x9b, 0x88, 0xaa, 0xaf, 0x74, 0x9c, 0xa2, 0xae, 0x90, 0x46, 0x86, 0x40,
+  0x1d, 0x8a, 0x6e, 0x7a, 0xec, 0x7d, 0xf6, 0xd6, 0x7b, 0xc7, 0x46, 0x94,
+  0x5e, 0xb1, 0x49, 0x17, 0x20, 0x68, 0xd5, 0xa4, 0x6c, 0xec, 0xcd, 0xf6,
+  0xfc, 0xe8, 0x31, 0xe9, 0xa3, 0x82, 0x4f, 0x22, 0xec, 0xb9, 0x45, 0x41,
+  0x5a, 0x33, 0xfe, 0x32, 0x88, 0x0e, 0x29, 0xbb, 0xbb, 0x10, 0x8a, 0x2b,
+  0x67, 0x39, 0x27, 0xa9, 0xf1, 0x0e, 0x97, 0x50, 0xbc, 0x3c, 0xe1, 0xde,
+  0x15, 0x9f, 0x1b, 0x85, 0x27, 0x6d, 0x1b, 0xc5, 0x4b, 0x2d, 0x47, 0x17,
+  0xde, 0x7c, 0x4f, 0xf8, 0x6b, 0x5f, 0x38, 0x07, 0xff, 0x00, 0xf4, 0x3b,
+  0x6b, 0xf5, 0x05, 0x0b, 0x4a, 0xc0, 0x47, 0xf4, 0xf5, 0x63, 0x8f, 0xdb,
+  0x4c, 0x7d, 0x99, 0xe7, 0xf6, 0x67, 0x75, 0x35, 0xb3, 0x4c, 0xea, 0xef,
+  0x4e, 0xab, 0x10, 0xc7, 0x94, 0x36, 0xe7, 0xf3, 0x8d, 0x47, 0x25, 0xc2,
+  0xae, 0xaa, 0x9b, 0x7c, 0xc4, 0x80, 0x91, 0x84, 0x63, 0x8d, 0xf4, 0x5d,
+  0x72, 0x43, 0x0c, 0x4d, 0x1b, 0x46, 0xdb, 0x0c, 0x82, 0x47, 0x7d, 0x2c,
+  0x89, 0x83, 0x92, 0x80, 0xf2, 0xe3, 0xaf, 0xbe, 0x95, 0x96, 0xe5, 0xd8,
+  0x1b, 0xda, 0x54, 0x86, 0x9c, 0x39, 0x17, 0xf3, 0x86, 0xd8, 0xdc, 0xef,
+  0xa2, 0xae, 0xeb, 0x43, 0x25, 0xd6, 0x1a, 0x6a, 0xe0, 0x48, 0x68, 0x18,
+  0xa9, 0x53, 0x82, 0xa7, 0x98, 0x60, 0xff, 0x00, 0x7d, 0x15, 0xc2, 0x54,
+  0xdf, 0x54, 0x84, 0x63, 0xcb, 0xb1, 0xf5, 0xd5, 0x4e, 0xfd, 0x5f, 0x3b,
+  0xf1, 0x7b, 0xbb, 0xb6, 0x4c, 0x4e, 0x23, 0x5f, 0x60, 0x32, 0x31, 0xa7,
+  0x41, 0xf2, 0x83, 0x8b, 0x0b, 0xbc, 0x59, 0x1a, 0x98, 0x37, 0xcb, 0xc8,
+  0x25, 0x55, 0x19, 0x23, 0x9b, 0x24, 0x7e, 0x7b, 0xe8, 0x1b, 0x4a, 0xab,
+  0xd5, 0xc4, 0x65, 0x1c, 0xcc, 0x18, 0x60, 0x74, 0xdb, 0x1a, 0xb5, 0xc1,
+  0x50, 0x95, 0x36, 0xf8, 0xa7, 0x45, 0x1e, 0x2c, 0x43, 0x1b, 0x9e, 0xa4,
+  0x6c, 0x47, 0xe7, 0x55, 0x4a, 0x80, 0x61, 0xb9, 0x4b, 0x2a, 0x46, 0xd1,
+  0xa3, 0x13, 0xca, 0x06, 0xe4, 0x12, 0x7a, 0x69, 0xcb, 0xc3, 0x25, 0x16,
+  0x5a, 0x89, 0x12, 0x47, 0x91, 0xf5, 0x0d, 0xf5, 0x55, 0xe2, 0x66, 0x4a,
+  0x69, 0x0d, 0x44, 0x67, 0xcf, 0x9f, 0xd0, 0xe9, 0x9b, 0xd4, 0x4c, 0x82,
+  0x92, 0x26, 0x86, 0x68, 0xda, 0xa1, 0x80, 0x42, 0xd1, 0xf6, 0xe8, 0x71,
+  0xbf, 0x5d, 0x53, 0x78, 0xb6, 0xa1, 0xa3, 0xe2, 0x1a, 0x8a, 0x0c, 0x3a,
+  0xc3, 0x4f, 0x21, 0x8c, 0xc6, 0xdd, 0x43, 0x03, 0xe6, 0xcf, 0xbe, 0x46,
+  0xaf, 0x3e, 0x54, 0xfc, 0x50, 0x49, 0x86, 0x96, 0x79, 0x5b, 0xc4, 0x73,
+  0x92, 0x7a, 0xeb, 0x87, 0xcf, 0x36, 0x74, 0x4b, 0x18, 0xe5, 0xa7, 0x8e,
+  0x48, 0x54, 0x05, 0x2b, 0xa2, 0xf8, 0x7e, 0xdf, 0x51, 0x57, 0x5c, 0xb2,
+  0x47, 0x1a, 0x48, 0x91, 0x9e, 0x66, 0x0f, 0x9c, 0x1c, 0x1e, 0x87, 0x1a,
+  0x5a, 0xe8, 0xb3, 0xba, 0x41, 0xfc, 0x3e, 0x38, 0x6b, 0xe4, 0x6c, 0x3c,
+  0x11, 0x16, 0x89, 0x39, 0x72, 0x09, 0x6d, 0xc1, 0x3f, 0x63, 0x83, 0xa8,
+  0x6d, 0xa9, 0x1d, 0x4b, 0x9a, 0xaa, 0x89, 0x32, 0x5c, 0x31, 0xa8, 0x90,
+  0x8e, 0x63, 0xd3, 0xaf, 0xf6, 0xc6, 0xac, 0x17, 0xb1, 0x59, 0x32, 0xcc,
+  0x95, 0x0b, 0x0a, 0xf9, 0x08, 0x41, 0x1a, 0x72, 0xa8, 0xff, 0x00, 0x97,
+  0x19, 0xd2, 0x9b, 0x3c, 0xd1, 0xc0, 0x94, 0x91, 0x14, 0x42, 0xf2, 0xc0,
+  0xf0, 0x37, 0x30, 0xcf, 0x29, 0x23, 0x63, 0xa6, 0x23, 0x7e, 0x9f, 0x95,
+  0x60, 0xdc, 0x2d, 0x22, 0xcb, 0x0c, 0x88, 0xcf, 0x29, 0xa9, 0x86, 0x63,
+  0x24, 0x4c, 0xa4, 0xe5, 0x81, 0x1d, 0xf1, 0xf6, 0xd5, 0xba, 0x3a, 0xb8,
+  0xab, 0xf8, 0x6e, 0x38, 0x48, 0x65, 0x9e, 0x4f, 0x17, 0x92, 0x10, 0x3e,
+  0x97, 0x56, 0xff, 0x00, 0x3c, 0xe3, 0x3e, 0xda, 0x43, 0xc3, 0x4d, 0x10,
+  0xb9, 0x1f, 0x91, 0x4c, 0xcb, 0x4e, 0x18, 0xbc, 0x8c, 0x00, 0x51, 0xb7,
+  0x98, 0x31, 0x3d, 0xbb, 0x0f, 0x4d, 0xb5, 0xf2, 0x9f, 0xf9, 0xbc, 0x49,
+  0x0c, 0x85, 0x84, 0x8b, 0x34, 0x26, 0xa2, 0x6c, 0x9c, 0x98, 0xf2, 0x32,
+  0xc0, 0x1e, 0xfb, 0xe3, 0xf4, 0xd1, 0xa6, 0x5a, 0x85, 0x4a, 0xc8, 0x61,
+  0x91, 0x7c, 0xa9, 0x22, 0x81, 0x20, 0x1f, 0x4b, 0x0e, 0x87, 0xd3, 0xef,
+  0xa2, 0x62, 0x63, 0x4d, 0x2a, 0x54, 0x14, 0xe5, 0x0c, 0x4a, 0xb2, 0xe7,
+  0xb6, 0x86, 0x42, 0xf2, 0x09, 0x9d, 0xfe, 0xb2, 0xdc, 0xf9, 0xf7, 0x27,
+  0x4c, 0xae, 0x54, 0xc1, 0x6d, 0xf4, 0xd5, 0x87, 0xac, 0xab, 0xca, 0xdf,
+  0x71, 0xd3, 0x43, 0x66, 0xcb, 0x21, 0x30, 0x14, 0xb9, 0xff, 0x00, 0x31,
+  0x1e, 0x28, 0x66, 0x5c, 0x83, 0x8d, 0x98, 0x7d, 0xf4, 0x1d, 0xd1, 0x15,
+  0x2c, 0xd5, 0x6a, 0xb1, 0xf3, 0x34, 0x28, 0xd2, 0x28, 0x0c, 0x40, 0x20,
+  0x03, 0xb1, 0xc7, 0x51, 0xa7, 0xd1, 0x47, 0xf3, 0x02, 0xcc, 0x5d, 0xb9,
+  0xd4, 0xc6, 0xeb, 0x9f, 0x42, 0x08, 0x1a, 0x89, 0x21, 0x8d, 0x2e, 0x8f,
+  0x04, 0xcb, 0x98, 0xca, 0xb0, 0xfb, 0x8d, 0x4b, 0x24, 0xe3, 0xc1, 0x4b,
+  0xb2, 0x99, 0x3c, 0x08, 0xe4, 0x32, 0x25, 0x24, 0x72, 0xec, 0xdc, 0xf2,
+  0x16, 0xc8, 0xef, 0xb6, 0x33, 0x8d, 0x6b, 0x3f, 0x09, 0x67, 0xa2, 0xb4,
+  0xf1, 0xc5, 0x80, 0xc1, 0x75, 0x49, 0x12, 0xa2, 0xa1, 0x44, 0xa8, 0xb1,
+  0x91, 0xb6, 0x3a, 0x80, 0x7b, 0x7f, 0xae, 0xa9, 0x13, 0x9b, 0x5d, 0xb1,
+  0x27, 0xa2, 0xaf, 0x94, 0xc0, 0xc8, 0xc7, 0xc1, 0x65, 0x21, 0x81, 0x5c,
+  0xe0, 0x65, 0x7e, 0xda, 0x55, 0x45, 0x55, 0x15, 0x1d, 0xca, 0x39, 0x29,
+  0xe4, 0x2b, 0x89, 0x39, 0xe1, 0x60, 0x70, 0xcb, 0x83, 0xdb, 0xdb, 0x52,
+  0x16, 0x9f, 0x28, 0xe7, 0x38, 0xf2, 0x7b, 0xea, 0x4b, 0xcd, 0x6d, 0xbe,
+  0xef, 0x4d, 0x45, 0x0d, 0xb6, 0x69, 0xe8, 0x66, 0x1b, 0xce, 0xb9, 0x21,
+  0x0f, 0xf9, 0x68, 0x8b, 0xdf, 0x11, 0x4f, 0x47, 0x75, 0xa3, 0xa0, 0xa6,
+  0xb4, 0xcd, 0x58, 0x95, 0x07, 0x0c, 0xe8, 0xdb, 0x2f, 0xa9, 0x3b, 0x1d,
+  0x65, 0x3f, 0x07, 0x3e, 0x2c, 0x45, 0x7e, 0xa7, 0x92, 0xd3, 0x5c, 0x39,
+  0x6e, 0x09, 0x1f, 0x2a, 0x11, 0xd2, 0x53, 0x8e, 0xb8, 0xed, 0xd3, 0x5a,
+  0x65, 0x96, 0xed, 0x53, 0x25, 0xa9, 0x5a, 0xb5, 0x39, 0x6b, 0x5c, 0x9e,
+  0x6c, 0x2e, 0x00, 0x1a, 0xd3, 0x43, 0x93, 0x2c, 0xf4, 0x2b, 0x04, 0x61,
+  0x96, 0x24, 0xe5, 0x27, 0x73, 0xeb, 0xed, 0xa2, 0x5d, 0xd5, 0x17, 0x2d,
+  0xf6, 0xd2, 0x9b, 0x5c, 0xc5, 0x61, 0x52, 0xdb, 0x93, 0xbe, 0x74, 0x75,
+  0x44, 0x88, 0xf0, 0x1d, 0x1d, 0x96, 0xd9, 0x29, 0x94, 0x75, 0x07, 0x6c,
+  0x68, 0x2a, 0xc9, 0xb6, 0x03, 0x27, 0x73, 0x8d, 0x41, 0x2c, 0x98, 0x5c,
+  0x73, 0x76, 0xd0, 0xd3, 0x4b, 0x90, 0xbe, 0x6e, 0x9b, 0xea, 0x14, 0x1d,
+  0x03, 0x79, 0x80, 0x3b, 0xfb, 0xe8, 0x95, 0x21, 0x77, 0x63, 0x8d, 0x2e,
+  0xa5, 0x94, 0x39, 0x07, 0x47, 0x9f, 0x32, 0x11, 0xea, 0x35, 0x08, 0x2c,
+  0xbb, 0xd4, 0x72, 0x82, 0x01, 0xfb, 0x68, 0x2a, 0x75, 0x21, 0x10, 0x8f,
+  0xa8, 0xef, 0xae, 0x6e, 0x44, 0x9a, 0xd1, 0x1b, 0x74, 0xd1, 0x74, 0x91,
+  0x86, 0x95, 0x41, 0xc0, 0x5e, 0xe4, 0x9c, 0x76, 0xd0, 0xc8, 0xbf, 0x56,
+  0x35, 0xa2, 0xa8, 0xcc, 0x18, 0x3b, 0x91, 0xac, 0xd7, 0xe3, 0x77, 0x06,
+  0xd5, 0x5f, 0x0c, 0x17, 0xdb, 0x72, 0xc6, 0x65, 0x82, 0x13, 0x1c, 0xca,
+  0xcc, 0x17, 0x2a, 0x0e, 0x41, 0xcf, 0x73, 0xbf, 0x4d, 0x5a, 0x6c, 0xf7,
+  0x8a, 0x09, 0xa4, 0x6a, 0x68, 0x2a, 0x01, 0x62, 0xc7, 0xcb, 0xe8, 0x7d,
+  0x34, 0xf2, 0x0a, 0x98, 0xd9, 0x4c, 0x13, 0xae, 0x53, 0x3b, 0xfa, 0x1f,
+  0xbe, 0xb3, 0xc5, 0xc3, 0x53, 0x8d, 0xa1, 0x52, 0x71, 0xc8, 0xb6, 0xa6,
+  0x79, 0x49, 0xa9, 0xe5, 0x8d, 0xf9, 0x1e, 0x32, 0x0e, 0x31, 0x9e, 0xda,
+  0xbd, 0x58, 0xab, 0x26, 0x7b, 0x4c, 0x34, 0x4a, 0x04, 0xd5, 0x0a, 0xa3,
+  0x94, 0xbf, 0x51, 0xe8, 0x3e, 0xda, 0xd4, 0xef, 0x5c, 0x07, 0xc3, 0x37,
+  0x69, 0x3c, 0x6f, 0x0e, 0x4a, 0x67, 0x0d, 0x9c, 0xc0, 0xc0, 0x64, 0xfd,
+  0x88, 0x3a, 0x92, 0xd1, 0xc2, 0xdc, 0x37, 0x60, 0xcc, 0xf1, 0xc6, 0xd3,
+  0x54, 0x0f, 0x31, 0x79, 0xbc, 0xc7, 0xf4, 0xe9, 0xac, 0x7a, 0x5d, 0x04,
+  0xb1, 0xcd, 0xb6, 0xf8, 0x11, 0x0d, 0x3b, 0x83, 0xe4, 0x49, 0xc2, 0xfc,
+  0x39, 0x72, 0xac, 0x8a, 0x37, 0xbb, 0xc5, 0x4c, 0xb4, 0x44, 0x15, 0x6a,
+  0x67, 0x4c, 0xb3, 0x83, 0x82, 0x18, 0x10, 0x46, 0x3a, 0x68, 0x3e, 0x36,
+  0xb1, 0x35, 0x92, 0xa6, 0x3a, 0xfa, 0x31, 0x31, 0xa5, 0x3b, 0x2a, 0x46,
+  0x76, 0x88, 0xf4, 0xdf, 0x3f, 0x7e, 0xba, 0xb0, 0x71, 0x0d, 0xfe, 0x0a,
+  0x78, 0xcc, 0xb3, 0x55, 0x88, 0x3c, 0xb9, 0x89, 0x72, 0x00, 0x3e, 0x99,
+  0xc9, 0x03, 0x1f, 0xe9, 0xaa, 0x5c, 0x7f, 0x16, 0x2d, 0x36, 0x62, 0xd4,
+  0xf5, 0xd7, 0x1f, 0xe2, 0x21, 0x9f, 0x99, 0x97, 0x93, 0x9d, 0x87, 0xa8,
+  0xe6, 0x1e, 0x50, 0x07, 0xa0, 0x27, 0x5b, 0xd4, 0x03, 0xd8, 0x9f, 0x42,
+  0xfa, 0x4e, 0x17, 0xae, 0x37, 0x75, 0xbc, 0xd7, 0xd5, 0x8a, 0xce, 0x64,
+  0x23, 0xc0, 0x66, 0xce, 0x33, 0xbe, 0x73, 0xed, 0xd3, 0x54, 0x1f, 0x8a,
+  0x94, 0x33, 0xc1, 0xc4, 0x9e, 0x38, 0xa4, 0x30, 0xc1, 0x34, 0x4a, 0x50,
+  0x21, 0xe6, 0x24, 0x8c, 0x0d, 0xbf, 0xd3, 0x57, 0x4b, 0xc7, 0xc5, 0x4e,
+  0x1b, 0xbc, 0x56, 0xc9, 0x0d, 0xb2, 0xd7, 0x74, 0xab, 0x90, 0x27, 0x24,
+  0x2b, 0x4d, 0xf4, 0xc4, 0xc3, 0x6c, 0x9c, 0xed, 0x81, 0xef, 0x81, 0xaa,
+  0xb9, 0x5b, 0x9d, 0x7c, 0x82, 0xbe, 0xf1, 0x0c, 0xa2, 0x9f, 0x18, 0x8e,
+  0x57, 0xab, 0x40, 0x99, 0xea, 0x72, 0xc0, 0x04, 0x03, 0xdb, 0x9b, 0xf5,
+  0x3a, 0xcb, 0x2c, 0x79, 0x25, 0x26, 0x9a, 0x2f, 0xf8, 0xae, 0x5d, 0x99,
+  0xbf, 0x10, 0xd1, 0x49, 0x51, 0xc4, 0xf7, 0x18, 0x60, 0x4f, 0x11, 0x9e,
+  0xb6, 0x5c, 0x8e, 0x9d, 0x5c, 0xef, 0xaf, 0xd7, 0x27, 0xa6, 0xb5, 0xdb,
+  0x7f, 0x87, 0xc5, 0x2b, 0x7c, 0xcb, 0x6e, 0xee, 0x9d, 0xbd, 0x8e, 0xae,
+  0x8b, 0x69, 0xaa, 0x9a, 0xff, 0x00, 0x51, 0x41, 0x6c, 0xa6, 0xf1, 0xee,
+  0x97, 0x4a, 0xa9, 0x92, 0x05, 0xce, 0xc0, 0x73, 0x12, 0x58, 0x9f, 0xe9,
+  0x03, 0x1a, 0x33, 0x8c, 0x3e, 0x03, 0xf1, 0x3d, 0x05, 0x8e, 0xba, 0xf1,
+  0xf3, 0xf4, 0xf5, 0xa6, 0x91, 0x11, 0xd2, 0x08, 0x54, 0x97, 0x75, 0xc6,
+  0x64, 0x3f, 0xfe, 0xbe, 0x9b, 0xe7, 0xdb, 0x57, 0x91, 0x78, 0xd9, 0x96,
+  0x78, 0x9b, 0x6d, 0xa3, 0x19, 0xab, 0xa9, 0x96, 0x56, 0x26, 0x49, 0x1e,
+  0x42, 0x06, 0x01, 0x63, 0x9d, 0x4b, 0x6a, 0x89, 0x5d, 0x59, 0x83, 0x79,
+  0xbd, 0x31, 0xa8, 0xe7, 0xa6, 0x90, 0x30, 0x52, 0xaf, 0xcf, 0x9d, 0xd7,
+  0x97, 0x7d, 0x3c, 0xb6, 0x5b, 0xda, 0x9a, 0x8f, 0xc7, 0x64, 0x09, 0x2c,
+  0xa5, 0x17, 0x04, 0x67, 0x0a, 0x71, 0x81, 0xf7, 0xff, 0x00, 0xc6, 0xb1,
+  0xa7, 0xb8, 0xcc, 0xe0, 0x19, 0x67, 0xb8, 0x47, 0x6d, 0x82, 0x59, 0x67,
+  0x93, 0x96, 0x30, 0xa4, 0x6b, 0x3c, 0xb8, 0x39, 0x9e, 0xe9, 0x51, 0x3a,
+  0x93, 0x99, 0x27, 0x66, 0x5c, 0xf6, 0x19, 0x3a, 0xd3, 0x69, 0x68, 0xd3,
+  0xe6, 0x5a, 0xa2, 0xa6, 0x30, 0xe3, 0x9b, 0x11, 0xa9, 0x18, 0xc0, 0xf5,
+  0xfb, 0xeb, 0x39, 0xbb, 0xd2, 0x9a, 0x6b, 0xbd, 0x44, 0x1c, 0xc4, 0xf2,
+  0xc8, 0x70, 0x71, 0xef, 0xa7, 0xec, 0xa4, 0x83, 0x8a, 0xa2, 0xc1, 0xc3,
+  0xb5, 0x8d, 0x08, 0x62, 0x42, 0xb8, 0x65, 0x1e, 0x56, 0x19, 0x04, 0xea,
+  0xc5, 0xc2, 0xd4, 0xf0, 0xdc, 0x38, 0x80, 0x07, 0x89, 0xe9, 0xbc, 0xa7,
+  0x2c, 0x06, 0x42, 0x9c, 0x8f, 0xb6, 0xda, 0xa7, 0xd2, 0x18, 0xd6, 0x8c,
+  0xc6, 0xc0, 0x99, 0x41, 0x05, 0x5b, 0xdb, 0x5a, 0x0f, 0x00, 0xa5, 0x6a,
+  0x8a, 0x79, 0x62, 0x85, 0xd9, 0x2a, 0x33, 0x0b, 0xbe, 0x3c, 0xb8, 0xe5,
+  0xce, 0x33, 0xeb, 0xb8, 0x3a, 0x73, 0x9d, 0x2b, 0xfd, 0x06, 0x32, 0xe2,
+  0xee, 0x1c, 0xb0, 0xd8, 0xfe, 0x21, 0xd0, 0x0a, 0xab, 0xbd, 0x45, 0x55,
+  0x35, 0x34, 0x70, 0x4c, 0x44, 0x6a, 0x3e, 0xb2, 0xbc, 0xc5, 0x48, 0x1e,
+  0xf8, 0xeb, 0xd3, 0x3a, 0xcd, 0x38, 0xa6, 0xcf, 0x4b, 0x5d, 0xc6, 0xb7,
+  0xab, 0xa4, 0xf5, 0x11, 0x52, 0xc5, 0x2c, 0x8e, 0xeb, 0x19, 0x04, 0x99,
+  0x25, 0x7d, 0xf9, 0x17, 0x19, 0xe9, 0x83, 0xbf, 0xdb, 0xd7, 0x56, 0xab,
+  0xdd, 0xd6, 0x3b, 0xab, 0x19, 0xa2, 0x6e, 0x49, 0xa1, 0x25, 0x1c, 0x31,
+  0xfa, 0x58, 0x10, 0x33, 0xf6, 0xdb, 0x55, 0x8f, 0x88, 0x15, 0xd4, 0xa6,
+  0x3b, 0x5c, 0x14, 0x30, 0x39, 0xae, 0x87, 0x9d, 0xab, 0x66, 0x32, 0x65,
+  0x67, 0x91, 0xfb, 0xa6, 0xdb, 0x00, 0x30, 0x3f, 0x1a, 0xcc, 0xa5, 0xf2,
+  0x64, 0xe3, 0xa2, 0xd1, 0x52, 0x2f, 0xfc, 0x3e, 0x8a, 0x65, 0x48, 0xc4,
+  0xb2, 0x87, 0x0a, 0xa5, 0x86, 0x00, 0x04, 0x1c, 0x6d, 0xed, 0x8d, 0x4d,
+  0x69, 0xe2, 0xbb, 0xc5, 0x34, 0x4b, 0x1c, 0x12, 0xc5, 0x1a, 0xa8, 0x21,
+  0x93, 0xc3, 0x18, 0x66, 0xf5, 0x3d, 0xce, 0x87, 0xe2, 0x58, 0xd9, 0x2b,
+  0xa3, 0xb6, 0x42, 0xe1, 0xc5, 0x10, 0xc0, 0x23, 0x6c, 0xb9, 0xc1, 0x63,
+  0xf8, 0x27, 0x1a, 0x0c, 0x4b, 0x19, 0x5e, 0x42, 0xac, 0x58, 0x7f, 0xc4,
+  0x38, 0xfa, 0x4e, 0xb5, 0xf4, 0x39, 0x16, 0x7b, 0x15, 0xc6, 0xe7, 0x73,
+  0xae, 0x35, 0xb5, 0x0c, 0x25, 0x00, 0x9e, 0x71, 0xd1, 0x11, 0x7d, 0x00,
+  0xec, 0x75, 0x2d, 0x4c, 0x40, 0x1a, 0x98, 0xa9, 0xd5, 0xb1, 0x16, 0x64,
+  0x4d, 0xf3, 0xe5, 0x27, 0xae, 0x74, 0x82, 0xd1, 0x72, 0xa9, 0xb7, 0x64,
+  0x42, 0xd9, 0x89, 0x98, 0x97, 0x18, 0xea, 0x0e, 0xad, 0x36, 0xf9, 0xc5,
+  0x6c, 0x2c, 0x88, 0x03, 0x10, 0x79, 0xe2, 0x5f, 0x62, 0x3a, 0x7e, 0xfa,
+  0xb4, 0x6c, 0xd3, 0x83, 0x50, 0xc0, 0xb3, 0xd4, 0xc5, 0x5b, 0x01, 0xf0,
+  0x96, 0x58, 0xb9, 0x26, 0xe6, 0x53, 0x82, 0xc3, 0x6e, 0xde, 0xa7, 0x18,
+  0xd3, 0x7b, 0x2c, 0x71, 0x52, 0xdf, 0xed, 0xf5, 0xf1, 0x0c, 0x53, 0x73,
+  0x9a, 0x1a, 0x96, 0x1f, 0xff, 0x00, 0x66, 0x3f, 0xb6, 0x30, 0x7f, 0x3a,
+  0x5d, 0x65, 0x45, 0x8a, 0xa5, 0xa1, 0x9d, 0xfc, 0x0d, 0xd8, 0xb6, 0xdc,
+  0xc0, 0x95, 0xdf, 0x18, 0xfb, 0x8e, 0xba, 0xea, 0xcf, 0x3a, 0xcb, 0x69,
+  0xbc, 0xa5, 0x53, 0xb1, 0x95, 0x58, 0xbb, 0x39, 0x3d, 0xf9, 0x87, 0x2e,
+  0x3e, 0xc7, 0x23, 0xf1, 0xa2, 0x43, 0x3d, 0x93, 0x49, 0x11, 0xa7, 0x9a,
+  0x78, 0x60, 0x3e, 0x54, 0x6f, 0x5c, 0xe0, 0x69, 0x84, 0x15, 0x08, 0xd6,
+  0x41, 0x4f, 0x50, 0x39, 0x8b, 0x49, 0x98, 0x37, 0xdd, 0x98, 0x03, 0xd3,
+  0xf7, 0xd0, 0x15, 0x14, 0xb5, 0x0e, 0x94, 0xf7, 0x17, 0x85, 0x9a, 0x39,
+  0x23, 0x0b, 0x20, 0x88, 0xe4, 0x82, 0x36, 0x39, 0xd7, 0x0e, 0xc6, 0x98,
+  0x2c, 0x94, 0x75, 0x0d, 0xe4, 0x60, 0x40, 0xce, 0xe1, 0xbd, 0xff, 0x00,
+  0x7d, 0x50, 0xf4, 0x7e, 0x6a, 0xa9, 0xff, 0x00, 0x85, 0x53, 0x49, 0x48,
+  0x18, 0x4b, 0x04, 0xce, 0x84, 0x77, 0xc6, 0x73, 0x9f, 0xdb, 0x45, 0xb2,
+  0x4b, 0x2d, 0xe2, 0x63, 0xcc, 0x59, 0xbc, 0x2e, 0x60, 0x01, 0xc6, 0x0e,
+  0x3d, 0x75, 0xc9, 0x84, 0x5d, 0xe9, 0x25, 0xa8, 0x5c, 0x53, 0x55, 0x27,
+  0xf5, 0x46, 0x70, 0x8c, 0xc7, 0x3e, 0x56, 0x1d, 0x8e, 0x74, 0x4d, 0x9a,
+  0x41, 0x58, 0xd4, 0x8d, 0x2e, 0x56, 0xaa, 0x37, 0x30, 0xb8, 0x23, 0xa8,
+  0x39, 0xe5, 0x38, 0xfd, 0xb5, 0x54, 0x49, 0x15, 0xae, 0x28, 0xa3, 0x2f,
+  0xc4, 0xd3, 0x54, 0x48, 0xac, 0xf0, 0x48, 0x82, 0x52, 0x71, 0xb1, 0x63,
+  0x8d, 0x89, 0xf5, 0xeb, 0xa5, 0xdc, 0xb8, 0x6f, 0x11, 0x5b, 0x0f, 0x1e,
+  0x42, 0xae, 0x3a, 0x2f, 0xae, 0xad, 0x9c, 0x49, 0x56, 0xf4, 0xf6, 0xfa,
+  0x3b, 0x8d, 0x1c, 0x41, 0xd3, 0xc3, 0xe4, 0x92, 0x22, 0xde, 0x5d, 0xb2,
+  0x37, 0xfd, 0x35, 0x4b, 0x37, 0xba, 0xda, 0x89, 0x8a, 0x9a, 0x6a, 0x78,
+  0x81, 0x18, 0xe9, 0x80, 0x07, 0xaf, 0xbf, 0x6d, 0x15, 0x18, 0x72, 0x7d,
+  0xd9, 0x75, 0xf8, 0x4f, 0x7c, 0xa5, 0xb3, 0xf1, 0xc5, 0xb2, 0xbe, 0xa9,
+  0x4a, 0x94, 0x94, 0x02, 0xfc, 0xd8, 0x18, 0xf7, 0xd7, 0xb7, 0xa8, 0xea,
+  0xe9, 0xea, 0x29, 0xa3, 0x9a, 0x98, 0xa3, 0x41, 0x22, 0x86, 0x46, 0x43,
+  0x90, 0x41, 0xe8, 0x75, 0xe0, 0x2b, 0x7c, 0x15, 0x0b, 0x02, 0x4d, 0x3d,
+  0x3a, 0x87, 0xce, 0x41, 0xe5, 0xc1, 0x03, 0x5e, 0x90, 0xff, 0x00, 0x67,
+  0x6e, 0x2a, 0x6b, 0x85, 0xa4, 0xd8, 0x2b, 0x80, 0x13, 0x52, 0xe5, 0xa9,
+  0xb2, 0x73, 0x94, 0xcf, 0x4d, 0x32, 0x2c, 0xa8, 0x48, 0xdd, 0xe0, 0x99,
+  0x55, 0xf1, 0xeb, 0xdf, 0x45, 0xbc, 0xbc, 0x89, 0x91, 0xbe, 0xfa, 0x4b,
+  0x4a, 0xdc, 0xca, 0x07, 0x71, 0xa2, 0x26, 0x9f, 0x92, 0x22, 0x19, 0xbb,
+  0x69, 0xa8, 0x68, 0x45, 0x44, 0xfe, 0x5e, 0xb8, 0xd2, 0xca, 0xa9, 0xfa,
+  0xf9, 0xbb, 0xe9, 0x7c, 0xb5, 0x8a, 0xb2, 0x31, 0x2c, 0xaa, 0xbe, 0xa5,
+  0x80, 0xc0, 0xd2, 0xea, 0xdb, 0xac, 0x14, 0xea, 0xd3, 0xb3, 0x3b, 0xc0,
+  0x33, 0xe7, 0x8d, 0x4b, 0xef, 0xd7, 0xb6, 0xac, 0x83, 0xbb, 0x75, 0x63,
+  0xa5, 0x49, 0x8d, 0x8f, 0x95, 0x89, 0x20, 0xea, 0xd1, 0x4a, 0xcc, 0x62,
+  0x04, 0xee, 0x35, 0xe7, 0xeb, 0xd7, 0x12, 0x5c, 0xab, 0x49, 0xa9, 0x49,
+  0x24, 0xa3, 0x89, 0x1f, 0xc2, 0x86, 0x15, 0xf3, 0x4b, 0x29, 0x39, 0x39,
+  0xed, 0xca, 0x36, 0x1b, 0x9f, 0x5e, 0x9a, 0xdb, 0x12, 0xbd, 0xa8, 0xf8,
+  0x7e, 0x0a, 0xaa, 0x85, 0x31, 0x4e, 0xd0, 0x2b, 0x14, 0x3d, 0x41, 0x2a,
+  0x09, 0xce, 0x91, 0x8b, 0x3a, 0xc9, 0x26, 0x97, 0xa0, 0x20, 0xd4, 0x9d,
+  0x20, 0x6b, 0xcb, 0x78, 0x77, 0x50, 0x3a, 0xe4, 0x67, 0x46, 0x51, 0x1f,
+  0x19, 0x25, 0x88, 0x0c, 0x17, 0x52, 0x07, 0xdf, 0x1a, 0xa5, 0x35, 0xf2,
+  0xbe, 0xe3, 0xc4, 0x51, 0x43, 0x48, 0x61, 0x9e, 0x30, 0xa7, 0xc6, 0x04,
+  0x79, 0x90, 0x9d, 0xfa, 0xfd, 0xb5, 0x64, 0xa4, 0xb8, 0x2d, 0x3b, 0xc5,
+  0x29, 0x39, 0x05, 0x82, 0xe7, 0xd7, 0x3a, 0xa8, 0xe5, 0x8e, 0x44, 0xf6,
+  0xbe, 0x86, 0x5a, 0x92, 0x69, 0x3e, 0x80, 0xa3, 0xe1, 0x1b, 0x65, 0x4c,
+  0x4b, 0x2d, 0x7f, 0x96, 0x44, 0x5e, 0x42, 0xb1, 0xca, 0x76, 0x23, 0xb8,
+  0xc6, 0x30, 0x74, 0x8a, 0xe4, 0x38, 0x96, 0xc7, 0x7b, 0xa7, 0xb7, 0x5b,
+  0x64, 0x96, 0xe7, 0x4b, 0x3a, 0x99, 0x14, 0x48, 0x33, 0x22, 0x28, 0x38,
+  0xe5, 0x2d, 0xd8, 0x6e, 0x34, 0xcb, 0x8e, 0xea, 0x64, 0xb4, 0x66, 0x7a,
+  0xdb, 0xd5, 0xb2, 0xdf, 0x04, 0x8e, 0x79, 0x92, 0x49, 0xf9, 0x5c, 0x8c,
+  0xfd, 0x41, 0x71, 0x92, 0x7d, 0xbb, 0xea, 0x9b, 0x37, 0xc5, 0xce, 0x1b,
+  0xa5, 0xb4, 0x34, 0x34, 0x13, 0xd6, 0xd6, 0x4c, 0xb1, 0xf2, 0xc2, 0x44,
+  0x44, 0x79, 0xb1, 0xf5, 0x1e, 0xbe, 0x53, 0xe9, 0xae, 0x16, 0x3c, 0x9a,
+  0x95, 0x36, 0xa1, 0x0a, 0xff, 0x00, 0x3e, 0x8c, 0xdf, 0x14, 0xa5, 0xe8,
+  0xb8, 0xcd, 0xc4, 0x73, 0x50, 0x31, 0xa6, 0xb8, 0xd3, 0xc9, 0x4c, 0xdc,
+  0x9c, 0xfb, 0xb6, 0x46, 0x3e, 0xfa, 0xad, 0xdf, 0xbe, 0x23, 0x59, 0xe8,
+  0x22, 0x59, 0x85, 0x55, 0x2c, 0x93, 0xf3, 0xf2, 0xad, 0x3b, 0x31, 0x63,
+  0x8c, 0xe3, 0x99, 0xb1, 0xd0, 0x7e, 0x7b, 0xeb, 0x22, 0x96, 0xb2, 0xf9,
+  0xc6, 0x55, 0xf3, 0x09, 0x1a, 0x69, 0x51, 0x5c, 0xb9, 0x54, 0x41, 0x15,
+  0x3c, 0x64, 0xf4, 0xe6, 0xc6, 0xe4, 0x9d, 0xc6, 0x0e, 0x4f, 0x6d, 0x29,
+  0x96, 0x2e, 0x1c, 0xa4, 0xac, 0xe6, 0xbe, 0x5c, 0x64, 0x75, 0x89, 0x5d,
+  0x65, 0xa7, 0xa3, 0x42, 0x5d, 0x88, 0x38, 0xc1, 0x6f, 0xe9, 0xff, 0x00,
+  0xa7, 0x4d, 0x76, 0x71, 0xbc, 0x95, 0x52, 0xec, 0xd4, 0xb0, 0x3f, 0x6c,
+  0xb6, 0x71, 0xad, 0xde, 0xcf, 0xc4, 0xb7, 0x65, 0xaa, 0xb9, 0xf1, 0x15,
+  0xb6, 0x8a, 0x8a, 0x37, 0xc8, 0x86, 0x29, 0x5e, 0x50, 0xa4, 0xfd, 0x44,
+  0xe4, 0x6e, 0x7a, 0x0c, 0x69, 0x7c, 0xf7, 0xbe, 0x04, 0xb4, 0xc4, 0x63,
+  0xa2, 0xa9, 0x6a, 0xf9, 0x1b, 0x67, 0x10, 0xc2, 0x79, 0xa5, 0xfc, 0x9c,
+  0x05, 0xfd, 0xfa, 0xea, 0xab, 0x57, 0x37, 0x0e, 0x04, 0x0d, 0x64, 0xe1,
+  0xaa, 0x8a, 0x97, 0x00, 0x7f, 0x32, 0xb6, 0x76, 0x92, 0x34, 0xce, 0xd9,
+  0xe5, 0x18, 0xe6, 0x39, 0x23, 0xfd, 0x34, 0xef, 0x87, 0xb8, 0x16, 0x77,
+  0xa4, 0xf9, 0xaa, 0xc7, 0x8a, 0xd9, 0xce, 0xbe, 0x21, 0x62, 0x8a, 0x18,
+  0x67, 0xb8, 0xe7, 0xfa, 0x74, 0xdb, 0x1d, 0x08, 0xb5, 0xd1, 0x61, 0x86,
+  0xe5, 0x77, 0x7b, 0x64, 0xa2, 0x38, 0xad, 0xbc, 0x27, 0x6a, 0x68, 0xf1,
+  0xcd, 0x33, 0x8f, 0x98, 0xe5, 0x3d, 0x08, 0x41, 0xfd, 0x47, 0xfe, 0x6f,
+  0x53, 0xaa, 0xcd, 0xde, 0xf1, 0xc2, 0x23, 0x99, 0x5c, 0x5d, 0x2f, 0x72,
+  0xa1, 0xc2, 0xd5, 0x56, 0xce, 0x4c, 0x63, 0xd9, 0x46, 0x7a, 0x7a, 0x0c,
+  0x0d, 0xb4, 0xba, 0xae, 0xc1, 0x49, 0x3d, 0xda, 0x4a, 0x5a, 0x2a, 0xe1,
+  0x58, 0x15, 0xb9, 0x66, 0xa9, 0x79, 0x76, 0x62, 0x33, 0xe5, 0x1d, 0xc9,
+  0x1b, 0xe7, 0x1b, 0x68, 0xb8, 0xe2, 0xe1, 0x7a, 0x08, 0x42, 0xd4, 0xd5,
+  0xc4, 0xd2, 0x01, 0x90, 0x24, 0xc9, 0x1c, 0xd8, 0xe9, 0x8f, 0x4f, 0x4d,
+  0x1b, 0x65, 0xb4, 0x4c, 0xb7, 0xba, 0xfb, 0x4f, 0x1d, 0x56, 0xdc, 0x69,
+  0x2b, 0x65, 0xa3, 0xaa, 0xa7, 0xa9, 0x99, 0x20, 0x70, 0x7c, 0xc4, 0x19,
+  0x1b, 0x3f, 0x8e, 0xda, 0xd3, 0xf8, 0x67, 0xe3, 0x45, 0xd6, 0x39, 0x61,
+  0x8a, 0xfb, 0x8a, 0x88, 0x73, 0xca, 0xd2, 0x20, 0x0a, 0xe4, 0x7b, 0x8e,
+  0x87, 0xfb, 0xeb, 0x23, 0xbe, 0xc6, 0x0f, 0x13, 0xdc, 0x9a, 0x60, 0xc5,
+  0x8d, 0x54, 0x9c, 0x80, 0x0c, 0xec, 0x1c, 0xe8, 0xfa, 0x63, 0x1b, 0xc6,
+  0x09, 0x5c, 0x82, 0x30, 0x41, 0xd2, 0x6e, 0xa3, 0xb4, 0xe3, 0xe4, 0xf1,
+  0x67, 0xde, 0x31, 0xa0, 0xa3, 0x8f, 0x8a, 0x6b, 0xaa, 0xed, 0xc9, 0x10,
+  0xb7, 0x4c, 0xcd, 0x3d, 0x17, 0x21, 0xdb, 0x0c, 0xd9, 0xc9, 0x1d, 0xb0,
+  0x0e, 0x31, 0xdb, 0x43, 0x54, 0x02, 0xd4, 0x54, 0xca, 0x18, 0x85, 0xe6,
+  0x8c, 0xe3, 0xf2, 0x34, 0xc6, 0x44, 0x89, 0xa9, 0x8d, 0x3c, 0x69, 0x1b,
+  0x33, 0x1f, 0x21, 0x2b, 0xba, 0x3f, 0x62, 0x3e, 0xe7, 0x63, 0xf7, 0xd0,
+  0x56, 0x5a, 0x0f, 0xe2, 0x17, 0xcb, 0x75, 0xa2, 0x6a, 0xc4, 0xa7, 0x8e,
+  0x79, 0x04, 0x52, 0x36, 0x39, 0xb9, 0x3c, 0xd9, 0x07, 0x1e, 0xb9, 0xc6,
+  0xb3, 0x28, 0xed, 0x95, 0x02, 0x9d, 0xc4, 0xb0, 0xf0, 0x55, 0x82, 0x6b,
+  0xfd, 0xfa, 0x9e, 0x85, 0x00, 0x31, 0x31, 0x1e, 0x33, 0x90, 0x71, 0x1c,
+  0x7d, 0xcf, 0xf6, 0x1f, 0x9d, 0x50, 0xfe, 0x32, 0x5a, 0xa9, 0x6d, 0x5f,
+  0x10, 0xaf, 0x94, 0xd4, 0x34, 0xc1, 0x29, 0x29, 0xeb, 0x4a, 0x46, 0x46,
+  0xf8, 0x05, 0x43, 0x72, 0x93, 0xeb, 0xb9, 0xd7, 0xaa, 0xed, 0x16, 0x5a,
+  0x5e, 0x13, 0x85, 0xe8, 0x28, 0xd8, 0x62, 0x48, 0xd9, 0xaa, 0x4f, 0xf5,
+  0xc8, 0x01, 0x1e, 0x6d, 0xba, 0x36, 0x3f, 0x1a, 0xf3, 0x97, 0x19, 0xdd,
+  0x29, 0xeb, 0x6d, 0x7c, 0x55, 0x0d, 0x25, 0x12, 0xb0, 0xae, 0xba, 0x1a,
+  0xb8, 0xea, 0xa4, 0x39, 0x91, 0x52, 0x2e, 0x60, 0xa9, 0xf6, 0x20, 0x92,
+  0x4f, 0xe3, 0x4d, 0xc9, 0xe5, 0x51, 0x06, 0x8c, 0xe2, 0x09, 0xd0, 0x37,
+  0x32, 0x8d, 0xba, 0x11, 0x9d, 0x6e, 0x3c, 0x2b, 0x55, 0x40, 0x7e, 0x16,
+  0xd1, 0x5b, 0xe5, 0xa3, 0x9e, 0x3a, 0xd4, 0x91, 0xea, 0x22, 0xa9, 0x59,
+  0x30, 0x00, 0x6c, 0x13, 0xe5, 0xfb, 0x05, 0xdf, 0xdb, 0x59, 0x07, 0x04,
+  0x59, 0xc5, 0xfb, 0x89, 0xe8, 0x6d, 0x23, 0x64, 0xa8, 0x90, 0xf3, 0x9f,
+  0x45, 0x00, 0xb1, 0xfe, 0xdf, 0xdb, 0x5e, 0x9c, 0x8b, 0xe1, 0xfc, 0xf1,
+  0xd1, 0x22, 0x55, 0xc9, 0x4d, 0x6f, 0xa5, 0x5a, 0x7c, 0x86, 0x73, 0x9e,
+  0x45, 0x1b, 0x00, 0x07, 0xae, 0xb8, 0xda, 0xdc, 0xfa, 0x88, 0xc9, 0x43,
+  0x12, 0xbf, 0xd8, 0x13, 0x52, 0xfe, 0xd3, 0x05, 0xae, 0xe1, 0xda, 0x81,
+  0x0c, 0xdc, 0xd3, 0x89, 0x91, 0xdc, 0xb4, 0x8d, 0xcb, 0xe6, 0x6d, 0xf2,
+  0x73, 0xf9, 0xd2, 0xdb, 0x9d, 0x0d, 0xb1, 0xa9, 0x84, 0x1e, 0x19, 0x04,
+  0xe0, 0xb3, 0x03, 0xe6, 0xce, 0x3f, 0xb6, 0xac, 0x9c, 0x4b, 0x5a, 0x69,
+  0x0c, 0xf0, 0xa4, 0x81, 0xe3, 0xe6, 0x60, 0xa5, 0x98, 0x2f, 0x32, 0xee,
+  0x01, 0xdf, 0xf1, 0xac, 0xd2, 0x82, 0x99, 0xea, 0xeb, 0x64, 0xa3, 0xa7,
+  0xac, 0x20, 0x80, 0x59, 0xf1, 0xd0, 0x0c, 0xe0, 0x8c, 0xfd, 0xce, 0x9d,
+  0xa5, 0xb9, 0xa4, 0xdf, 0x65, 0x20, 0x49, 0x2d, 0x46, 0xdd, 0x5b, 0x3b,
+  0x02, 0x5e, 0x19, 0xd4, 0x90, 0xc7, 0xae, 0x73, 0xd0, 0xeb, 0x93, 0x1c,
+  0x7f, 0x26, 0xf4, 0x7e, 0x1a, 0x04, 0x76, 0x0f, 0xcd, 0x8f, 0x36, 0x40,
+  0x23, 0xaf, 0xa6, 0xfa, 0x7d, 0xf2, 0x49, 0x6e, 0x81, 0xe3, 0x3e, 0x6e,
+  0x6e, 0xad, 0xeb, 0xed, 0x9d, 0x71, 0x4f, 0x46, 0x95, 0xd0, 0xb3, 0xd3,
+  0x00, 0x42, 0xec, 0xc0, 0x9e, 0x87, 0x5b, 0x5c, 0x87, 0x29, 0x95, 0x65,
+  0xa4, 0x44, 0x8a, 0x58, 0x02, 0x61, 0x8f, 0x98, 0x1f, 0x5c, 0x76, 0xd3,
+  0xfe, 0x1e, 0x30, 0xac, 0x54, 0xb5, 0x04, 0x12, 0x23, 0x1e, 0x1c, 0xdb,
+  0xe0, 0x80, 0x7b, 0xff, 0x00, 0x6d, 0x7c, 0xb8, 0x50, 0x48, 0xb0, 0x1f,
+  0x05, 0x59, 0x59, 0x71, 0xcc, 0xfd, 0x40, 0xc7, 0x5c, 0xe8, 0x5a, 0x39,
+  0xdd, 0x64, 0x68, 0xe4, 0x05, 0x56, 0x4c, 0x07, 0x1d, 0x41, 0xdf, 0xd7,
+  0x4d, 0xc5, 0x3b, 0x56, 0x6a, 0xd2, 0xcf, 0x91, 0x85, 0x7a, 0xad, 0x05,
+  0xc3, 0xc3, 0x0c, 0x4a, 0x33, 0x07, 0xe7, 0x53, 0xb3, 0x6f, 0x9f, 0xdc,
+  0x68, 0x9a, 0x98, 0x20, 0xb8, 0x55, 0x5d, 0x24, 0x85, 0x4d, 0x27, 0xcc,
+  0xc7, 0x12, 0x53, 0xc6, 0x83, 0x79, 0x31, 0x8e, 0x62, 0x7f, 0xd7, 0xd8,
+  0xe8, 0x6f, 0x97, 0x82, 0x96, 0x7a, 0xa4, 0xa8, 0x54, 0x94, 0xbc, 0x79,
+  0x8b, 0x7c, 0xf2, 0x80, 0x71, 0x91, 0xe8, 0x74, 0x55, 0xa2, 0x17, 0x7a,
+  0xba, 0x66, 0xa5, 0x1e, 0x2c, 0x49, 0x19, 0x8f, 0x9a, 0x56, 0x3e, 0x47,
+  0x61, 0xb9, 0xc8, 0xec, 0x0e, 0x9b, 0x66, 0xd7, 0xc9, 0x1d, 0x96, 0xb2,
+  0xa5, 0x65, 0x31, 0x46, 0xdc, 0xf1, 0x16, 0xdf, 0x27, 0x66, 0x1a, 0x6f,
+  0x14, 0x74, 0xa9, 0x4c, 0xce, 0x39, 0xb9, 0xea, 0x25, 0x74, 0xf0, 0x94,
+  0x67, 0x93, 0x7d, 0x8e, 0x4e, 0xf8, 0xd4, 0x14, 0xd4, 0xd3, 0x5b, 0x78,
+  0x82, 0xa6, 0x9a, 0xb6, 0x9d, 0x23, 0xe6, 0x50, 0x33, 0x17, 0xd0, 0xa0,
+  0xee, 0x37, 0xf7, 0xce, 0xbe, 0x56, 0xd2, 0x9b, 0x4d, 0xc9, 0x6b, 0x23,
+  0x8c, 0xcb, 0x09, 0x7f, 0xa4, 0x37, 0x4e, 0xf8, 0x3e, 0x9b, 0x6a, 0x30,
+  0xa2, 0x88, 0x69, 0xcc, 0x94, 0x57, 0x52, 0x7c, 0xc6, 0x35, 0x2a, 0x1d,
+  0x47, 0x7e, 0xbb, 0xe9, 0x90, 0x53, 0x4f, 0x78, 0x92, 0xa2, 0x17, 0x02,
+  0x0a, 0xef, 0x2c, 0x52, 0x2e, 0xde, 0x14, 0x9d, 0x41, 0xfd, 0x8e, 0xba,
+  0xe2, 0x2a, 0x64, 0xf9, 0x68, 0xaf, 0x14, 0x39, 0x28, 0xdc, 0xae, 0xd9,
+  0x39, 0xc0, 0x3d, 0x0f, 0xe3, 0xa6, 0x34, 0x05, 0x75, 0x4d, 0x2d, 0x4f,
+  0x0e, 0x35, 0x62, 0x00, 0x67, 0x49, 0x42, 0xbb, 0x2f, 0x73, 0xeb, 0xf7,
+  0xef, 0xaa, 0x0d, 0x87, 0x08, 0x45, 0x4d, 0x75, 0x4d, 0x02, 0xc6, 0x40,
+  0x59, 0x85, 0x42, 0x46, 0xeb, 0x80, 0x41, 0x18, 0x7f, 0xc7, 0x43, 0xaa,
+  0x4d, 0xd6, 0xa6, 0x1b, 0x87, 0x10, 0x22, 0x50, 0xa2, 0xc5, 0x12, 0xc9,
+  0x9d, 0x97, 0xea, 0xc6, 0x7a, 0x6a, 0xf1, 0x72, 0x0f, 0x47, 0x53, 0x41,
+  0x75, 0x2e, 0xb2, 0xbc, 0x54, 0xd1, 0x34, 0x8a, 0x06, 0xcf, 0x19, 0x18,
+  0x20, 0xfd, 0x8e, 0x35, 0x47, 0xe2, 0x8a, 0x38, 0x2d, 0x97, 0xea, 0x82,
+  0x8b, 0xcb, 0x4f, 0x54, 0x9e, 0x3d, 0x39, 0xce, 0x70, 0x1b, 0x7f, 0xdb,
+  0xa6, 0xad, 0x19, 0x73, 0xae, 0x0b, 0x50, 0xa6, 0x6a, 0x1b, 0x5b, 0xd7,
+  0xdc, 0x5f, 0xcc, 0xe7, 0x96, 0x3c, 0x8c, 0xfd, 0x8f, 0xed, 0xa7, 0x1f,
+  0x04, 0xaf, 0xcf, 0x6b, 0xe3, 0xfb, 0x7a, 0x00, 0x43, 0xd6, 0x54, 0xaa,
+  0x6c, 0x70, 0x00, 0x3d, 0x7f, 0xf1, 0xac, 0xb3, 0xe7, 0x95, 0x6d, 0xed,
+  0x14, 0xb2, 0xb4, 0xd2, 0x48, 0xc7, 0xc4, 0x24, 0xe7, 0xec, 0x33, 0xab,
+  0xef, 0xc0, 0x0a, 0x09, 0x27, 0xf8, 0x89, 0x63, 0x25, 0x39, 0xb1, 0x52,
+  0xa4, 0x7b, 0x0e, 0xa7, 0xf6, 0xd1, 0xc4, 0x44, 0x4f, 0x6e, 0xb1, 0x5e,
+  0x75, 0x2a, 0xa1, 0x01, 0x1b, 0x01, 0xe9, 0xeb, 0xa4, 0x7c, 0x57, 0x74,
+  0xa7, 0xb5, 0xda, 0xea, 0xeb, 0x6a, 0xe6, 0x11, 0x41, 0x04, 0x4c, 0xf2,
+  0x31, 0xec, 0x00, 0xd3, 0xa9, 0x4a, 0x99, 0x32, 0xbf, 0x4a, 0x2e, 0xb0,
+  0x7f, 0xf6, 0xa7, 0xe2, 0x94, 0xa5, 0xb0, 0xc3, 0x60, 0x81, 0xc8, 0x9e,
+  0xe0, 0xe7, 0xc4, 0x55, 0x3d, 0x23, 0x53, 0xd4, 0xfd, 0xcf, 0xf6, 0x3a,
+  0x63, 0x63, 0x51, 0x94, 0x5f, 0xf8, 0xf6, 0xff, 0x00, 0xc4, 0x77, 0x4a,
+  0xd6, 0x35, 0xf5, 0x30, 0xd0, 0x34, 0xdc, 0xa9, 0x0a, 0x30, 0x1c, 0xb1,
+  0x6f, 0x80, 0x76, 0xdf, 0x6d, 0xb5, 0xdc, 0xbc, 0x47, 0x53, 0xf3, 0xf5,
+  0x74, 0x56, 0xda, 0xc9, 0x29, 0xa8, 0x0b, 0x83, 0x1c, 0x68, 0x4a, 0xb3,
+  0x63, 0x6c, 0x92, 0x31, 0x9d, 0x56, 0x6d, 0x74, 0x5e, 0x2c, 0x1e, 0x29,
+  0xa8, 0x58, 0xff, 0x00, 0xa5, 0x55, 0xd4, 0x8f, 0x13, 0x1e, 0x9a, 0xfd,
+  0x4b, 0x14, 0x82, 0xf9, 0x0b, 0xb4, 0x4e, 0xb0, 0x44, 0xc0, 0x49, 0x21,
+  0x5e, 0xdf, 0x6d, 0x62, 0x72, 0x94, 0xd3, 0x89, 0x9d, 0xdb, 0xb4, 0x8d,
+  0xe7, 0xe0, 0x15, 0x8e, 0xe5, 0xc4, 0x17, 0xef, 0x98, 0xb9, 0x09, 0x1a,
+  0xd3, 0x42, 0x7c, 0x4e, 0x79, 0x06, 0x79, 0xdc, 0x74, 0x50, 0x7b, 0xff,
+  0x00, 0xd3, 0x5a, 0x77, 0xc5, 0x1e, 0x2b, 0xa5, 0xa2, 0x43, 0x11, 0x9c,
+  0x21, 0x07, 0x94, 0x31, 0xd8, 0x2e, 0x3a, 0x93, 0xe8, 0x06, 0xa8, 0x77,
+  0xef, 0x8a, 0x74, 0x74, 0x56, 0x18, 0x6d, 0x3c, 0x27, 0x47, 0xe1, 0xd2,
+  0xc3, 0x12, 0xc6, 0x27, 0x90, 0x00, 0x84, 0x8e, 0xbb, 0x77, 0xc7, 0xdf,
+  0x59, 0xf5, 0x4d, 0xee, 0xbe, 0xf6, 0xe6, 0x79, 0x99, 0x6e, 0x55, 0x59,
+  0x38, 0x12, 0x36, 0x51, 0x47, 0xd8, 0x6c, 0x07, 0xdf, 0x27, 0x4c, 0x86,
+  0x3f, 0x8f, 0x15, 0x47, 0xb3, 0x44, 0x31, 0x54, 0x69, 0x70, 0x5f, 0x69,
+  0xbe, 0x21, 0xf0, 0xd5, 0xaa, 0x1f, 0xfe, 0x9f, 0x2c, 0xd5, 0x55, 0x72,
+  0x00, 0x6a, 0x3c, 0x38, 0x39, 0x8c, 0x8c, 0x47, 0x9b, 0x7e, 0xc0, 0xe4,
+  0xea, 0xb1, 0xc4, 0x5c, 0x6f, 0x7c, 0xba, 0xd5, 0x43, 0x50, 0x95, 0x37,
+  0x0b, 0x65, 0x3c, 0x3f, 0x42, 0xc3, 0x10, 0x0e, 0xc7, 0xb1, 0x1b, 0xfe,
+  0xfa, 0x54, 0xd7, 0xfe, 0x21, 0xb3, 0x42, 0x89, 0x4d, 0x6d, 0xb5, 0xd3,
+  0xc1, 0x1f, 0x2f, 0x3c, 0x49, 0x16, 0x5d, 0x8e, 0x06, 0xe7, 0xbb, 0x7a,
+  0xfa, 0x7b, 0x68, 0x6a, 0xee, 0x2e, 0xbe, 0xd5, 0xce, 0xe5, 0xea, 0x68,
+  0xbc, 0x73, 0x9f, 0x0d, 0xd2, 0x21, 0xcc, 0x83, 0x3f, 0xd2, 0x3a, 0x03,
+  0xd3, 0x7c, 0x67, 0x43, 0x87, 0x14, 0x71, 0x7d, 0x46, 0x43, 0x02, 0xc6,
+  0xb8, 0x19, 0x7c, 0xe3, 0xb5, 0x48, 0xaa, 0x97, 0x87, 0x12, 0xe1, 0x70,
+  0x9f, 0xfe, 0x1d, 0x55, 0xca, 0xa5, 0xe7, 0x76, 0x63, 0xbe, 0x79, 0x00,
+  0xc1, 0xf5, 0xc6, 0xfd, 0xf4, 0x2c, 0xb7, 0xba, 0x1a, 0x1b, 0xa3, 0xcd,
+  0x3d, 0xaf, 0xf8, 0xbd, 0x48, 0x51, 0xe7, 0xa8, 0xfe, 0x45, 0x30, 0xf6,
+  0x48, 0xb1, 0xb8, 0x1b, 0xee, 0x71, 0xf9, 0xd5, 0x7e, 0xe5, 0x76, 0xb8,
+  0xd7, 0xb9, 0x5b, 0xd5, 0x55, 0x55, 0x7b, 0xf2, 0xff, 0x00, 0x2d, 0x60,
+  0xf2, 0x85, 0xf7, 0x3e, 0xfa, 0xf9, 0x4d, 0x14, 0x41, 0x61, 0x47, 0x81,
+  0x56, 0x49, 0x59, 0x7c, 0x3f, 0x12, 0x41, 0x9d, 0xf6, 0xc1, 0xf4, 0x1d,
+  0xf1, 0xa6, 0x58, 0xed, 0xa5, 0x8a, 0xa7, 0x89, 0x6a, 0x6b, 0xe3, 0x96,
+  0x28, 0xea, 0x69, 0x6c, 0x74, 0xb8, 0xc9, 0x4a, 0x38, 0xda, 0x49, 0x71,
+  0xf7, 0x18, 0x03, 0xa9, 0xd8, 0x63, 0x43, 0x50, 0xd5, 0x70, 0x8d, 0xb1,
+  0xa1, 0x06, 0xd5, 0x55, 0x57, 0x50, 0xc0, 0x06, 0x32, 0xaf, 0x29, 0x95,
+  0x8f, 0x42, 0xc4, 0xef, 0xf8, 0x18, 0xeb, 0xed, 0xa0, 0x8c, 0x36, 0xca,
+  0x59, 0x1e, 0x4a, 0xdb, 0x8d, 0xbd, 0x21, 0x58, 0x8b, 0x49, 0x1d, 0x34,
+  0xad, 0x27, 0x33, 0xf4, 0xe5, 0xcf, 0x63, 0x9d, 0xf1, 0xf7, 0xd2, 0xfb,
+  0x6d, 0x7d, 0x20, 0x68, 0xca, 0x51, 0x97, 0x8d, 0x18, 0x16, 0xe7, 0x8f,
+  0x24, 0x8e, 0xd9, 0x3d, 0x8e, 0xa5, 0x93, 0x69, 0x6c, 0xad, 0xe3, 0x28,
+  0xe8, 0xa5, 0x14, 0xbc, 0x3d, 0xc2, 0xd4, 0xd4, 0x55, 0x2d, 0xb4, 0xad,
+  0x2c, 0x61, 0xcf, 0x3f, 0xa8, 0x07, 0xd3, 0x1a, 0x45, 0x57, 0x3d, 0xd6,
+  0xe3, 0xe2, 0xd6, 0x5d, 0xee, 0x0f, 0x2e, 0x58, 0xf3, 0x2e, 0xfb, 0x7d,
+  0x87, 0x7f, 0xb6, 0xa0, 0x9e, 0xe5, 0x33, 0xdc, 0x26, 0x9e, 0x7a, 0x76,
+  0x48, 0x99, 0x88, 0x48, 0xd1, 0xbc, 0xc8, 0x99, 0xeb, 0x9e, 0xf8, 0x1f,
+  0x6d, 0x17, 0x15, 0xd1, 0x45, 0x33, 0x47, 0x6b, 0xa5, 0x8e, 0x05, 0x5e,
+  0xb2, 0x48, 0xb9, 0x73, 0xf6, 0xf4, 0xed, 0xeb, 0xa9, 0x64, 0xda, 0x21,
+  0x99, 0xa9, 0x1e, 0xa4, 0x2d, 0x3c, 0x6f, 0x22, 0x2a, 0xe1, 0x7c, 0x98,
+  0x24, 0xe7, 0x73, 0xd7, 0x5c, 0x0a, 0x7a, 0x86, 0x6c, 0x78, 0x01, 0x54,
+  0x37, 0xd2, 0xdb, 0x9d, 0x37, 0x82, 0x8a, 0xb1, 0xaa, 0xda, 0xa6, 0xab,
+  0xce, 0xf5, 0x21, 0x71, 0xcc, 0xdb, 0x8d, 0xb6, 0x27, 0xd3, 0x6d, 0x17,
+  0x5b, 0x6f, 0x4a, 0x1a, 0x7f, 0x13, 0xe7, 0x04, 0x72, 0xe3, 0x3c, 0xaa,
+  0x3a, 0x9f, 0x4c, 0xea, 0x59, 0x36, 0x9d, 0x5d, 0xe4, 0x4f, 0xfd, 0x47,
+  0x72, 0xdc, 0x9c, 0x55, 0x4a, 0x08, 0xff, 0x00, 0xf7, 0x3a, 0xee, 0x38,
+  0x7c, 0x53, 0xfc, 0xb7, 0xc2, 0x1d, 0xf5, 0x45, 0xe3, 0x59, 0x6b, 0x2d,
+  0x9c, 0x75, 0x77, 0x31, 0x48, 0xd1, 0x78, 0xb5, 0xb2, 0xca, 0x31, 0xdf,
+  0xf9, 0x87, 0xae, 0xb4, 0x1f, 0x86, 0x73, 0x58, 0xef, 0xb4, 0xb1, 0xc1,
+  0x57, 0xc4, 0x0b, 0x41, 0x76, 0x79, 0x02, 0x88, 0x27, 0x4f, 0xe5, 0x48,
+  0x4f, 0x75, 0x61, 0xd3, 0xdc, 0x69, 0x0e, 0x67, 0x2a, 0x5f, 0x66, 0x7e,
+  0x14, 0x73, 0x0a, 0x59, 0x98, 0x48, 0x39, 0x55, 0x49, 0xe9, 0xe9, 0xa9,
+  0xb8, 0xae, 0x68, 0x9e, 0xa6, 0xc9, 0xc6, 0x74, 0xd1, 0x85, 0x51, 0xe1,
+  0xc7, 0x5d, 0x1a, 0x9f, 0xa6, 0x74, 0xc7, 0x98, 0xff, 0x00, 0xf2, 0x5c,
+  0x1f, 0xbe, 0x75, 0x71, 0xe2, 0x2b, 0x35, 0xae, 0xc9, 0x4a, 0xe9, 0x7d,
+  0xbe, 0x5b, 0xbc, 0xc4, 0x72, 0x42, 0x92, 0x12, 0xf2, 0x02, 0x73, 0xba,
+  0xf6, 0x00, 0x6f, 0xa6, 0x93, 0xd0, 0xda, 0x78, 0x87, 0x83, 0xe4, 0x82,
+  0xd6, 0x21, 0xac, 0xa7, 0x8a, 0x23, 0xe1, 0x98, 0xc4, 0x71, 0x22, 0xb8,
+  0x1f, 0x54, 0x80, 0x2e, 0x49, 0xc6, 0x76, 0x2c, 0x7a, 0xe9, 0x39, 0x73,
+  0x01, 0x1c, 0x65, 0xb7, 0xc7, 0xff, 0x00, 0xd4, 0xd6, 0xc9, 0x22, 0xa7,
+  0xac, 0x68, 0x7e, 0x66, 0x00, 0x66, 0xaa, 0x40, 0x1b, 0xc1, 0x8c, 0xa8,
+  0xdb, 0xdd, 0x88, 0x38, 0xc7, 0x6c, 0xeb, 0x0a, 0xab, 0x8e, 0xcb, 0x6b,
+  0xac, 0x5a, 0x6a, 0xd7, 0x94, 0x5b, 0xbc, 0x72, 0x82, 0x32, 0x33, 0x23,
+  0xc5, 0x92, 0x09, 0xfb, 0xe3, 0xf5, 0xd6, 0xd9, 0xf0, 0x92, 0xf1, 0x41,
+  0x07, 0x06, 0x51, 0x5b, 0xae, 0x6b, 0x19, 0x58, 0xd5, 0xd6, 0x39, 0x81,
+  0x00, 0x45, 0xe6, 0xda, 0x26, 0xdf, 0x63, 0xd3, 0xf6, 0xd7, 0x9c, 0x38,
+  0xe2, 0x29, 0x1f, 0x8a, 0xab, 0x40, 0x93, 0x31, 0x53, 0xca, 0x51, 0x30,
+  0x32, 0x00, 0xc9, 0xc7, 0xeb, 0xa9, 0x0c, 0x89, 0x26, 0x56, 0x55, 0x49,
+  0x17, 0x4f, 0xf6, 0x76, 0xa9, 0xe1, 0x2b, 0x37, 0x10, 0x5c, 0xd2, 0xed,
+  0x3b, 0xc1, 0x25, 0x50, 0x11, 0x5b, 0xeb, 0x25, 0x8f, 0x1c, 0x89, 0xcc,
+  0x4f, 0x9b, 0xfc, 0x3c, 0xde, 0x5f, 0xd3, 0x5b, 0x7f, 0xc5, 0xea, 0x0b,
+  0xc5, 0x75, 0xa2, 0x8d, 0xa1, 0x9a, 0x23, 0x43, 0x1c, 0x5c, 0xd3, 0x32,
+  0xb6, 0x39, 0x98, 0xf7, 0xc0, 0xeb, 0xdb, 0xf5, 0x3a, 0xf2, 0xb5, 0xba,
+  0x9d, 0x8b, 0x2b, 0x73, 0x64, 0x03, 0xe9, 0xad, 0xc3, 0xe1, 0x2f, 0x17,
+  0xf3, 0x52, 0x0e, 0x12, 0xe2, 0x33, 0x2c, 0x96, 0xc9, 0xd7, 0x92, 0x9e,
+  0x51, 0xd6, 0x1f, 0x40, 0x4f, 0x65, 0xfe, 0xda, 0x4e, 0x45, 0xf2, 0xc1,
+  0xc2, 0xe9, 0xb0, 0x23, 0x2d, 0xde, 0x26, 0x43, 0xf1, 0x67, 0x87, 0x6e,
+  0xf6, 0x8a, 0x5a, 0x4b, 0xbb, 0x40, 0xcd, 0x47, 0x55, 0xcc, 0x91, 0xcc,
+  0x01, 0x00, 0x15, 0xeb, 0xf8, 0x3d, 0x8f, 0xb6, 0xb2, 0xca, 0x6a, 0xaa,
+  0xba, 0x5a, 0xd4, 0x96, 0x98, 0x81, 0x39, 0x6e, 0x50, 0x18, 0x64, 0x6f,
+  0xd8, 0xeb, 0xd8, 0x9f, 0x18, 0x78, 0xae, 0xd5, 0x61, 0xe1, 0x8a, 0xae,
+  0x10, 0xb4, 0x53, 0xbd, 0xc9, 0xaa, 0x23, 0x30, 0xca, 0x66, 0x97, 0xc4,
+  0x8a, 0x9d, 0x71, 0xdb, 0x3d, 0x4f, 0xdb, 0xa6, 0xbc, 0xad, 0x5d, 0x6f,
+  0x14, 0x37, 0x6a, 0x7a, 0xb4, 0x84, 0xb4, 0x62, 0x45, 0xfa, 0x17, 0x70,
+  0x33, 0xbe, 0x33, 0xd3, 0x6d, 0xb3, 0xab, 0xc1, 0x1f, 0x86, 0x3b, 0x3b,
+  0x18, 0xa9, 0x70, 0x99, 0x15, 0x4a, 0xdc, 0xeb, 0xe3, 0x3f, 0x35, 0x31,
+  0x65, 0x8f, 0x01, 0xe3, 0x4d, 0x82, 0x92, 0x36, 0xc8, 0x1b, 0x1f, 0xbe,
+  0xa3, 0xb1, 0xdc, 0x2a, 0xec, 0xb5, 0x6e, 0x20, 0x45, 0x31, 0x33, 0xf2,
+  0xba, 0x30, 0xce, 0x47, 0xb7, 0xa1, 0xd5, 0xbe, 0xed, 0x34, 0x4d, 0x0c,
+  0xc2, 0xc8, 0x8f, 0x15, 0x1d, 0x75, 0x51, 0x73, 0x14, 0x92, 0x66, 0x4c,
+  0x2e, 0x71, 0xcd, 0x8e, 0xb8, 0xc9, 0xfd, 0x74, 0x04, 0x96, 0x3f, 0x98,
+  0x77, 0xa9, 0xf0, 0x01, 0x25, 0x4e, 0xd9, 0xc6, 0x0f, 0x63, 0xf8, 0xd1,
+  0x42, 0x7b, 0xc0, 0x0e, 0xb9, 0xc1, 0x69, 0xaf, 0xb2, 0x81, 0x1d, 0x44,
+  0xf2, 0xd4, 0x56, 0xb8, 0x58, 0xa9, 0x23, 0x3b, 0xbb, 0x06, 0x53, 0xe7,
+  0x19, 0xfa, 0x71, 0x90, 0x3b, 0x93, 0xa4, 0x2b, 0x43, 0x27, 0x81, 0x2b,
+  0x0a, 0x69, 0x72, 0xaf, 0xca, 0x06, 0x31, 0xca, 0x07, 0xb6, 0x87, 0xb8,
+  0x97, 0xb7, 0x54, 0xc2, 0x82, 0x36, 0x47, 0x4c, 0x32, 0x48, 0x1b, 0xa7,
+  0xb6, 0x86, 0x86, 0xf3, 0x51, 0x51, 0xf3, 0x11, 0xbd, 0x43, 0x72, 0x8d,
+  0x95, 0xc0, 0xdd, 0x40, 0x3d, 0x3f, 0x52, 0x4e, 0x99, 0x6d, 0x34, 0xd0,
+  0xf4, 0x1f, 0x0d, 0x10, 0x5a, 0xca, 0x66, 0x58, 0xe5, 0x91, 0xe6, 0x19,
+  0x20, 0x8c, 0x12, 0xdf, 0xe1, 0xd3, 0x26, 0x06, 0x82, 0x14, 0x05, 0xea,
+  0x21, 0x46, 0x56, 0x95, 0x49, 0x18, 0x0c, 0x79, 0xba, 0x63, 0xd4, 0x74,
+  0xce, 0xb9, 0x17, 0x28, 0xe3, 0x6b, 0x05, 0x7c, 0x2b, 0x22, 0x8a, 0x79,
+  0xd0, 0x33, 0x81, 0x9c, 0x90, 0x77, 0xc0, 0xfd, 0xf5, 0xcd, 0xd6, 0x6a,
+  0xba, 0xde, 0x23, 0x9e, 0x59, 0x9e, 0x59, 0x92, 0x56, 0x56, 0x0c, 0x5b,
+  0x97, 0x62, 0x7b, 0x0e, 0xcb, 0xd7, 0x6d, 0xf5, 0xad, 0x1b, 0xd7, 0x41,
+  0x46, 0xe3, 0x3d, 0xc5, 0x2a, 0x6a, 0xe0, 0x5e, 0x77, 0x1c, 0xb2, 0xca,
+  0x59, 0x32, 0x4e, 0x36, 0xce, 0x74, 0x44, 0xd7, 0x2a, 0x4a, 0xea, 0x54,
+  0x47, 0x46, 0x8d, 0xda, 0x50, 0xae, 0x0f, 0x63, 0x82, 0x03, 0x67, 0xdb,
+  0xa7, 0xe7, 0x42, 0x4d, 0x44, 0xf6, 0x8b, 0xdd, 0x54, 0x0a, 0xf9, 0x8b,
+  0x67, 0x60, 0x1b, 0x2c, 0xc0, 0x8c, 0x93, 0xf6, 0xce, 0x8d, 0xad, 0xa6,
+  0x48, 0xec, 0xc2, 0xe3, 0x84, 0x53, 0x59, 0xe1, 0x99, 0x90, 0x27, 0x51,
+  0xb9, 0x04, 0x1f, 0x7e, 0xbf, 0xa6, 0xad, 0x8d, 0x88, 0x1c, 0x7f, 0x3d,
+  0x6f, 0x86, 0x52, 0xcb, 0xe2, 0x50, 0xc3, 0x28, 0x8c, 0xf7, 0x00, 0xee,
+  0x0e, 0x3d, 0xb4, 0x59, 0xb3, 0xd1, 0x54, 0x5b, 0xeb, 0x83, 0x9f, 0x0a,
+  0x47, 0x0d, 0x35, 0x39, 0x4e, 0x85, 0x15, 0x73, 0xfb, 0xe4, 0x6d, 0xdb,
+  0x50, 0x99, 0x69, 0xc7, 0x0b, 0xc9, 0x42, 0x81, 0x85, 0x43, 0x4c, 0x5d,
+  0x49, 0x5c, 0x2b, 0x63, 0x27, 0x19, 0xfc, 0x68, 0x6a, 0x99, 0x5a, 0x0b,
+  0x13, 0xb8, 0x95, 0xa3, 0x2e, 0xc5, 0x02, 0x11, 0xb9, 0xce, 0xfb, 0xfb,
+  0x74, 0xd5, 0x14, 0xc0, 0xe3, 0xb9, 0xd5, 0xc5, 0x6e, 0x4b, 0x6d, 0x42,
+  0xab, 0xa3, 0x60, 0x29, 0xe6, 0xdd, 0x37, 0xc6, 0x3e, 0xda, 0x8f, 0x8c,
+  0x56, 0x3b, 0x8f, 0xc9, 0xdb, 0xa0, 0x58, 0xd6, 0x4a, 0x28, 0x39, 0x07,
+  0x20, 0xd8, 0x9e, 0x62, 0x4f, 0xf7, 0xd4, 0x34, 0xf4, 0x6f, 0x2d, 0x39,
+  0x33, 0xcb, 0x1e, 0x14, 0xf5, 0xcf, 0x51, 0xe9, 0xa6, 0x86, 0x9e, 0x81,
+  0x29, 0x21, 0x34, 0xec, 0xef, 0x50, 0xc4, 0xbc, 0xac, 0x63, 0xc0, 0x51,
+  0xdb, 0x07, 0xf3, 0xf9, 0xeb, 0xa8, 0x51, 0x4b, 0xa4, 0xb5, 0x4a, 0x6b,
+  0x42, 0x54, 0xc6, 0x42, 0xab, 0x63, 0xa6, 0xdf, 0x73, 0xad, 0xcf, 0xfd,
+  0x9c, 0x78, 0x5e, 0xe2, 0x9c, 0x71, 0x15, 0xf6, 0x68, 0xa4, 0xa5, 0xb4,
+  0xd2, 0x42, 0xd2, 0x0a, 0x99, 0x94, 0xac, 0x4e, 0xdf, 0x48, 0x0a, 0xdd,
+  0x3b, 0xea, 0x8c, 0x23, 0xa7, 0x0a, 0x24, 0xa7, 0x9b, 0x2f, 0xc9, 0x86,
+  0x2d, 0xd3, 0x71, 0xd3, 0x1d, 0xf5, 0x74, 0xa1, 0xe2, 0xba, 0xcb, 0x85,
+  0xa2, 0x92, 0xd1, 0x79, 0xb8, 0x56, 0xad, 0x14, 0x51, 0x24, 0x74, 0xd4,
+  0x54, 0x31, 0x15, 0x32, 0x80, 0x4e, 0x32, 0x07, 0xdb, 0x54, 0x9d, 0x3b,
+  0x15, 0x2c, 0x3c, 0xa7, 0x66, 0xf5, 0x5d, 0xf1, 0x17, 0x84, 0x23, 0x8e,
+  0x68, 0x92, 0xff, 0x00, 0x4b, 0x2c, 0xe1, 0x8a, 0xb3, 0xae, 0x48, 0x03,
+  0xa7, 0x5c, 0x6b, 0xcd, 0x5f, 0x10, 0x6b, 0xc7, 0x17, 0x71, 0x8d, 0x4d,
+  0xe6, 0xb6, 0xae, 0xa7, 0xe4, 0xd4, 0xf8, 0x54, 0xb0, 0xa4, 0x79, 0x61,
+  0x1a, 0xf4, 0x3c, 0xc7, 0xa6, 0x7a, 0x9d, 0xba, 0x9d, 0x1a, 0xd5, 0x09,
+  0x6e, 0x4a, 0x8a, 0x5a, 0x6b, 0x4d, 0x22, 0x38, 0x25, 0xdc, 0xcf, 0x2f,
+  0x8b, 0x3f, 0x2e, 0x46, 0x32, 0x01, 0x21, 0x49, 0x24, 0x6d, 0xd7, 0x42,
+  0xd6, 0x53, 0x5e, 0x26, 0xa5, 0x7a, 0xca, 0xdb, 0x7c, 0xb1, 0x53, 0xe3,
+  0x0c, 0x4c, 0x61, 0x47, 0xdc, 0x6f, 0x8c, 0x7b, 0xef, 0xa6, 0xfc, 0x96,
+  0x5e, 0xd5, 0xec, 0x57, 0x15, 0x1c, 0x6e, 0x23, 0x5a, 0x48, 0x59, 0x56,
+  0x32, 0x70, 0xe5, 0xcb, 0x36, 0xe7, 0x39, 0xcf, 0x41, 0xfa, 0x69, 0x84,
+  0x9e, 0x1d, 0x08, 0x8e, 0x55, 0x81, 0x2a, 0xaa, 0x58, 0x79, 0xbc, 0x61,
+  0xcc, 0x07, 0xb8, 0xf5, 0x3a, 0x12, 0x2a, 0x84, 0x83, 0x95, 0x22, 0x2e,
+  0xc3, 0x2a, 0x63, 0x50, 0xd9, 0x18, 0xf7, 0x3d, 0xfe, 0xda, 0x6a, 0xb5,
+  0x55, 0xb7, 0x26, 0x94, 0xc7, 0x4b, 0x09, 0x90, 0x10, 0xa1, 0xd9, 0xb9,
+  0x79, 0x33, 0xd7, 0x1b, 0x7b, 0x01, 0xbe, 0x97, 0x63, 0x94, 0x52, 0x5c,
+  0x10, 0xd4, 0xf1, 0x15, 0x74, 0xb4, 0x9f, 0x2f, 0x23, 0xc1, 0x2b, 0x10,
+  0x10, 0x46, 0xb4, 0xa8, 0x7c, 0x31, 0xe8, 0xa4, 0xf4, 0x23, 0xd8, 0x7e,
+  0x75, 0x02, 0xd5, 0x5c, 0x82, 0xab, 0x43, 0x4a, 0x54, 0x85, 0x11, 0x86,
+  0x38, 0xe7, 0xc6, 0xfb, 0x91, 0xd0, 0x69, 0xa9, 0xb4, 0xdd, 0xa6, 0x3c,
+  0x83, 0xe5, 0xa0, 0xdf, 0xeb, 0x50, 0x0b, 0x63, 0xee, 0x37, 0xfe, 0xda,
+  0x51, 0x71, 0xa4, 0xab, 0xb7, 0xd4, 0x34, 0x2d, 0x56, 0x80, 0x48, 0x0e,
+  0xc4, 0xe1, 0x8e, 0x0e, 0x33, 0xef, 0xa9, 0xb8, 0xbd, 0xa7, 0xc8, 0x94,
+  0x3d, 0x68, 0x92, 0xbd, 0x3c, 0x55, 0x1f, 0x53, 0x09, 0x80, 0xfc, 0x68,
+  0xf4, 0x64, 0xaf, 0xa9, 0x86, 0x8a, 0x3b, 0x7a, 0x7c, 0x9c, 0x32, 0x9f,
+  0xe6, 0xbb, 0xf9, 0x00, 0xf5, 0x3b, 0x6f, 0xa5, 0x96, 0xe9, 0x2d, 0xd4,
+  0x71, 0xbd, 0x40, 0xff, 0x00, 0x7b, 0xb8, 0x33, 0x93, 0xc9, 0x92, 0xa1,
+  0x17, 0xa7, 0x5f, 0x7e, 0xa7, 0x5d, 0xd4, 0xd5, 0x5d, 0xa6, 0x6f, 0x91,
+  0x79, 0x82, 0xc1, 0x27, 0xd0, 0x22, 0xd9, 0x70, 0x7a, 0x0f, 0x7e, 0xd8,
+  0xd5, 0xa6, 0x53, 0x1b, 0xcd, 0x6f, 0xa1, 0x7a, 0xf6, 0x89, 0x78, 0x86,
+  0x08, 0x5a, 0x43, 0xcb, 0x1c, 0x14, 0xf1, 0xb0, 0x0e, 0x07, 0x60, 0xc7,
+  0x63, 0xf7, 0xd3, 0x9f, 0xfe, 0xdb, 0xa4, 0xa3, 0x4a, 0x6a, 0x88, 0xa9,
+  0x58, 0x46, 0x08, 0x9a, 0x77, 0x4f, 0x1a, 0x5e, 0x7c, 0x6d, 0xd3, 0x03,
+  0x3d, 0x4f, 0xa6, 0xab, 0xed, 0xc3, 0x91, 0xc3, 0x68, 0x89, 0x9a, 0xf4,
+  0xb1, 0xcc, 0xe4, 0xad, 0x44, 0x0f, 0x10, 0x0f, 0x18, 0x1d, 0x40, 0x6c,
+  0xe7, 0xa8, 0x1b, 0x69, 0x6a, 0xc7, 0x13, 0xd6, 0xc4, 0x94, 0x95, 0x2d,
+  0x38, 0x62, 0x39, 0xde, 0x52, 0x70, 0x49, 0xdb, 0x97, 0xdf, 0xae, 0x7f,
+  0x1a, 0x8c, 0x0d, 0xca, 0x5c, 0x23, 0xf5, 0x7a, 0xdb, 0xa4, 0x99, 0x12,
+  0xc5, 0x43, 0x54, 0x22, 0x4d, 0xe4, 0x92, 0xa0, 0x87, 0x27, 0xdc, 0x0e,
+  0xdf, 0xae, 0xbe, 0x8a, 0x17, 0x99, 0x15, 0x8b, 0xc8, 0x0e, 0x76, 0x04,
+  0xe3, 0x95, 0x7e, 0xda, 0xb3, 0xf1, 0x4d, 0xae, 0xa6, 0x82, 0x9a, 0x2a,
+  0xba, 0xca, 0xec, 0xf3, 0x80, 0x84, 0x41, 0x1e, 0x31, 0xb6, 0xc0, 0x00,
+  0x71, 0x9c, 0x7f, 0xe7, 0x55, 0xa1, 0x08, 0x5a, 0x49, 0xa6, 0xa9, 0x96,
+  0x72, 0xae, 0xdc, 0xaa, 0x07, 0x5d, 0x4a, 0x19, 0x1a, 0x6a, 0xd3, 0x23,
+  0x32, 0xa5, 0x14, 0x73, 0x27, 0x2b, 0xb8, 0xc9, 0xc3, 0x02, 0x00, 0xce,
+  0x7d, 0x3a, 0xeb, 0xbb, 0x3d, 0xda, 0x92, 0x9d, 0xd6, 0x69, 0x29, 0x9e,
+  0x49, 0x54, 0xe4, 0x3e, 0x3c, 0xa4, 0xff, 0x00, 0x96, 0xa2, 0xb6, 0xa2,
+  0xf8, 0xc9, 0xe3, 0xc7, 0x2f, 0x80, 0xc7, 0xc3, 0xe7, 0xe5, 0xcf, 0xeb,
+  0xef, 0x8c, 0x68, 0xda, 0xa8, 0xa8, 0xad, 0x95, 0x58, 0xc0, 0x9e, 0x9d,
+  0x9b, 0x20, 0x78, 0x7e, 0x61, 0xe9, 0x9d, 0xf6, 0x07, 0x54, 0x59, 0x35,
+  0x5d, 0xee, 0x79, 0x99, 0xdd, 0x22, 0x8e, 0x25, 0x29, 0x85, 0x63, 0xb1,
+  0xfc, 0x7e, 0x34, 0xbd, 0xb3, 0x57, 0x34, 0x6c, 0xae, 0x65, 0x6c, 0x81,
+  0x1a, 0x83, 0x90, 0x0f, 0xb9, 0xd1, 0x97, 0x1a, 0xb7, 0xac, 0x40, 0xb1,
+  0x43, 0xf2, 0x94, 0xea, 0x02, 0xf2, 0x2e, 0x09, 0x62, 0x3b, 0xe9, 0x32,
+  0x99, 0x21, 0x12, 0x34, 0x52, 0x14, 0x05, 0xb1, 0x19, 0x23, 0x72, 0xde,
+  0xc3, 0x50, 0x84, 0x7f, 0x10, 0xb8, 0x6b, 0x88, 0xc5, 0xfa, 0xe3, 0x79,
+  0x9e, 0xd9, 0x33, 0x50, 0xcb, 0x57, 0x37, 0x85, 0x2a, 0xee, 0x39, 0x3c,
+  0x56, 0x03, 0x3e, 0x9d, 0x07, 0xeb, 0xa1, 0x28, 0xac, 0xf3, 0xd2, 0xd2,
+  0xbd, 0x6d, 0x43, 0x72, 0x3c, 0x60, 0x15, 0x41, 0xd5, 0x75, 0x78, 0xe3,
+  0x7e, 0x27, 0xa5, 0x96, 0xef, 0x3d, 0xb7, 0xe6, 0x5c, 0xc7, 0x4b, 0x33,
+  0xaf, 0x86, 0x7f, 0xc6, 0x18, 0xe4, 0x9e, 0xdd, 0x49, 0xc7, 0xb6, 0xaa,
+  0x35, 0x57, 0x17, 0xaa, 0x2d, 0x00, 0x3c, 0xa8, 0x73, 0xef, 0x9d, 0xf5,
+  0x9b, 0x04, 0x25, 0xb5, 0xca, 0x7d, 0xff, 0x00, 0xe1, 0xc5, 0x97, 0xd9,
+  0x84, 0x47, 0x55, 0x25, 0x6d, 0x74, 0x75, 0x15, 0xb3, 0xbc, 0xc4, 0xb6,
+  0x4b, 0x39, 0xe6, 0x00, 0xfa, 0x9c, 0x9d, 0xc6, 0xfa, 0xb5, 0x9e, 0x24,
+  0xa7, 0xa5, 0xb3, 0xd3, 0xd9, 0xa9, 0xee, 0x0c, 0x20, 0x4c, 0xf3, 0x00,
+  0xa5, 0x4b, 0x39, 0xdc, 0x9f, 0x5c, 0x7f, 0xdf, 0xde, 0x91, 0x12, 0x08,
+  0x21, 0x67, 0x5f, 0xab, 0x1b, 0x6b, 0xed, 0x0a, 0x78, 0x93, 0x89, 0x64,
+  0xcb, 0x04, 0x39, 0xfc, 0xe8, 0x26, 0xf9, 0x48, 0x56, 0xf2, 0xfb, 0x6f,
+  0xba, 0x34, 0x96, 0xba, 0xab, 0x74, 0x52, 0x7f, 0xba, 0xcb, 0xcb, 0xe2,
+  0x12, 0x30, 0x3a, 0x74, 0xc6, 0xab, 0xb7, 0x68, 0xe3, 0xa7, 0xa9, 0x54,
+  0x8c, 0x89, 0x09, 0x1e, 0x66, 0x1b, 0x83, 0xed, 0x9d, 0x29, 0xaf, 0xaf,
+  0xa9, 0xa6, 0x63, 0x0d, 0x31, 0x68, 0xfc, 0x4e, 0x56, 0x66, 0x56, 0xec,
+  0x07, 0x4f, 0xdf, 0x52, 0x5a, 0xe7, 0x79, 0xa2, 0x78, 0x66, 0x60, 0xce,
+  0x4f, 0x30, 0x63, 0xd7, 0x55, 0x54, 0x54, 0xa7, 0xb8, 0xd4, 0xfe, 0x11,
+  0x58, 0x7e, 0x1f, 0xde, 0xea, 0x61, 0xa1, 0xbd, 0x5e, 0xea, 0xa9, 0xeb,
+  0xa5, 0xd9, 0x69, 0x5c, 0x08, 0xe3, 0x90, 0xfa, 0x09, 0x0e, 0x72, 0x7a,
+  0xed, 0xb6, 0xb7, 0xe8, 0x61, 0xe1, 0x1e, 0x07, 0xa2, 0x4a, 0x5a, 0x5a,
+  0x40, 0x8e, 0xc9, 0xff, 0x00, 0x06, 0x18, 0x8c, 0x92, 0x32, 0xe3, 0xa9,
+  0xf6, 0xdb, 0xae, 0xc3, 0x5e, 0x53, 0xe1, 0xb8, 0x6d, 0xf5, 0x93, 0x1a,
+  0x5a, 0xe8, 0x99, 0x9e, 0x48, 0xf9, 0x29, 0x9c, 0x3f, 0x2f, 0x85, 0x36,
+  0x57, 0x95, 0x89, 0xf4, 0xeb, 0xfa, 0xea, 0xdd, 0x74, 0xbc, 0xf1, 0x6f,
+  0x0d, 0xd3, 0x1b, 0x55, 0xce, 0xb2, 0x3b, 0x8d, 0x1b, 0x1e, 0x69, 0x8a,
+  0x8c, 0xcf, 0x32, 0x67, 0xe9, 0x62, 0x7c, 0xc5, 0x7b, 0x63, 0xa6, 0xda,
+  0x09, 0x6a, 0x31, 0xc7, 0xc2, 0xbc, 0xbd, 0x0d, 0xc7, 0x38, 0xae, 0x97,
+  0x27, 0xcf, 0x88, 0xb7, 0x3b, 0x75, 0xf6, 0xf7, 0x57, 0x58, 0x69, 0x44,
+  0x6a, 0x1d, 0xbc, 0x1f, 0x02, 0x35, 0x50, 0x17, 0x3b, 0x1d, 0xba, 0x93,
+  0xea, 0x73, 0xac, 0xca, 0xba, 0x81, 0x64, 0xad, 0x32, 0x46, 0x8c, 0xa3,
+  0xb3, 0x36, 0x0b, 0x63, 0xf4, 0xd5, 0xba, 0xf4, 0xa5, 0x78, 0x4a, 0xb3,
+  0x8a, 0x6d, 0x55, 0x54, 0xd1, 0x50, 0xd1, 0xf2, 0xc2, 0x20, 0x95, 0xb9,
+  0x5a, 0x49, 0x5b, 0xfe, 0x5e, 0xe7, 0x19, 0x39, 0xed, 0xac, 0xee, 0xd5,
+  0x7e, 0x45, 0x41, 0x1d, 0x67, 0x36, 0x32, 0xcd, 0xe2, 0x01, 0x96, 0xc9,
+  0xdf, 0x41, 0x8d, 0x39, 0x2b, 0x6a, 0x85, 0xbb, 0xbe, 0x06, 0x41, 0x15,
+  0x67, 0xf9, 0x79, 0x23, 0x0a, 0x08, 0xf2, 0x30, 0x3e, 0x9d, 0x06, 0x34,
+  0x44, 0xf1, 0xd5, 0xd2, 0x53, 0xac, 0xeb, 0x87, 0x8f, 0x62, 0x79, 0x86,
+  0x70, 0x34, 0x9f, 0x88, 0xea, 0x64, 0xa8, 0xb3, 0xd1, 0x55, 0x40, 0xad,
+  0x03, 0x34, 0x87, 0xae, 0xe4, 0xe3, 0x38, 0x3a, 0x0e, 0xa7, 0x88, 0x2e,
+  0x15, 0x36, 0x7a, 0x9a, 0x17, 0x3e, 0x27, 0x88, 0x98, 0x04, 0x1c, 0x15,
+  0xdc, 0x69, 0x98, 0xbe, 0xa0, 0x9c, 0xf1, 0x0d, 0x6c, 0xf5, 0xfc, 0xa2,
+  0x6a, 0x78, 0x51, 0xe2, 0x61, 0x1a, 0xf2, 0xb7, 0x98, 0x83, 0xed, 0x8e,
+  0x83, 0x5d, 0x0b, 0x39, 0xb7, 0x52, 0x0a, 0xcb, 0x8c, 0x4b, 0xe0, 0xcb,
+  0x1f, 0x89, 0x4e, 0x76, 0xfe, 0x68, 0xe6, 0x23, 0xd7, 0x6d, 0xd7, 0x40,
+  0xd8, 0xa9, 0xda, 0xa8, 0xb3, 0xcf, 0x0c, 0xb2, 0x78, 0x23, 0x9c, 0x0e,
+  0xc0, 0x02, 0x3a, 0xfa, 0x8d, 0x38, 0xbd, 0xdf, 0xe9, 0xae, 0xf5, 0x15,
+  0x8f, 0x53, 0x48, 0xb1, 0xca, 0x89, 0x1a, 0x52, 0xa4, 0x28, 0x23, 0x48,
+  0x54, 0x64, 0x9d, 0x80, 0xef, 0x9d, 0x0b, 0x1b, 0x16, 0x70, 0xe5, 0xea,
+  0xa8, 0xe3, 0x01, 0x7f, 0x9a, 0xaf, 0xcc, 0xb1, 0xa0, 0xf2, 0xa2, 0x67,
+  0x6f, 0xce, 0x8a, 0xbd, 0xcf, 0x34, 0xa9, 0x29, 0x41, 0xe6, 0x88, 0x22,
+  0xb1, 0x07, 0x21, 0x98, 0x64, 0x93, 0x9f, 0x5d, 0xfa, 0x68, 0x5e, 0x1f,
+  0xaa, 0x92, 0x92, 0xb6, 0x1a, 0x93, 0x1a, 0xb7, 0x33, 0x96, 0x90, 0x11,
+  0x9f, 0x21, 0xdb, 0xfe, 0xbf, 0x8d, 0x17, 0xcf, 0x51, 0x6f, 0xaf, 0xad,
+  0xa5, 0x0d, 0x84, 0x9c, 0x73, 0x00, 0x06, 0xc4, 0x7a, 0x6b, 0x5e, 0x17,
+  0xc5, 0x1d, 0x0c, 0x0f, 0xc4, 0x0e, 0xa6, 0x71, 0x55, 0x08, 0xb8, 0x4c,
+  0xed, 0x14, 0xed, 0x20, 0x56, 0x3d, 0x79, 0x90, 0x83, 0xab, 0x2f, 0x11,
+  0xc1, 0x3b, 0xdb, 0x66, 0x96, 0x01, 0x27, 0x82, 0xaa, 0xa5, 0x14, 0x8d,
+  0x89, 0x39, 0x00, 0x0f, 0xb0, 0x1f, 0xf7, 0x9d, 0x27, 0xe1, 0xca, 0x58,
+  0xee, 0x54, 0xb2, 0x41, 0x24, 0x2a, 0x0f, 0x3e, 0xd2, 0x16, 0xc9, 0x4f,
+  0xc6, 0x37, 0x18, 0xed, 0xab, 0x2c, 0x17, 0x1f, 0xfe, 0xcf, 0xa5, 0xb5,
+  0x55, 0x4f, 0x2d, 0x3c, 0xd2, 0x86, 0x85, 0x5e, 0x55, 0x3c, 0xb8, 0x2e,
+  0x00, 0xc7, 0x63, 0x91, 0x9e, 0xfd, 0x34, 0xfb, 0x34, 0xd8, 0x05, 0x1c,
+  0x36, 0xf8, 0xf8, 0x6e, 0x9a, 0xe3, 0x53, 0x0b, 0xa4, 0x10, 0xa3, 0x23,
+  0xc6, 0xad, 0xe6, 0x79, 0x5b, 0xa3, 0x7d, 0x8e, 0x3f, 0x1a, 0xab, 0x57,
+  0x61, 0xa0, 0xa7, 0x91, 0x69, 0x5a, 0x28, 0x08, 0x28, 0x27, 0xee, 0xec,
+  0x7f, 0xc4, 0x3f, 0x1a, 0x3e, 0xe8, 0x93, 0x50, 0x73, 0x5a, 0x56, 0xa1,
+  0xa5, 0x32, 0xb1, 0xf0, 0xd4, 0x21, 0xfa, 0x81, 0x20, 0x6a, 0x4a, 0x09,
+  0x29, 0xa5, 0xa5, 0x4a, 0x4a, 0x98, 0x2a, 0x24, 0xa9, 0x84, 0x37, 0xf2,
+  0x08, 0xf2, 0x87, 0x3b, 0x02, 0x7e, 0xc7, 0x54, 0x53, 0x64, 0x34, 0x86,
+  0x96, 0x8a, 0x92, 0x25, 0x8e, 0x15, 0x96, 0xac, 0x64, 0x3f, 0x8a, 0xbc,
+  0xd1, 0xae, 0xe3, 0x18, 0x19, 0xd3, 0x99, 0xa9, 0x1a, 0xa6, 0x64, 0xe7,
+  0x67, 0x92, 0x56, 0x40, 0x5c, 0x2a, 0xe0, 0x2e, 0x71, 0xb8, 0x00, 0xe3,
+  0x1e, 0xda, 0x16, 0x8a, 0xd1, 0x5b, 0x82, 0x23, 0xa6, 0x25, 0x64, 0xf2,
+  0x80, 0x1f, 0x20, 0x37, 0x5d, 0xce, 0x3a, 0xf4, 0xd8, 0xfa, 0x8d, 0x39,
+  0xa1, 0x57, 0xb7, 0xd4, 0xcf, 0x6f, 0xb8, 0x49, 0x1c, 0x50, 0x48, 0x8a,
+  0xf2, 0x2a, 0x37, 0x3c, 0xc7, 0xa7, 0xd2, 0xc3, 0xf7, 0x1a, 0x84, 0x21,
+  0xf0, 0xe8, 0x28, 0x5a, 0x28, 0xe1, 0x57, 0xab, 0xa9, 0x23, 0x99, 0x93,
+  0xa9, 0x18, 0xf5, 0x5e, 0xc3, 0xdb, 0xf4, 0xd4, 0xc6, 0xba, 0xfc, 0x94,
+  0xd3, 0x2b, 0x62, 0x86, 0x0a, 0x8c, 0x16, 0x64, 0x02, 0x36, 0xe5, 0xec,
+  0x32, 0x4e, 0xc3, 0xa6, 0xa1, 0xae, 0xac, 0xa5, 0x9f, 0xc2, 0x86, 0xd3,
+  0x6e, 0x65, 0x98, 0xcc, 0x79, 0xa6, 0x7e, 0xac, 0x4e, 0x7c, 0xbf, 0x60,
+  0x75, 0xc3, 0xfc, 0xb0, 0x0f, 0x05, 0x64, 0x4e, 0xd2, 0xb1, 0xda, 0x79,
+  0xc9, 0xc0, 0x1d, 0x49, 0x41, 0x8d, 0x87, 0xbe, 0xff, 0x00, 0x6d, 0x42,
+  0x06, 0x43, 0x7d, 0x96, 0x1b, 0x7c, 0x34, 0x56, 0x89, 0x33, 0x51, 0x51,
+  0xe7, 0xa8, 0x91, 0xa3, 0x0c, 0xfc, 0xc7, 0x6e, 0x6c, 0x9e, 0xfe, 0xfa,
+  0xee, 0x9a, 0xcb, 0x78, 0xa9, 0x55, 0x96, 0xae, 0x59, 0xa5, 0x8a, 0x12,
+  0x58, 0x78, 0x8d, 0xce, 0x71, 0xdf, 0xca, 0x3a, 0x01, 0xd3, 0x3f, 0xf6,
+  0x07, 0x96, 0x4a, 0x68, 0x22, 0x89, 0x6d, 0xe8, 0xaa, 0xe8, 0x7c, 0x4f,
+  0x1b, 0x9b, 0x97, 0x94, 0xf5, 0xdc, 0xe3, 0xd3, 0x42, 0x52, 0x56, 0x56,
+  0x55, 0x21, 0xa7, 0x8e, 0xad, 0x99, 0x64, 0x62, 0xcf, 0x32, 0x13, 0xcc,
+  0xfb, 0xf4, 0x3a, 0x84, 0x0c, 0xb8, 0x5c, 0xa8, 0x29, 0xa3, 0xf9, 0x6b,
+  0x4c, 0x4a, 0x24, 0x66, 0x21, 0xe4, 0x45, 0x05, 0xc7, 0xb0, 0x6f, 0x5f,
+  0x7f, 0xf5, 0xd7, 0x16, 0x64, 0xba, 0xb2, 0xd4, 0xd4, 0xd2, 0x52, 0xc7,
+  0x14, 0x4a, 0xc3, 0x9e, 0x57, 0x39, 0x20, 0xe3, 0xbf, 0xa9, 0xd7, 0x5f,
+  0x25, 0x49, 0x41, 0x28, 0x2c, 0x7c, 0x59, 0x0a, 0x61, 0x41, 0x18, 0x20,
+  0xed, 0xdf, 0x46, 0x56, 0xd5, 0xc5, 0xf2, 0x06, 0x0e, 0x52, 0xaf, 0x26,
+  0x19, 0xa2, 0x41, 0x85, 0x51, 0x8e, 0xff, 0x00, 0xe2, 0x3a, 0x11, 0x88,
+  0xe9, 0x2e, 0xd5, 0xe9, 0x13, 0x52, 0xc7, 0x13, 0x47, 0x33, 0xc9, 0xca,
+  0xae, 0xd8, 0x5e, 0x61, 0xdf, 0x18, 0x1f, 0x4e, 0x81, 0xab, 0xa4, 0xa3,
+  0x42, 0xc6, 0xa2, 0xbd, 0xa5, 0x99, 0x62, 0xe7, 0x96, 0x45, 0xcb, 0x1e,
+  0x6f, 0xf0, 0x80, 0x3b, 0x60, 0xe7, 0x5c, 0x56, 0xbd, 0x24, 0x94, 0xca,
+  0xa7, 0x94, 0x33, 0x1c, 0xe0, 0x1f, 0x30, 0xcf, 0xb6, 0x8c, 0xb3, 0xdd,
+  0xa1, 0xa4, 0x33, 0x53, 0x45, 0x4b, 0x1c, 0x6d, 0x24, 0x65, 0x10, 0xc9,
+  0x0a, 0xb3, 0x1e, 0x98, 0xcb, 0x7d, 0x86, 0xa0, 0x14, 0xe3, 0xd0, 0xb6,
+  0xc7, 0x1c, 0x32, 0xe5, 0xa3, 0xa7, 0x32, 0x7f, 0x49, 0x69, 0x54, 0xe4,
+  0x82, 0x3d, 0xff, 0x00, 0xb6, 0x98, 0x57, 0xd1, 0x59, 0xa3, 0xaa, 0x5a,
+  0x8a, 0xda, 0xb9, 0xe4, 0x99, 0xf7, 0xf0, 0x55, 0x42, 0x82, 0x70, 0x70,
+  0x07, 0xa0, 0x1a, 0x81, 0x6b, 0x40, 0xcb, 0xab, 0xc6, 0xc0, 0xae, 0x15,
+  0x91, 0x76, 0x07, 0xbf, 0xe9, 0xa5, 0xeb, 0x53, 0x11, 0xaa, 0x0b, 0x31,
+  0x90, 0xb6, 0x7a, 0x7f, 0x4b, 0x1f, 0x5c, 0xff, 0x00, 0x96, 0xad, 0x12,
+  0xac, 0xb4, 0x70, 0xf5, 0xb2, 0x8e, 0xf5, 0x6a, 0x9e, 0x05, 0x34, 0x94,
+  0x45, 0x50, 0xc9, 0x3c, 0x93, 0xe5, 0xe4, 0x75, 0x04, 0x74, 0x03, 0xd0,
+  0x67, 0xef, 0x8d, 0x09, 0x53, 0x6a, 0xa3, 0xa5, 0x74, 0x9e, 0x82, 0xe6,
+  0x67, 0x90, 0x02, 0xdc, 0xc0, 0x05, 0x0b, 0xbf, 0xeb, 0x9f, 0x6e, 0xdb,
+  0xf5, 0xd2, 0xf9, 0xa5, 0x2d, 0x4d, 0x24, 0x91, 0x88, 0x96, 0x25, 0x6c,
+  0x66, 0x3f, 0xbe, 0x8b, 0x8a, 0xe0, 0xfe, 0x04, 0x94, 0xb4, 0x8b, 0xcf,
+  0xcd, 0x8c, 0x86, 0x18, 0xe5, 0x03, 0x55, 0x61, 0xc3, 0x1a, 0x5d, 0x9f,
+  0x6b, 0x24, 0x9a, 0xb2, 0xa4, 0x4d, 0x59, 0x53, 0xe3, 0x15, 0x1e, 0x69,
+  0x65, 0x7e, 0x8b, 0xec, 0x7d, 0x75, 0xc5, 0xe2, 0x48, 0xab, 0x63, 0xa7,
+  0xa4, 0xa3, 0xa7, 0x59, 0x20, 0xa7, 0x53, 0x23, 0xca, 0xab, 0x8f, 0x10,
+  0x12, 0x0e, 0xe7, 0xbf, 0x6d, 0x45, 0x77, 0x45, 0xab, 0x8c, 0x2c, 0xf2,
+  0xa1, 0x91, 0xf0, 0x15, 0x00, 0xfa, 0x71, 0xa9, 0xe8, 0x84, 0x66, 0x86,
+  0x48, 0x9a, 0x75, 0x8d, 0xce, 0xc5, 0xdb, 0x7e, 0x6d, 0x52, 0x65, 0xed,
+  0xae, 0x85, 0x57, 0x9a, 0xfa, 0xb8, 0x5e, 0x08, 0xe2, 0x05, 0xa3, 0x93,
+  0x0f, 0xca, 0xaa, 0x70, 0xa7, 0xfc, 0xfd, 0x35, 0x35, 0x4c, 0xf4, 0xb1,
+  0xa7, 0xcc, 0xd4, 0x54, 0xcc, 0x95, 0x12, 0x2e, 0x70, 0xbf, 0xe2, 0xff,
+  0x00, 0x2f, 0x4d, 0x0b, 0x5f, 0x3c, 0x4a, 0xea, 0x8e, 0x24, 0x6f, 0x0d,
+  0xb0, 0x08, 0x07, 0x71, 0xed, 0xbf, 0xdb, 0x5c, 0x4b, 0x72, 0xa1, 0x33,
+  0x47, 0x1b, 0x53, 0xaa, 0xca, 0xa0, 0x2a, 0x87, 0x1e, 0x60, 0x75, 0x2c,
+  0x94, 0x49, 0xe3, 0xcd, 0x3d, 0x31, 0xf0, 0xe0, 0x54, 0x56, 0x1b, 0xb6,
+  0x31, 0x9f, 0x7d, 0x09, 0x4a, 0x88, 0x19, 0x96, 0x59, 0x0c, 0x93, 0xc5,
+  0xe6, 0x2c, 0xdd, 0x17, 0xd3, 0x5d, 0xcf, 0x0d, 0x74, 0xc7, 0x9a, 0x7a,
+  0x94, 0xa7, 0x84, 0x9c, 0x80, 0xbf, 0x57, 0xe3, 0x40, 0x56, 0xb5, 0x32,
+  0x7f, 0x22, 0x08, 0x9a, 0x56, 0xfe, 0xa9, 0x1f, 0xb9, 0xf4, 0xd5, 0xd9,
+  0x03, 0x38, 0x96, 0x10, 0x9c, 0x51, 0x79, 0xce, 0x0f, 0x3d, 0xc2, 0x76,
+  0x3f, 0xff, 0x00, 0xd1, 0xb4, 0x3c, 0x30, 0xab, 0xb4, 0x71, 0x80, 0x00,
+  0xc8, 0x3a, 0xfd, 0xc5, 0xcc, 0xff, 0x00, 0xfa, 0xbe, 0xee, 0xb1, 0x80,
+  0x49, 0xaf, 0x9c, 0x1f, 0x6f, 0xe6, 0x36, 0x8e, 0xb3, 0x52, 0xb1, 0x2b,
+  0x9c, 0x9c, 0x0c, 0x13, 0xe9, 0x8e, 0xfa, 0x16, 0x70, 0x72, 0x76, 0xce,
+  0xde, 0x15, 0x05, 0x52, 0x31, 0xcd, 0x81, 0x86, 0x3a, 0xfc, 0xc1, 0x29,
+  0xe9, 0xf0, 0x48, 0x01, 0x77, 0x27, 0x46, 0x38, 0x5c, 0x19, 0x30, 0x79,
+  0x15, 0x79, 0x8b, 0x7b, 0x7a, 0xe9, 0x69, 0x9e, 0x49, 0xa6, 0x25, 0x55,
+  0x58, 0x8e, 0xfd, 0xa3, 0xfb, 0x7b, 0xfb, 0xe9, 0x51, 0x8d, 0xb1, 0x62,
+  0xda, 0xe6, 0x92, 0x4f, 0xf7, 0x96, 0x6e, 0x50, 0xf8, 0x48, 0xd4, 0x8d,
+  0xd8, 0x6e, 0x73, 0xa6, 0x16, 0xa6, 0x2b, 0x1a, 0x13, 0xb8, 0xf5, 0xd2,
+  0xfb, 0xb3, 0x7f, 0x35, 0x23, 0xe7, 0x69, 0x02, 0x8e, 0x76, 0x63, 0xd4,
+  0x93, 0xb7, 0xf6, 0x1a, 0x71, 0x41, 0x4f, 0x23, 0xd2, 0x24, 0xf1, 0xc6,
+  0x4c, 0x60, 0x0e, 0x9f, 0x6d, 0x04, 0xf8, 0x74, 0x08, 0xd2, 0x9c, 0x3f,
+  0x97, 0x93, 0x6c, 0x60, 0xe7, 0x4c, 0xae, 0xdc, 0x61, 0x72, 0xa4, 0xe2,
+  0xda, 0x5a, 0xf5, 0x68, 0xb1, 0x35, 0xb8, 0x51, 0xb4, 0x64, 0x86, 0x19,
+  0x0b, 0x80, 0xec, 0x08, 0xf5, 0xdf, 0x42, 0xd9, 0x69, 0xa5, 0x9c, 0x16,
+  0x2d, 0x1c, 0x51, 0x03, 0x86, 0x79, 0x1b, 0x00, 0x1f, 0x4f, 0xbe, 0xac,
+  0x77, 0x2e, 0x1f, 0xb0, 0xd2, 0x59, 0x29, 0x2f, 0x55, 0xf3, 0xc7, 0xf3,
+  0x8a, 0x59, 0x0a, 0x15, 0xd9, 0xa3, 0x3e, 0x56, 0x38, 0xeb, 0xce, 0x33,
+  0xb1, 0x1d, 0x0f, 0xae, 0xb9, 0xf9, 0xfe, 0x36, 0xed, 0x87, 0x08, 0xd1,
+  0x4b, 0xa9, 0x5a, 0x4a, 0x9a, 0x34, 0x72, 0x64, 0x12, 0x39, 0x08, 0x55,
+  0x50, 0x90, 0xcc, 0x46, 0x72, 0x31, 0xdc, 0xe4, 0xfd, 0xb7, 0xd5, 0x6e,
+  0xe9, 0x6a, 0x8a, 0x86, 0x71, 0x3d, 0x43, 0xc6, 0x50, 0xe7, 0x28, 0xad,
+  0xe6, 0x18, 0x3b, 0xe4, 0x76, 0xd5, 0x9a, 0xe9, 0xc5, 0xd5, 0xfc, 0x25,
+  0x7b, 0xaa, 0xa4, 0xb1, 0x50, 0xd1, 0x8a, 0x6a, 0x92, 0xbe, 0x0c, 0xf3,
+  0xd3, 0x7f, 0x35, 0x53, 0x1b, 0x18, 0xcb, 0x6e, 0x0e, 0xe7, 0x7d, 0x57,
+  0xef, 0xcd, 0x47, 0x2a, 0xc2, 0xeb, 0x70, 0x4a, 0x8a, 0xc9, 0xc0, 0x73,
+  0x18, 0x88, 0x83, 0x1b, 0x13, 0xb8, 0x66, 0x27, 0x05, 0xba, 0xe7, 0x1b,
+  0x7b, 0xeb, 0x55, 0x49, 0xc5, 0x49, 0x8e, 0x64, 0x53, 0x9f, 0xe2, 0x14,
+  0xa0, 0xa2, 0x08, 0xa9, 0xcb, 0x1f, 0x96, 0x42, 0x77, 0x7d, 0x03, 0x1c,
+  0x46, 0x13, 0xba, 0x05, 0xe5, 0x38, 0x6f, 0x63, 0xa8, 0x2f, 0xb5, 0x75,
+  0x35, 0x12, 0xc5, 0x4d, 0x24, 0xb9, 0x8a, 0x8d, 0x4c, 0x70, 0x28, 0x18,
+  0xe5, 0x19, 0xcb, 0x1f, 0xbe, 0x75, 0xf6, 0xcb, 0x53, 0x4f, 0x9a, 0x95,
+  0xaf, 0x8d, 0xa7, 0xfe, 0x51, 0xf0, 0xdb, 0x9b, 0x74, 0x3b, 0x60, 0xfe,
+  0x3a, 0x7e, 0x75, 0x70, 0x8b, 0x5d, 0x80, 0xd0, 0x5d, 0xc2, 0xf3, 0x58,
+  0xf2, 0x54, 0x3c, 0x54, 0x94, 0xf0, 0x42, 0xe4, 0x23, 0x34, 0x29, 0xcb,
+  0x80, 0x31, 0xb7, 0xea, 0x33, 0x9f, 0x53, 0xa3, 0x38, 0x32, 0xde, 0xd7,
+  0xab, 0xb9, 0xa5, 0x32, 0xc3, 0x02, 0x4a, 0x59, 0xa4, 0xa8, 0x99, 0xb9,
+  0x42, 0x80, 0x32, 0x49, 0x6e, 0xc0, 0x01, 0x9d, 0x22, 0x9b, 0x9a, 0x03,
+  0x2c, 0x7c, 0xbe, 0x2c, 0x64, 0x61, 0xb2, 0x71, 0xae, 0xed, 0xeb, 0x22,
+  0x51, 0x38, 0x35, 0x02, 0x2a, 0x76, 0x50, 0x65, 0xc1, 0xce, 0x7b, 0xe0,
+  0xe9, 0xff, 0x00, 0x1a, 0xf4, 0x35, 0x44, 0x6f, 0x71, 0xb9, 0x41, 0x6a,
+  0x81, 0x8d, 0x21, 0x47, 0x4f, 0x10, 0xac, 0x52, 0x63, 0x3e, 0x22, 0x8e,
+  0xfb, 0xef, 0xff, 0x00, 0x9d, 0x75, 0x55, 0x2f, 0xce, 0xd3, 0xdb, 0x6f,
+  0x10, 0x9f, 0xe7, 0x4c, 0xc2, 0x19, 0x71, 0xdb, 0x6d, 0x57, 0xef, 0x01,
+  0x2b, 0x44, 0x2b, 0x02, 0x88, 0xd1, 0x00, 0x00, 0x67, 0x60, 0x31, 0xab,
+  0x7d, 0xb6, 0xc1, 0x33, 0xf0, 0x55, 0x35, 0x54, 0x15, 0x10, 0x34, 0x09,
+  0x2b, 0x2e, 0x43, 0x79, 0xa3, 0x97, 0x63, 0xb8, 0xed, 0x9c, 0x9c, 0x6a,
+  0xf1, 0xc5, 0x46, 0x5c, 0x7b, 0x1d, 0xa7, 0x95, 0x4a, 0x8e, 0xf8, 0x46,
+  0x68, 0xad, 0xd7, 0x7a, 0xba, 0x29, 0xc1, 0x8a, 0x69, 0x64, 0x0a, 0xac,
+  0x47, 0x94, 0x6f, 0xbe, 0x47, 0xa6, 0x33, 0xa6, 0x5c, 0x46, 0x69, 0xa4,
+  0xe1, 0x44, 0x34, 0xd3, 0x2c, 0x81, 0x18, 0xf8, 0x43, 0x3b, 0xa3, 0x07,
+  0x38, 0x20, 0xf7, 0xdb, 0x51, 0x5a, 0xad, 0x54, 0x55, 0xf7, 0xca, 0x05,
+  0x59, 0x98, 0x45, 0x71, 0x82, 0x58, 0xe5, 0x27, 0xcd, 0xcb, 0x2a, 0x0f,
+  0x37, 0xa6, 0xc4, 0xe8, 0x8e, 0x17, 0x84, 0x53, 0xd4, 0x49, 0x62, 0xbb,
+  0x27, 0xf3, 0x28, 0x5d, 0xbc, 0x0c, 0x9d, 0x9f, 0x27, 0x61, 0x8f, 0x40,
+  0x0e, 0x7f, 0x3a, 0xd2, 0x6e, 0x14, 0xdf, 0x28, 0xe6, 0x17, 0xf1, 0x0c,
+  0xb5, 0xb0, 0xb7, 0x2c, 0x48, 0xe7, 0xae, 0x09, 0x6c, 0x74, 0x3d, 0x36,
+  0xcf, 0x5d, 0x4d, 0x6e, 0x9e, 0xa2, 0x19, 0x62, 0x7a, 0x57, 0xa7, 0x12,
+  0xab, 0x32, 0x13, 0x2e, 0xea, 0x33, 0xb8, 0x23, 0xd4, 0xed, 0xfa, 0x6a,
+  0x5b, 0x85, 0x12, 0x10, 0xd5, 0x10, 0x85, 0x2f, 0x22, 0x91, 0xb7, 0xd0,
+  0x33, 0x90, 0x32, 0x7d, 0xb1, 0xd3, 0x40, 0x5c, 0xe6, 0x5b, 0x6d, 0xbd,
+  0xcc, 0xcc, 0x5d, 0x8a, 0x8e, 0xa3, 0x04, 0xb3, 0x0e, 0x9d, 0xff, 0x00,
+  0xec, 0x1d, 0x42, 0x9a, 0x38, 0x5b, 0xcd, 0x64, 0xcd, 0x53, 0x45, 0x3d,
+  0x5d, 0x05, 0x2b, 0x2b, 0x9e, 0x79, 0x9a, 0x52, 0xc4, 0x80, 0x77, 0xf0,
+  0xd4, 0xec, 0x09, 0xf4, 0xd1, 0x34, 0x86, 0x2a, 0xb9, 0x44, 0x76, 0xf9,
+  0x1a, 0xa0, 0xf4, 0x79, 0x64, 0x3c, 0xa4, 0xfa, 0x8e, 0xfa, 0xa2, 0xba,
+  0xc0, 0x55, 0xe5, 0x91, 0xd9, 0xe5, 0x46, 0xc2, 0xa9, 0x3b, 0x0f, 0xfc,
+  0x6a, 0xff, 0x00, 0xf0, 0xd6, 0x84, 0xdd, 0xd5, 0x56, 0x3a, 0xa2, 0xaf,
+  0x21, 0x28, 0x60, 0x43, 0x86, 0x60, 0xa0, 0x16, 0x6c, 0xfa, 0x6a, 0x15,
+  0xb9, 0x2e, 0xce, 0xe5, 0x33, 0xd1, 0xd6, 0x24, 0x63, 0xc3, 0x25, 0x18,
+  0x1e, 0x45, 0xf6, 0xd3, 0xca, 0x9a, 0xab, 0x65, 0x4c, 0x82, 0xb2, 0xad,
+  0xa1, 0x33, 0x3e, 0x09, 0x76, 0x18, 0x03, 0x6e, 0xde, 0x9a, 0x1a, 0xba,
+  0xc6, 0xf6, 0xab, 0x84, 0x8f, 0x24, 0x0d, 0x0b, 0x83, 0x82, 0xa7, 0x32,
+  0x72, 0x13, 0xd0, 0x64, 0x7a, 0xe8, 0x1a, 0x8a, 0x55, 0xaa, 0xb8, 0xf2,
+  0xbd, 0x4c, 0x06, 0x38, 0xcf, 0x21, 0x91, 0xdb, 0x93, 0x1b, 0x03, 0xf4,
+  0x9e, 0xdd, 0xb5, 0x06, 0x45, 0x46, 0x43, 0xca, 0xba, 0x3b, 0x65, 0x4d,
+  0x2c, 0x75, 0x10, 0x49, 0x2b, 0x52, 0xf2, 0x66, 0x47, 0x91, 0x79, 0x15,
+  0xcf, 0xa0, 0xfb, 0x7a, 0xe9, 0x1c, 0x72, 0x5a, 0xab, 0xae, 0x93, 0xba,
+  0x54, 0xcb, 0x41, 0x16, 0x15, 0x12, 0x3c, 0x1e, 0x46, 0x41, 0xeb, 0x8f,
+  0x5d, 0x73, 0x0d, 0x28, 0xab, 0xaf, 0x11, 0x52, 0xd4, 0x07, 0xa5, 0x89,
+  0x72, 0xf2, 0x67, 0xcb, 0xdb, 0x23, 0xdb, 0xed, 0xa9, 0xab, 0x22, 0xa4,
+  0x15, 0x5f, 0xee, 0x6f, 0xe2, 0xc6, 0x83, 0x99, 0xa4, 0xe4, 0xcf, 0x39,
+  0xe9, 0xb6, 0xfd, 0x34, 0x05, 0xec, 0x3f, 0x55, 0xc0, 0x22, 0x96, 0x49,
+  0xf3, 0x13, 0x72, 0xb9, 0xe5, 0x4f, 0x10, 0x6c, 0xb9, 0xe9, 0x9c, 0x64,
+  0xe3, 0x5f, 0x09, 0xa0, 0x69, 0xd7, 0xc4, 0x12, 0x3c, 0x6d, 0xbb, 0x3f,
+  0x26, 0x06, 0x75, 0xd5, 0x0c, 0x2a, 0xb0, 0x99, 0x0a, 0x2e, 0x7a, 0xf3,
+  0xb8, 0xc9, 0x1e, 0x9a, 0x1e, 0xa6, 0xad, 0x01, 0x6c, 0xc8, 0xc4, 0x11,
+  0x82, 0x54, 0x72, 0x92, 0x7d, 0xb5, 0x2c, 0x24, 0x88, 0xee, 0x09, 0x4d,
+  0x15, 0x63, 0x44, 0x2a, 0x92, 0x6a, 0x79, 0x14, 0x81, 0xcb, 0xb0, 0x55,
+  0x3d, 0x06, 0x7a, 0x9c, 0x6a, 0x4a, 0x6b, 0x62, 0xcc, 0xac, 0xf3, 0x7c,
+  0xa1, 0x87, 0x62, 0x25, 0x73, 0xbe, 0xdd, 0x40, 0xd2, 0x72, 0x61, 0x59,
+  0x39, 0xa4, 0x2c, 0xa8, 0x0e, 0x48, 0x51, 0x9d, 0x33, 0xa2, 0x96, 0x81,
+  0xdb, 0xe6, 0xe0, 0x89, 0x88, 0x56, 0xe5, 0xfa, 0x82, 0x9f, 0xbe, 0xfa,
+  0x96, 0x48, 0x47, 0x90, 0xca, 0xa0, 0x5e, 0x1c, 0xc3, 0x22, 0x98, 0x90,
+  0xe5, 0x42, 0x0f, 0x20, 0x1f, 0xf2, 0xfe, 0xa7, 0xf5, 0xd4, 0x10, 0xab,
+  0x46, 0x85, 0xd8, 0x0f, 0x31, 0xd8, 0x93, 0xa6, 0x72, 0xd5, 0x17, 0x89,
+  0x56, 0x33, 0x85, 0x23, 0x38, 0x6d, 0xf1, 0x9d, 0x05, 0x51, 0x19, 0x78,
+  0xb9, 0x24, 0x95, 0x37, 0x39, 0xc8, 0x19, 0x00, 0x7a, 0x7d, 0xf4, 0x36,
+  0x32, 0x8e, 0x23, 0xe4, 0x2f, 0x97, 0x78, 0xbc, 0x6c, 0xf9, 0x15, 0xba,
+  0x0f, 0x7f, 0xfa, 0xe8, 0x5a, 0x95, 0x8d, 0xe7, 0x0d, 0x53, 0x52, 0xc9,
+  0x17, 0x49, 0x18, 0x30, 0x23, 0x3e, 0xc3, 0xbe, 0x8e, 0x8e, 0xaa, 0x8a,
+  0x9c, 0x32, 0x1c, 0x29, 0xc7, 0x95, 0x89, 0xce, 0x80, 0xaa, 0xf0, 0x1a,
+  0x21, 0x15, 0x35, 0x32, 0x7f, 0x88, 0x1e, 0x5c, 0x67, 0xdf, 0x3a, 0x89,
+  0x83, 0x41, 0x31, 0x44, 0x21, 0x85, 0xa4, 0x86, 0x6c, 0x43, 0x8f, 0x2b,
+  0x14, 0xc3, 0x63, 0xfc, 0xb5, 0x09, 0xab, 0xa4, 0x40, 0xaf, 0x83, 0x2c,
+  0xa0, 0x7d, 0x4c, 0x37, 0xd0, 0x71, 0x53, 0x4d, 0x22, 0xa4, 0x50, 0xc1,
+  0x34, 0xf3, 0x31, 0xc6, 0x22, 0x56, 0x60, 0xb8, 0xfc, 0x6f, 0xab, 0x5f,
+  0x0b, 0xfc, 0x32, 0xe3, 0x2e, 0x24, 0x9a, 0x37, 0x86, 0xc1, 0x58, 0x60,
+  0xe5, 0x00, 0xcb, 0x51, 0x88, 0x50, 0x6e, 0x33, 0xf5, 0x60, 0x9c, 0x0f,
+  0x4c, 0xea, 0xec, 0x85, 0x62, 0x6b, 0xc4, 0xb2, 0x6c, 0x94, 0xa4, 0xb2,
+  0x9c, 0x00, 0xfd, 0x0e, 0x3d, 0x35, 0xf2, 0xa2, 0xae, 0xaa, 0xb9, 0x07,
+  0x8a, 0x90, 0xaf, 0x37, 0xd3, 0x91, 0xb6, 0x75, 0xb3, 0x56, 0x7c, 0x06,
+  0x96, 0xcf, 0x2c, 0xd5, 0x95, 0xd7, 0x75, 0x34, 0x71, 0x6e, 0x9e, 0x04,
+  0x21, 0x5a, 0x4f, 0xc9, 0x27, 0x97, 0xf7, 0xd5, 0x83, 0x83, 0x57, 0x86,
+  0x78, 0x76, 0xa5, 0x0f, 0xf0, 0x2a, 0x22, 0x09, 0x21, 0xe6, 0x91, 0x3c,
+  0x49, 0x37, 0xea, 0x43, 0x36, 0x71, 0xf6, 0xd6, 0x0c, 0xdf, 0x90, 0xc5,
+  0x87, 0x26, 0xc9, 0xf0, 0x64, 0xcb, 0xac, 0xc7, 0x89, 0xd4, 0x8c, 0x9b,
+  0xe1, 0xf7, 0xc2, 0x4e, 0x30, 0xe2, 0xdc, 0x55, 0x4d, 0x1c, 0x94, 0x16,
+  0xdf, 0xe9, 0xa9, 0xa8, 0x04, 0x07, 0x1f, 0xf2, 0xa9, 0xc1, 0x23, 0x7e,
+  0xba, 0xde, 0xf8, 0x1f, 0xe1, 0x0f, 0x06, 0x70, 0xd5, 0x10, 0x7a, 0x8a,
+  0x75, 0xbb, 0x5c, 0x39, 0x73, 0x24, 0xd5, 0x03, 0x2a, 0x0e, 0x07, 0xd2,
+  0x9d, 0x06, 0xfe, 0xb9, 0x3e, 0xfa, 0xb7, 0xdc, 0x78, 0xc2, 0x8e, 0x9e,
+  0x8e, 0x19, 0x62, 0x41, 0x3f, 0x38, 0xda, 0x3e, 0x81, 0x75, 0xd5, 0x97,
+  0x88, 0xa3, 0xba, 0xb8, 0x8e, 0x4a, 0x55, 0x87, 0x23, 0x20, 0x0d, 0xc7,
+  0xeb, 0xeb, 0xab, 0x7a, 0xcd, 0x33, 0x96, 0xc8, 0xcd, 0x36, 0xcc, 0xdf,
+  0xca, 0xc7, 0x3e, 0x99, 0xe7, 0x2f, 0xff, 0x00, 0x88, 0x6b, 0xab, 0x6e,
+  0xf5, 0x17, 0xbb, 0xd5, 0xc2, 0x9a, 0xd3, 0x6e, 0xad, 0xac, 0x92, 0x58,
+  0x9b, 0x9c, 0x3c, 0x92, 0xa1, 0x72, 0xc4, 0x85, 0xe8, 0x36, 0x23, 0xaf,
+  0xae, 0x99, 0x70, 0xef, 0x03, 0xc1, 0x59, 0x5d, 0xc5, 0x31, 0x59, 0xe9,
+  0x95, 0xe9, 0xe0, 0x81, 0xe9, 0xe9, 0xcc, 0xad, 0xb9, 0xc9, 0x05, 0x7e,
+  0xec, 0x40, 0xeb, 0x9d, 0x69, 0x1c, 0x5b, 0x15, 0xba, 0x4a, 0xae, 0x1d,
+  0x92, 0xe7, 0x33, 0x24, 0x51, 0x5b, 0x61, 0xe4, 0xe5, 0x6c, 0xb0, 0x24,
+  0x1f, 0xe9, 0xf4, 0x3b, 0x6f, 0xa6, 0x1c, 0x1d, 0x4b, 0x5b, 0x6f, 0xa5,
+  0xb9, 0xcf, 0x1c, 0x50, 0x47, 0x4a, 0x19, 0xa6, 0x46, 0x55, 0xda, 0x47,
+  0xe5, 0x3c, 0xa7, 0x3d, 0xc0, 0xc6, 0x7e, 0xf8, 0xd3, 0xe7, 0xe1, 0x22,
+  0x64, 0xc6, 0x94, 0xa9, 0x1e, 0x53, 0xbd, 0xb3, 0xc2, 0xe6, 0x85, 0xd5,
+  0xe3, 0x90, 0x31, 0xf1, 0x50, 0x8f, 0x30, 0xc6, 0xdc, 0xa7, 0xdf, 0x39,
+  0xfd, 0x34, 0x34, 0x4b, 0x31, 0x89, 0x62, 0x08, 0xb1, 0x21, 0x20, 0x10,
+  0x06, 0xe7, 0xef, 0xa2, 0xae, 0xd3, 0x34, 0xb7, 0x09, 0x6a, 0x27, 0x72,
+  0xf2, 0xca, 0xd9, 0x77, 0x3d, 0xcf, 0x7d, 0x45, 0x16, 0x19, 0x58, 0x91,
+  0xb6, 0x36, 0xd1, 0xc5, 0xd1, 0x81, 0xf6, 0x03, 0x5f, 0x01, 0x77, 0x66,
+  0x55, 0xc1, 0x52, 0x47, 0xdf, 0x56, 0x9e, 0x1f, 0x88, 0xa5, 0x8e, 0x33,
+  0x08, 0x01, 0xca, 0xe4, 0xae, 0x92, 0x34, 0x6a, 0xd1, 0xb6, 0x7e, 0xc3,
+  0x5a, 0x25, 0xa2, 0xd9, 0x1c, 0x74, 0x34, 0x50, 0xca, 0xeb, 0x1a, 0xb6,
+  0x09, 0x94, 0x9c, 0x05, 0x07, 0xa9, 0xfd, 0x33, 0xaa, 0x84, 0xb9, 0x6c,
+  0xa0, 0xeb, 0x35, 0xda, 0xe9, 0x07, 0x04, 0x09, 0x23, 0xb7, 0xc3, 0x1c,
+  0x36, 0xe5, 0x92, 0x45, 0x9f, 0x00, 0x18, 0xe6, 0x66, 0xc2, 0xc9, 0xbf,
+  0xd4, 0xdd, 0x40, 0x03, 0xa0, 0xce, 0xdd, 0xf5, 0x47, 0xaa, 0x7b, 0x95,
+  0x65, 0xc9, 0xaa, 0x6b, 0x6a, 0x1a, 0x67, 0x93, 0x76, 0x9b, 0x3b, 0x9d,
+  0xf3, 0xd7, 0xae, 0x72, 0x35, 0x0d, 0xd2, 0x6a, 0xba, 0x9a, 0x99, 0x16,
+  0x33, 0x53, 0x1d, 0x03, 0x4a, 0x3e, 0x5e, 0x9e, 0x59, 0x08, 0xe6, 0x03,
+  0xa3, 0x15, 0xf5, 0xc6, 0xbe, 0x73, 0x4d, 0x44, 0xfc, 0xa8, 0x43, 0xc4,
+  0x40, 0x62, 0x31, 0xea, 0x33, 0xae, 0x7d, 0xb9, 0xab, 0x7d, 0x92, 0xdf,
+  0xb1, 0xef, 0xfe, 0xab, 0xe1, 0xdb, 0x35, 0x1c, 0xd5, 0xf7, 0xdb, 0x3c,
+  0x97, 0xab, 0xc8, 0x46, 0x58, 0x04, 0xa5, 0x4c, 0x4c, 0x36, 0xf3, 0x3e,
+  0x73, 0xb8, 0xf4, 0x00, 0x1d, 0xf5, 0x93, 0x5d, 0x6a, 0x7f, 0x8a, 0xdc,
+  0x26, 0xae, 0x11, 0x47, 0x4d, 0x23, 0x31, 0x2b, 0x14, 0x43, 0x0a, 0x83,
+  0x39, 0xc0, 0xd3, 0x5e, 0x2c, 0x91, 0x66, 0xaa, 0x05, 0x0e, 0xeb, 0x93,
+  0x8f, 0x63, 0xa4, 0x44, 0xaa, 0xc7, 0x14, 0x7c, 0xc0, 0x78, 0xe7, 0x90,
+  0xb1, 0xe8, 0x0f, 0xa1, 0xd7, 0x46, 0x2d, 0xec, 0x49, 0x8f, 0x8c, 0x9b,
+  0xec, 0xec, 0x1f, 0x15, 0x73, 0x27, 0x99, 0xb3, 0xe6, 0xcf, 0xae, 0xa2,
+  0xaf, 0x44, 0x82, 0x08, 0xc8, 0x60, 0xbc, 0xc7, 0x66, 0xf7, 0xd3, 0x7a,
+  0x2b, 0x44, 0xf1, 0xe0, 0xa0, 0x0b, 0x8d, 0xb0, 0x76, 0x24, 0x6b, 0x8b,
+  0xe4, 0x3e, 0x15, 0x19, 0xf1, 0xd2, 0x2d, 0xfe, 0xa0, 0x17, 0xbf, 0xae,
+  0xab, 0x22, 0xb4, 0x8a, 0x8f, 0x62, 0x4a, 0x47, 0x69, 0x27, 0x45, 0x69,
+  0x39, 0x57, 0x1b, 0x9e, 0xde, 0xff, 0x00, 0xdb, 0x47, 0xdc, 0x2a, 0x69,
+  0xa3, 0x50, 0xd4, 0xf0, 0xc6, 0x25, 0xe8, 0xdb, 0x6d, 0x9f, 0x4c, 0x69,
+  0x13, 0x2b, 0xae, 0x02, 0xbb, 0x04, 0xd8, 0x92, 0x36, 0xfc, 0x68, 0xe6,
+  0x81, 0x10, 0x23, 0x40, 0xc4, 0xae, 0x03, 0x12, 0xdd, 0x73, 0xdf, 0xf1,
+  0xa5, 0xa4, 0x12, 0x64, 0x31, 0xc9, 0x14, 0x93, 0xe1, 0x93, 0x90, 0x92,
+  0x7a, 0x74, 0xfd, 0x35, 0xe8, 0xfa, 0x0e, 0x0d, 0xb3, 0x5b, 0x3e, 0x09,
+  0x48, 0x68, 0x96, 0x79, 0xeb, 0xaa, 0x04, 0x15, 0xf5, 0x12, 0x33, 0x79,
+  0x49, 0x5d, 0xc8, 0x51, 0x9d, 0x80, 0x42, 0xda, 0xf3, 0xfa, 0xc2, 0x12,
+  0x56, 0x2e, 0x42, 0xb8, 0x00, 0xa9, 0x03, 0xa8, 0x3b, 0xeb, 0xd0, 0xdc,
+  0x0f, 0xf1, 0x04, 0x55, 0xf0, 0x5d, 0xbe, 0xd0, 0x91, 0xc4, 0xd3, 0x52,
+  0xd3, 0x0a, 0x69, 0x55, 0x86, 0x4e, 0x00, 0xc0, 0x3f, 0x91, 0xa5, 0x67,
+  0xda, 0xaa, 0x52, 0x74, 0x90, 0x37, 0xcd, 0x99, 0xa8, 0x13, 0xc5, 0x43,
+  0x25, 0xc5, 0x1f, 0x96, 0x7a, 0x3a, 0x91, 0x32, 0xa9, 0x18, 0xf1, 0x14,
+  0x9e, 0x57, 0xc0, 0xef, 0xe6, 0x03, 0xf5, 0x1a, 0x6d, 0x7f, 0x78, 0xe4,
+  0xbd, 0x5a, 0xaa, 0xea, 0x52, 0x58, 0x52, 0x5a, 0x57, 0xdc, 0x1f, 0x36,
+  0x7a, 0x8c, 0x8f, 0x61, 0x8d, 0x7e, 0xa5, 0xa3, 0x86, 0xa0, 0x5e, 0xad,
+  0x0d, 0x21, 0x5a, 0xa8, 0x49, 0x11, 0x87, 0xd8, 0x3c, 0x6c, 0x83, 0x60,
+  0x3b, 0x79, 0x94, 0x7e, 0xba, 0xe6, 0xae, 0x2a, 0x9b, 0x9d, 0x8f, 0x87,
+  0x1c, 0x6f, 0x50, 0xb2, 0xc7, 0x18, 0x3f, 0xf2, 0x82, 0x57, 0xfb, 0x0d,
+  0x74, 0x62, 0xd4, 0x95, 0xa3, 0xac, 0xb9, 0x42, 0xca, 0x8a, 0xb1, 0x00,
+  0x96, 0x9e, 0x59, 0xe1, 0x67, 0x8e, 0x55, 0x87, 0x9b, 0x18, 0x56, 0x52,
+  0x09, 0xe6, 0x23, 0xb9, 0xc9, 0xc9, 0xf5, 0xfc, 0x69, 0x1d, 0xcd, 0xa2,
+  0x91, 0xe3, 0x50, 0xa2, 0x79, 0x64, 0x03, 0x2f, 0xfd, 0x38, 0xec, 0x71,
+  0xdb, 0xed, 0xa7, 0xbc, 0x45, 0x22, 0x7f, 0x15, 0x91, 0x04, 0x3c, 0xe9,
+  0x2c, 0x2a, 0x55, 0x13, 0x62, 0x58, 0x33, 0x63, 0x3a, 0x4d, 0x67, 0xa7,
+  0x96, 0x47, 0x96, 0xb2, 0xa6, 0x3c, 0xb2, 0x36, 0xc9, 0xd3, 0x18, 0xd8,
+  0xea, 0xc6, 0x51, 0x2d, 0xaa, 0xd5, 0x6d, 0xa4, 0xa9, 0xac, 0x32, 0xc5,
+  0x0c, 0xf2, 0x54, 0x29, 0x4f, 0x3a, 0x6d, 0x19, 0xc7, 0x51, 0xff, 0x00,
+  0x7d, 0xf4, 0xf3, 0x83, 0xea, 0xa5, 0xb0, 0x42, 0x25, 0xa4, 0x8a, 0x9a,
+  0x82, 0x49, 0xa6, 0x65, 0x4a, 0x95, 0x8c, 0x39, 0x8e, 0x23, 0xec, 0x48,
+  0xdc, 0x91, 0xb7, 0xb6, 0x96, 0x4c, 0x4c, 0x15, 0x12, 0x7c, 0xc3, 0x6f,
+  0x29, 0x57, 0xe5, 0x4d, 0xd8, 0x92, 0x3b, 0x0d, 0x77, 0x71, 0xa9, 0x69,
+  0x53, 0xe4, 0x60, 0xa6, 0x8e, 0x06, 0x95, 0x46, 0x65, 0x78, 0xc6, 0xeb,
+  0xd3, 0x3e, 0xd8, 0x07, 0x19, 0xf5, 0x3a, 0x00, 0x66, 0x83, 0xab, 0x6a,
+  0xea, 0xe6, 0x49, 0xab, 0x2e, 0x17, 0x96, 0xf0, 0x6a, 0x7c, 0xd1, 0x45,
+  0x1b, 0x79, 0x80, 0x3b, 0x82, 0xde, 0xff, 0x00, 0x6d, 0x2d, 0x86, 0x4a,
+  0x68, 0x22, 0x96, 0x78, 0xe1, 0x79, 0xcb, 0x00, 0xaa, 0xd2, 0x80, 0x47,
+  0x36, 0x3b, 0x69, 0xa5, 0x45, 0xbe, 0x8a, 0x92, 0xdc, 0xf5, 0x4c, 0xaf,
+  0x20, 0x50, 0xab, 0x17, 0x3a, 0xed, 0x81, 0xdc, 0x8f, 0x43, 0xdb, 0x50,
+  0x53, 0x1f, 0x98, 0xa8, 0x35, 0x95, 0xe2, 0x38, 0x29, 0x97, 0xc8, 0x39,
+  0x13, 0x00, 0x11, 0xd8, 0x0f, 0xc6, 0xa0, 0x6a, 0x07, 0x34, 0x90, 0x23,
+  0x50, 0xc3, 0x0b, 0xf2, 0xa3, 0xc8, 0x39, 0x9f, 0x19, 0x00, 0x8f, 0x4f,
+  0xfb, 0xf4, 0xd1, 0x31, 0x40, 0xb0, 0xc8, 0x20, 0xf1, 0x02, 0x43, 0x93,
+  0xcc, 0x54, 0xee, 0xc3, 0x4b, 0x6b, 0xeb, 0x5a, 0x79, 0x84, 0x31, 0x07,
+  0x48, 0xf9, 0x89, 0x0b, 0xcc, 0x73, 0x8f, 0xf2, 0xd4, 0xad, 0x1c, 0xd1,
+  0x22, 0x91, 0x84, 0xc9, 0xca, 0x03, 0x92, 0x70, 0x46, 0x7a, 0xe7, 0x50,
+  0x60, 0x65, 0x53, 0xc7, 0x0a, 0x88, 0xd2, 0x00, 0x0f, 0x31, 0x06, 0x59,
+  0x18, 0x1e, 0x6f, 0x4c, 0x7a, 0x68, 0x1a, 0xaa, 0xd6, 0xe5, 0x68, 0x95,
+  0x23, 0x04, 0x0c, 0x73, 0x05, 0xc8, 0xd7, 0x35, 0xd2, 0xb3, 0xc7, 0x12,
+  0x31, 0xf3, 0x31, 0x00, 0x9e, 0x60, 0x77, 0xc7, 0xf7, 0xd0, 0x29, 0x04,
+  0x22, 0xb2, 0x40, 0xc2, 0x52, 0x63, 0xe8, 0x5b, 0x61, 0x9d, 0x2c, 0x84,
+  0x90, 0x55, 0x2a, 0x23, 0x09, 0xa7, 0x63, 0xd8, 0xaa, 0x46, 0x30, 0x75,
+  0x0c, 0x73, 0xc5, 0x1c, 0x92, 0xba, 0x29, 0x54, 0x39, 0x61, 0x9f, 0x5d,
+  0x14, 0x65, 0xa5, 0xa6, 0x4e, 0x6a, 0x94, 0x66, 0x69, 0x73, 0xc9, 0xe5,
+  0xc6, 0x4f, 0xa0, 0xd4, 0x74, 0x34, 0x93, 0x5c, 0xaa, 0x9e, 0x38, 0x41,
+  0x41, 0x18, 0x0c, 0xf1, 0xb0, 0xc1, 0x00, 0xf6, 0xd5, 0x49, 0xa4, 0xad,
+  0x82, 0xe7, 0x1c, 0x6a, 0xe4, 0xcf, 0xd1, 0xd5, 0x49, 0x55, 0x12, 0x32,
+  0xe5, 0xb3, 0x91, 0x8e, 0x83, 0x6d, 0x3b, 0xe1, 0xde, 0x1c, 0xbc, 0x5c,
+  0xe0, 0x6a, 0xb5, 0x10, 0xd2, 0x53, 0x09, 0x39, 0x3c, 0x6a, 0x89, 0x02,
+  0x26, 0x7d, 0x89, 0xdd, 0xbe, 0xc0, 0x1d, 0x3d, 0xb0, 0x70, 0xd5, 0xca,
+  0xd2, 0xf4, 0xb7, 0xb6, 0xb3, 0x25, 0x4d, 0x1c, 0x45, 0x64, 0xe5, 0x91,
+  0x03, 0xa4, 0x9e, 0xc4, 0x67, 0x45, 0xdf, 0xae, 0x54, 0x1c, 0x45, 0xc6,
+  0x12, 0xd5, 0xc4, 0xb0, 0x5a, 0xa9, 0x9c, 0x89, 0x24, 0x49, 0x5f, 0x96,
+  0x35, 0x7c, 0x00, 0xd8, 0x18, 0xeb, 0xfe, 0x9a, 0xcd, 0x93, 0x54, 0xaa,
+  0xa1, 0xd9, 0xcf, 0xcb, 0xac, 0x57, 0x50, 0xe4, 0x9a, 0x5f, 0x86, 0x16,
+  0xf3, 0xe1, 0x4d, 0x72, 0xba, 0x99, 0xd1, 0x94, 0xb0, 0x92, 0x05, 0xf2,
+  0x6d, 0xd4, 0x02, 0x7a, 0x77, 0xed, 0xa6, 0x74, 0x1f, 0x0d, 0x78, 0x7d,
+  0xee, 0x34, 0xd5, 0x74, 0xf7, 0x4b, 0x8d, 0x55, 0x34, 0x88, 0x3f, 0x92,
+  0xfb, 0x3b, 0x82, 0x32, 0x14, 0x1c, 0xec, 0x0e, 0xdb, 0xe3, 0x56, 0xfe,
+  0x16, 0xbf, 0x70, 0xb5, 0x25, 0xa5, 0xe9, 0x2b, 0x6a, 0xad, 0xd3, 0xc3,
+  0x12, 0x2a, 0x8f, 0x02, 0x42, 0x43, 0x9e, 0xcd, 0x82, 0x3e, 0xbd, 0xce,
+  0xfe, 0xc3, 0x57, 0xbb, 0x05, 0x77, 0x0a, 0x47, 0x6d, 0x94, 0xda, 0xea,
+  0xe9, 0xa0, 0xf0, 0x51, 0x25, 0xa9, 0x91, 0x9b, 0x1e, 0x18, 0x60, 0x70,
+  0x0b, 0x7e, 0x0e, 0xda, 0xe6, 0xfc, 0x3a, 0xb9, 0xbb, 0x79, 0x69, 0x19,
+  0xbe, 0x7c, 0x8f, 0xfb, 0xcc, 0xf6, 0x86, 0xeb, 0x5d, 0xc1, 0x96, 0xd6,
+  0xb2, 0xd1, 0x5a, 0x85, 0xa2, 0x16, 0x91, 0x8b, 0x18, 0xe2, 0xcb, 0x36,
+  0x7f, 0xab, 0x9f, 0xd7, 0x6d, 0x36, 0xb4, 0x71, 0xdc, 0xb4, 0xb6, 0xf5,
+  0x86, 0xae, 0xe3, 0x1a, 0x73, 0x1c, 0xc1, 0x2b, 0xb7, 0x9a, 0x45, 0x3d,
+  0x9b, 0xdc, 0x7f, 0x96, 0x9d, 0xdf, 0x6f, 0x56, 0x2b, 0xa5, 0xba, 0xa2,
+  0x95, 0x6a, 0xad, 0xd3, 0xa7, 0x86, 0x79, 0xa5, 0x9a, 0x50, 0x30, 0x7d,
+  0x37, 0x1f, 0xbe, 0xb1, 0x7b, 0x8d, 0xb2, 0xed, 0x2c, 0x32, 0x7c, 0x9c,
+  0x74, 0xf7, 0x5a, 0x26, 0xcb, 0x2c, 0x51, 0x37, 0x34, 0x91, 0x2e, 0x3a,
+  0xff, 0x00, 0xd7, 0x57, 0x9b, 0x0e, 0x5d, 0xb4, 0xa7, 0x7f, 0xf6, 0x23,
+  0x24, 0xa7, 0xea, 0x56, 0x6b, 0xd7, 0x3e, 0x2d, 0x9e, 0xa2, 0xdf, 0xe0,
+  0x0a, 0xc8, 0xda, 0x26, 0x05, 0x64, 0xca, 0x87, 0x2f, 0xfa, 0xf4, 0xd5,
+  0x2a, 0xed, 0x0c, 0x33, 0x54, 0x43, 0x83, 0xf2, 0xf0, 0x31, 0x1e, 0x33,
+  0x67, 0x65, 0x4e, 0xbf, 0xae, 0x91, 0x70, 0xec, 0xb1, 0x41, 0xc2, 0x38,
+  0x86, 0x36, 0x9e, 0x56, 0x25, 0xe3, 0x32, 0x3f, 0xd0, 0x17, 0x66, 0x5c,
+  0xe3, 0x1d, 0xc6, 0xdd, 0x76, 0xd2, 0xda, 0xaa, 0x9a, 0x8b, 0xbd, 0x05,
+  0x44, 0xe6, 0xb2, 0x8a, 0x0a, 0x78, 0x17, 0x95, 0x95, 0xe7, 0x0a, 0x5b,
+  0xff, 0x00, 0x88, 0xfd, 0xb5, 0xcc, 0x78, 0x35, 0x19, 0x66, 0xb7, 0xc9,
+  0xb4, 0x26, 0xa6, 0xfb, 0x1b, 0xde, 0x78, 0xe2, 0x82, 0x0b, 0xc8, 0x86,
+  0x82, 0x88, 0x55, 0x51, 0x53, 0xa2, 0xa6, 0x0c, 0xe4, 0x07, 0x20, 0x63,
+  0x9b, 0x38, 0xce, 0xfa, 0xd1, 0x3e, 0x1c, 0x71, 0xfd, 0x8a, 0xf0, 0x82,
+  0xdb, 0x4d, 0x4b, 0xfc, 0x3e, 0xbf, 0x97, 0x22, 0x26, 0x3c, 0xdc, 0xe4,
+  0x76, 0x56, 0xdb, 0x3a, 0xc7, 0xed, 0x2d, 0xc2, 0xd4, 0x09, 0x29, 0x96,
+  0xd8, 0xd7, 0x9a, 0x9c, 0x8d, 0x84, 0xf8, 0xa7, 0x55, 0xc7, 0xa8, 0x1b,
+  0x9d, 0xff, 0x00, 0xbe, 0xb4, 0xbe, 0x09, 0x3c, 0x33, 0x74, 0x86, 0x2a,
+  0x9a, 0x6b, 0x5d, 0x1d, 0x2d, 0x64, 0x78, 0x25, 0x15, 0x07, 0x3a, 0x9f,
+  0x5c, 0xeb, 0xa7, 0x87, 0x0c, 0x31, 0x4a, 0xe3, 0x15, 0x63, 0x21, 0x2d,
+  0xa2, 0x7e, 0x28, 0x8e, 0xe5, 0xc5, 0x1c, 0x5f, 0x6e, 0xa6, 0xb5, 0xd3,
+  0x93, 0x53, 0x6d, 0xb7, 0xc4, 0x31, 0x33, 0x72, 0xc6, 0x11, 0x54, 0x67,
+  0x27, 0x7d, 0x89, 0x23, 0x57, 0x2e, 0x20, 0xe2, 0x0b, 0x77, 0x0f, 0x70,
+  0xfd, 0x3d, 0x0c, 0xf5, 0x46, 0x09, 0x2a, 0x19, 0x11, 0xe4, 0x84, 0x11,
+  0xcb, 0xd8, 0xe0, 0x7a, 0x76, 0xfb, 0x0d, 0x0d, 0x5d, 0x2d, 0x55, 0x15,
+  0xae, 0x29, 0x2d, 0xf0, 0x4e, 0x9e, 0x2c, 0x71, 0x89, 0x66, 0xa7, 0x5e,
+  0x69, 0x47, 0x97, 0xb0, 0xd5, 0x16, 0xe1, 0x79, 0xe1, 0x0b, 0x4d, 0xfa,
+  0x14, 0xe2, 0x7b, 0xb4, 0xb5, 0xb2, 0x73, 0xf3, 0xd4, 0x52, 0xcf, 0x91,
+  0x27, 0x7c, 0x0f, 0x2f, 0xbf, 0x6f, 0xdb, 0x5d, 0x79, 0x79, 0xb3, 0xa7,
+  0x2f, 0x25, 0x66, 0x3d, 0x78, 0x8e, 0x4a, 0x5e, 0x21, 0xae, 0x81, 0xd5,
+  0xd7, 0xc3, 0x99, 0x94, 0x12, 0x36, 0x23, 0x27, 0x1f, 0xb0, 0xd7, 0x70,
+  0x03, 0xcb, 0x93, 0xdf, 0xb6, 0xb5, 0xcf, 0x8b, 0x5c, 0x05, 0x1d, 0xea,
+  0x55, 0xe2, 0xce, 0x0f, 0x6a, 0x6a, 0x9a, 0x49, 0x23, 0x5f, 0x16, 0x92,
+  0x39, 0x4f, 0x88, 0x08, 0x00, 0x64, 0x29, 0xea, 0x71, 0x81, 0x81, 0xbe,
+  0xda, 0xad, 0xf0, 0xd7, 0xc2, 0xbe, 0x2d, 0xbc, 0xf8, 0x73, 0x4d, 0x6e,
+  0x9a, 0xdb, 0x42, 0xcc, 0xb9, 0x9a, 0xa5, 0x08, 0x23, 0x7d, 0xf0, 0xbd,
+  0x4e, 0xde, 0xb8, 0x1a, 0x4a, 0x95, 0xba, 0x39, 0xd2, 0xc5, 0x26, 0xf8,
+  0x14, 0x70, 0x05, 0x82, 0xe1, 0xc4, 0x5c, 0x45, 0x1d, 0x2d, 0x15, 0x0c,
+  0xd5, 0x29, 0x09, 0x12, 0x4d, 0xc8, 0x36, 0x54, 0xf5, 0x3f, 0x73, 0xad,
+  0xd6, 0x9e, 0xd8, 0x96, 0x79, 0xde, 0xe5, 0x55, 0x49, 0x1c, 0xb2, 0x52,
+  0xa7, 0x96, 0x09, 0xd7, 0x99, 0x79, 0x8f, 0x42, 0x46, 0x7e, 0xfa, 0xbb,
+  0x70, 0x57, 0x08, 0xd9, 0x78, 0x2e, 0xcb, 0x15, 0x1d, 0xba, 0x27, 0x79,
+  0x1c, 0x8f, 0x1a, 0xa9, 0x90, 0x19, 0x25, 0x6f, 0x56, 0xf6, 0xf6, 0xed,
+  0xaa, 0xef, 0x1f, 0xde, 0x2d, 0xe2, 0xad, 0xa9, 0xe0, 0x90, 0x97, 0x4d,
+  0xa5, 0x0a, 0x36, 0x2c, 0x3a, 0xfe, 0xfa, 0x1c, 0xf3, 0x96, 0x3c, 0x6e,
+  0x9d, 0x36, 0x1c, 0xf1, 0xa8, 0x46, 0xd9, 0x99, 0x71, 0x6d, 0x25, 0xba,
+  0xe5, 0x57, 0x25, 0x7d, 0xca, 0x95, 0x00, 0x5c, 0xb3, 0x38, 0x24, 0x01,
+  0xeb, 0xb0, 0xd6, 0x7f, 0x76, 0x97, 0x87, 0xaa, 0xea, 0x45, 0x1d, 0x9e,
+  0x92, 0x6e, 0x42, 0x30, 0xf3, 0x4a, 0xc5, 0x53, 0xdc, 0x81, 0xe9, 0xad,
+  0x1f, 0x8c, 0x2d, 0xb3, 0xdd, 0x2c, 0x2e, 0xd4, 0xde, 0x43, 0x34, 0x80,
+  0x04, 0xc1, 0x62, 0xc3, 0x7c, 0xf4, 0xe9, 0xf9, 0xd6, 0x37, 0xc4, 0x2e,
+  0x96, 0xfb, 0x83, 0xdb, 0x23, 0xe4, 0x11, 0xc6, 0xc1, 0x26, 0x90, 0x36,
+  0x72, 0xdd, 0xf1, 0xfa, 0x63, 0xef, 0x9d, 0x63, 0xd2, 0xc3, 0x2c, 0xe1,
+  0xbf, 0x23, 0x62, 0x60, 0x7c, 0xb9, 0xd9, 0x28, 0x00, 0xf0, 0x9a, 0xa6,
+  0x6e, 0x40, 0x0a, 0x99, 0xd1, 0x0a, 0xa9, 0x1e, 0xed, 0x9d, 0x05, 0x1f,
+  0x0d, 0xd3, 0x47, 0x08, 0x8e, 0x98, 0xb4, 0x91, 0x1c, 0xee, 0xe7, 0x25,
+  0x94, 0xee, 0x0e, 0x75, 0x71, 0x86, 0x5a, 0x3a, 0x7b, 0x4b, 0x45, 0x30,
+  0x24, 0x39, 0x00, 0xc7, 0x8e, 0xa3, 0x1a, 0xa3, 0x52, 0xde, 0xa4, 0xa7,
+  0xbb, 0x56, 0x52, 0xc4, 0x85, 0x69, 0x62, 0x97, 0x08, 0x8c, 0x73, 0x81,
+  0xed, 0xae, 0x94, 0x61, 0x51, 0xa1, 0x84, 0xc6, 0x2a, 0xdb, 0x74, 0x52,
+  0x34, 0x55, 0x06, 0x58, 0x93, 0x2a, 0xb1, 0x3f, 0x55, 0x3e, 0xc7, 0x55,
+  0xcb, 0x8d, 0xce, 0xa2, 0x49, 0xd6, 0x26, 0x91, 0xd4, 0xc9, 0x83, 0x82,
+  0x7d, 0x75, 0x76, 0x8c, 0xd0, 0x5c, 0x84, 0x80, 0xb7, 0x84, 0x1c, 0x61,
+  0xb0, 0x39, 0x89, 0x3f, 0x6d, 0x4b, 0x6c, 0xf8, 0x71, 0x6b, 0xae, 0xf8,
+  0x8d, 0x4f, 0xc2, 0xf4, 0x57, 0x89, 0xbc, 0x27, 0x1e, 0x2c, 0xd5, 0x95,
+  0x09, 0x83, 0x12, 0x84, 0x2e, 0xe3, 0x04, 0xf5, 0x18, 0xc6, 0x33, 0xd7,
+  0xbe, 0x8d, 0x85, 0x13, 0x3e, 0x93, 0x0a, 0x0f, 0x88, 0x76, 0x03, 0xbf,
+  0x7d, 0x4f, 0x02, 0x2b, 0xc0, 0xac, 0x98, 0xc1, 0x03, 0x5c, 0xdd, 0xed,
+  0xd3, 0xd4, 0x5c, 0xea, 0x29, 0x52, 0x4f, 0xf7, 0x78, 0xa6, 0x60, 0x24,
+  0x3b, 0xe4, 0x02, 0x40, 0xfb, 0xed, 0xa9, 0xa1, 0x85, 0x29, 0x63, 0x31,
+  0xa9, 0x2e, 0xa0, 0xec, 0x71, 0x8d, 0x0d, 0x12, 0x71, 0x0a, 0x4a, 0x41,
+  0x25, 0x30, 0x63, 0x2c, 0x6c, 0xe8, 0xbb, 0x28, 0x3d, 0x73, 0xd0, 0x7d,
+  0xf4, 0xce, 0xdf, 0x5d, 0x4f, 0x68, 0x00, 0x13, 0x3c, 0x15, 0x41, 0xbc,
+  0xcc, 0x4e, 0xc0, 0xe0, 0xe3, 0x3e, 0xde, 0xda, 0x06, 0xd9, 0x70, 0xf0,
+  0x23, 0x92, 0x15, 0xa7, 0x89, 0xe2, 0x95, 0xd7, 0xc4, 0x56, 0x1b, 0x9e,
+  0x52, 0x0e, 0x41, 0xed, 0xd3, 0x4d, 0x2f, 0x37, 0x1a, 0x4b, 0x8f, 0x2b,
+  0x55, 0xc4, 0xa5, 0xd1, 0x3c, 0x35, 0x7c, 0x79, 0xf9, 0x47, 0x40, 0x4f,
+  0x7c, 0x0d, 0x25, 0xc7, 0xfd, 0xcb, 0x82, 0x51, 0x6d, 0xb5, 0xd6, 0x9b,
+  0xb7, 0x10, 0xdb, 0x2e, 0xd0, 0xc4, 0xaf, 0x52, 0x41, 0x8a, 0xa0, 0x83,
+  0xb3, 0xe1, 0x00, 0xc9, 0x1e, 0x9d, 0x0e, 0xa0, 0x98, 0xbd, 0x0d, 0xa6,
+  0xe9, 0x49, 0x09, 0x65, 0x9e, 0xdf, 0x5a, 0x8f, 0x4e, 0x73, 0x95, 0x72,
+  0xe7, 0x2a, 0x07, 0xa6, 0xdd, 0x74, 0xb7, 0x83, 0xee, 0x1e, 0x35, 0x3c,
+  0xdf, 0x22, 0x16, 0x39, 0xed, 0xa8, 0x65, 0x0a, 0xc3, 0x66, 0x0a, 0x30,
+  0x0f, 0xef, 0xa3, 0x2e, 0xf2, 0xc7, 0x4f, 0x75, 0xaf, 0x28, 0xea, 0x62,
+  0x8e, 0x5a, 0x5a, 0xa6, 0x03, 0xe9, 0x72, 0x46, 0x3f, 0x38, 0xc8, 0xc1,
+  0xd7, 0x47, 0x0f, 0xd0, 0xeb, 0x61, 0xfa, 0x20, 0x5a, 0xf5, 0x32, 0xf1,
+  0x2d, 0xae, 0xac, 0x4c, 0x4b, 0xc8, 0x65, 0x89, 0x8c, 0x87, 0x02, 0x26,
+  0x0c, 0x7f, 0x4c, 0xf6, 0xd7, 0xeb, 0x51, 0x92, 0x3b, 0xad, 0x7d, 0x2c,
+  0xb4, 0xc0, 0x4b, 0x1f, 0x33, 0xa2, 0x73, 0x64, 0xb1, 0x27, 0xaf, 0xe3,
+  0x44, 0x5c, 0x26, 0xb6, 0x8b, 0x64, 0x74, 0xef, 0x1c, 0x32, 0x4b, 0x0c,
+  0xb2, 0x31, 0x95, 0x81, 0x39, 0x2e, 0x49, 0x05, 0xbe, 0xe3, 0x03, 0xbe,
+  0x87, 0xbc, 0xcf, 0x53, 0x55, 0x73, 0xb5, 0x5c, 0xa8, 0xd3, 0xc2, 0xae,
+  0xa8, 0x85, 0x4c, 0xa1, 0x4e, 0x39, 0x59, 0x47, 0x9b, 0x56, 0x37, 0x78,
+  0x3a, 0x49, 0x4c, 0xd5, 0x69, 0x55, 0x31, 0x12, 0xf9, 0xc2, 0xb8, 0x71,
+  0xf4, 0x8f, 0x61, 0xe9, 0xef, 0xdf, 0x44, 0x5e, 0xd6, 0x1b, 0x55, 0xfe,
+  0x3a, 0xb1, 0x00, 0x9a, 0x9e, 0x78, 0x73, 0x4e, 0x84, 0xf9, 0x47, 0x62,
+  0x71, 0xae, 0x78, 0xba, 0x2a, 0x2a, 0xc8, 0xed, 0xd5, 0xc9, 0x34, 0x69,
+  0x55, 0x53, 0x2f, 0x2c, 0xab, 0xd0, 0x64, 0x1f, 0xaf, 0x1e, 0x9b, 0x6f,
+  0xf7, 0xd0, 0xf7, 0x46, 0x79, 0xe5, 0x89, 0x6a, 0x66, 0x1c, 0xf4, 0x8a,
+  0xc8, 0x54, 0x0d, 0x86, 0x48, 0x23, 0x07, 0xdf, 0xae, 0x80, 0xb4, 0x75,
+  0x4b, 0xce, 0xed, 0x8a, 0xfa, 0xc9, 0x8b, 0xb6, 0x5a, 0x34, 0xce, 0x54,
+  0x2f, 0x6d, 0xb5, 0x30, 0x64, 0xab, 0xb7, 0x24, 0x40, 0x78, 0x8c, 0x93,
+  0x34, 0x9b, 0x0f, 0xa7, 0xae, 0x73, 0xfa, 0xea, 0x0a, 0x68, 0x96, 0x48,
+  0x92, 0x44, 0x99, 0x54, 0x3f, 0xfc, 0x42, 0xc7, 0x04, 0x2e, 0x40, 0xdb,
+  0xdb, 0x5f, 0x60, 0xad, 0x6a, 0x39, 0xe4, 0xf9, 0x44, 0x0f, 0x02, 0xc5,
+  0xcc, 0x18, 0xaf, 0x28, 0xf3, 0x13, 0xe6, 0x03, 0xbf, 0x7d, 0x40, 0x8f,
+  0xb1, 0x4a, 0xa6, 0x65, 0x54, 0x81, 0x23, 0x89, 0x37, 0x77, 0xc7, 0x99,
+  0xbd, 0x4e, 0xbe, 0x32, 0x40, 0x0c, 0x8c, 0xbc, 0xc5, 0x7e, 0xac, 0x0e,
+  0xa7, 0x3d, 0xc9, 0xed, 0xa1, 0x67, 0x50, 0x70, 0xb1, 0x33, 0x3c, 0x60,
+  0x82, 0x09, 0xed, 0xae, 0xe2, 0x6c, 0x4e, 0x59, 0xc0, 0x0f, 0xb6, 0x0f,
+  0x6c, 0xfa, 0xe8, 0x4b, 0x25, 0x74, 0x75, 0x91, 0x11, 0x5b, 0x9d, 0xd7,
+  0x0c, 0xac, 0xdd, 0x7d, 0xb1, 0xa8, 0xf3, 0x5f, 0x5d, 0x70, 0x5a, 0x58,
+  0x55, 0xe5, 0xab, 0x76, 0x21, 0x63, 0x5d, 0xce, 0x74, 0x3d, 0x65, 0x4b,
+  0x53, 0xd5, 0xf8, 0xce, 0xa6, 0x47, 0xe5, 0xd8, 0x83, 0xb6, 0x7d, 0xf5,
+  0xf7, 0x86, 0xae, 0x95, 0x14, 0xd7, 0x46, 0x9d, 0x27, 0x6a, 0x4a, 0xb7,
+  0x23, 0xe5, 0xe4, 0x0e, 0x31, 0xcd, 0x9d, 0xc6, 0x71, 0xb1, 0x3a, 0x10,
+  0x33, 0xe7, 0x8c, 0x29, 0x7b, 0x2f, 0x7c, 0x39, 0xc0, 0x4c, 0x1a, 0xdb,
+  0xc4, 0x86, 0xe5, 0x4d, 0x70, 0x73, 0x3a, 0xac, 0x90, 0x8d, 0xfc, 0x3e,
+  0xdb, 0x83, 0xd0, 0xab, 0x63, 0xf4, 0xd2, 0xa4, 0x8e, 0x6a, 0xaf, 0x88,
+  0x57, 0x08, 0x3a, 0xcb, 0x55, 0x2b, 0x73, 0x12, 0x37, 0xc8, 0x03, 0x1a,
+  0xe2, 0x5b, 0xa5, 0x55, 0x35, 0x5d, 0x75, 0xc3, 0x15, 0x14, 0xb7, 0x29,
+  0x4f, 0x37, 0x82, 0xbb, 0x01, 0x9d, 0xd8, 0xfa, 0x0d, 0xfb, 0x63, 0x5f,
+  0x78, 0x3f, 0x88, 0x3e, 0x43, 0x88, 0x23, 0xe2, 0x23, 0x49, 0x1d, 0x5c,
+  0xa0, 0xb1, 0x71, 0x2f, 0x46, 0xe6, 0x03, 0x39, 0x03, 0xa1, 0xdb, 0x3a,
+  0x46, 0x59, 0x5b, 0x38, 0xd9, 0x72, 0xca, 0x6f, 0x93, 0x42, 0xac, 0x92,
+  0xba, 0xcd, 0x65, 0x9e, 0xd6, 0x64, 0x91, 0x59, 0xa0, 0x1e, 0x33, 0x74,
+  0xcf, 0x72, 0x3d, 0xfa, 0x6b, 0x2c, 0xb9, 0x55, 0x86, 0xa8, 0xf1, 0xa2,
+  0x8d, 0xa3, 0x47, 0xc3, 0x60, 0x9c, 0x63, 0x3d, 0x75, 0xa9, 0xf1, 0x6f,
+  0x19, 0xd9, 0xea, 0xed, 0x50, 0xd4, 0xd9, 0x96, 0xad, 0x6b, 0x6a, 0x0e,
+  0x25, 0x8e, 0xa1, 0xb9, 0xd6, 0x9f, 0xae, 0x79, 0x4e, 0x37, 0x27, 0xb1,
+  0xd6, 0x43, 0x7f, 0xa8, 0xa5, 0x15, 0x8a, 0xa3, 0x69, 0x79, 0xb0, 0xd8,
+  0x1b, 0x03, 0xdb, 0x3f, 0x7f, 0x5d, 0x2a, 0x9d, 0xee, 0x62, 0xb6, 0x96,
+  0xba, 0xbb, 0x6b, 0x52, 0xaa, 0x2b, 0xc7, 0x24, 0x53, 0x90, 0x09, 0x46,
+  0xe8, 0x41, 0x00, 0x86, 0xcf, 0x7c, 0xe7, 0x57, 0x7a, 0x4e, 0x1f, 0xb9,
+  0x57, 0xf0, 0x4d, 0x24, 0x56, 0xc0, 0x90, 0xab, 0xb2, 0xb4, 0xb0, 0xf4,
+  0x69, 0x64, 0xc9, 0xc3, 0x13, 0xfd, 0x5b, 0x74, 0xf4, 0x1a, 0x4b, 0xc4,
+  0x75, 0x90, 0x49, 0x6e, 0xb7, 0x45, 0xf2, 0x75, 0x91, 0x5c, 0x69, 0xd7,
+  0x13, 0x89, 0x36, 0x55, 0x42, 0xbe, 0x51, 0xef, 0xb6, 0x0f, 0xd8, 0x8d,
+  0x1f, 0x65, 0xe2, 0x2a, 0xd9, 0x6a, 0x22, 0xad, 0x7a, 0xd6, 0x2b, 0x00,
+  0x08, 0xc8, 0x48, 0x20, 0xa0, 0xec, 0x06, 0xda, 0xe6, 0xad, 0xc9, 0xbb,
+  0x42, 0xd2, 0x57, 0xc8, 0xa9, 0xad, 0x97, 0x84, 0xbb, 0xc1, 0x6e, 0xf9,
+  0x59, 0x3e, 0x6a, 0xa1, 0x7f, 0x92, 0x24, 0x1c, 0xbc, 0xde, 0xfa, 0x60,
+  0x9c, 0x15, 0xc6, 0xd4, 0xb5, 0x22, 0xba, 0x8e, 0x23, 0x0c, 0xd1, 0xe5,
+  0x87, 0xcb, 0x4c, 0x39, 0x87, 0xb6, 0x36, 0xdb, 0x45, 0x7c, 0x53, 0xb8,
+  0x51, 0x56, 0xd3, 0x43, 0x74, 0xb7, 0xd5, 0xab, 0xba, 0x1e, 0x5e, 0x50,
+  0x71, 0x2a, 0x12, 0xa3, 0xbf, 0xa6, 0x47, 0xe3, 0xf7, 0xd4, 0xfc, 0x01,
+  0xf1, 0x17, 0xf8, 0x75, 0x9a, 0x9e, 0xdf, 0x7a, 0x54, 0x92, 0x30, 0x4b,
+  0x19, 0x17, 0xeb, 0x52, 0x77, 0xdf, 0xd7, 0x3a, 0x67, 0xd5, 0x59, 0x36,
+  0xc7, 0xf4, 0x0b, 0xc7, 0x75, 0x33, 0x7f, 0xe8, 0x1b, 0x7c, 0x0b, 0x48,
+  0xb6, 0xea, 0x88, 0x1b, 0x9e, 0xb6, 0x34, 0x3b, 0x9c, 0x82, 0x01, 0xc7,
+  0xf7, 0xfb, 0x8d, 0x67, 0x96, 0x88, 0x8b, 0xba, 0x21, 0x84, 0x4a, 0x59,
+  0xb1, 0x82, 0x76, 0x24, 0xed, 0xad, 0x42, 0xb6, 0xb6, 0xd3, 0xc5, 0x6d,
+  0x55, 0x47, 0x14, 0xae, 0x6a, 0x6b, 0x26, 0x39, 0x2a, 0x0b, 0x10, 0xa3,
+  0xa0, 0xfc, 0x0c, 0x0d, 0x41, 0x27, 0x0a, 0xd3, 0x5a, 0x28, 0x8d, 0x1d,
+  0x24, 0x86, 0x3a, 0x92, 0xb9, 0xf1, 0x25, 0x05, 0x5b, 0x20, 0x74, 0xdf,
+  0xa0, 0xed, 0xa4, 0xe4, 0xd5, 0x42, 0x0d, 0x2f, 0x61, 0x49, 0xf0, 0x33,
+  0x36, 0xeb, 0x3a, 0xdb, 0x95, 0xad, 0x51, 0x0a, 0x0a, 0xe9, 0x11, 0x01,
+  0xf1, 0x10, 0x18, 0xf3, 0x8d, 0xf6, 0x18, 0xc8, 0x27, 0xd7, 0x54, 0xcb,
+  0x5d, 0xee, 0xe5, 0x1f, 0x15, 0xa8, 0x48, 0x29, 0x62, 0x11, 0x31, 0x59,
+  0x84, 0x3e, 0x50, 0x18, 0x67, 0x24, 0x2f, 0xa6, 0xd8, 0xeb, 0xdf, 0x42,
+  0x53, 0xf1, 0x15, 0x42, 0xdc, 0xe9, 0x6d, 0xd7, 0x98, 0xde, 0xa2, 0x88,
+  0xcb, 0xe1, 0x1e, 0x71, 0xba, 0x12, 0x71, 0xb1, 0xd1, 0x9c, 0x55, 0xc2,
+  0x15, 0x10, 0xc5, 0x51, 0x78, 0x86, 0xa1, 0x63, 0x59, 0x6a, 0x3c, 0x2a,
+  0x68, 0xc3, 0x79, 0xe4, 0x52, 0x7a, 0xff, 0x00, 0x6f, 0xd3, 0x4f, 0x96,
+  0x6d, 0xd2, 0xda, 0xd5, 0x58, 0x26, 0xa4, 0xb7, 0x1a, 0x99, 0xa9, 0x4d,
+  0xb1, 0xdc, 0xa8, 0x68, 0xc7, 0x20, 0x04, 0x0c, 0x8d, 0x86, 0xdf, 0x8d,
+  0x53, 0xf8, 0xcb, 0xe1, 0x95, 0x0d, 0xe0, 0x1a, 0xd9, 0xaa, 0x62, 0x82,
+  0x45, 0x89, 0x9e, 0x01, 0xcb, 0xcc, 0xe1, 0x80, 0x52, 0x03, 0xb0, 0xce,
+  0x17, 0xd7, 0xb0, 0x3a, 0xb2, 0xf0, 0x35, 0xb1, 0xae, 0xb7, 0x8a, 0xfa,
+  0x5a, 0xfb, 0x83, 0x47, 0x4f, 0xcc, 0x7e, 0x5d, 0x42, 0x85, 0x20, 0xe7,
+  0xfe, 0x63, 0xbf, 0xe3, 0x56, 0x1a, 0xab, 0x5d, 0x65, 0xbe, 0xad, 0x05,
+  0x6d, 0x23, 0x4f, 0x40, 0xaa, 0x73, 0x32, 0xb0, 0xe4, 0x60, 0x08, 0xc0,
+  0x65, 0x1d, 0x88, 0xdf, 0x1e, 0xda, 0xdd, 0x2c, 0x92, 0x8b, 0xb8, 0xfa,
+  0x1f, 0x14, 0xe2, 0xdb, 0x64, 0x1f, 0x02, 0x6d, 0xf5, 0x94, 0xb6, 0x39,
+  0xe2, 0x92, 0x9a, 0x96, 0x8a, 0xa6, 0x96, 0x51, 0x0b, 0x2c, 0x1b, 0xc1,
+  0x56, 0xa1, 0x47, 0xf3, 0x8b, 0xff, 0x00, 0x5b, 0x13, 0x91, 0xb6, 0x02,
+  0xf4, 0xc1, 0xd6, 0x93, 0x1f, 0x2c, 0xf3, 0x2c, 0x09, 0x51, 0x0a, 0xc9,
+  0x0e, 0x0c, 0x91, 0x23, 0x73, 0x11, 0x9d, 0xc1, 0x3d, 0x3a, 0xe9, 0x2d,
+  0x3a, 0x45, 0x05, 0xbe, 0x3a, 0xaa, 0x78, 0x21, 0x8e, 0x49, 0x10, 0x78,
+  0x66, 0x30, 0x04, 0x7e, 0x1e, 0x41, 0xd8, 0x7f, 0x49, 0xff, 0x00, 0x4d,
+  0x35, 0x88, 0x40, 0x8c, 0x95, 0x2a, 0x86, 0x42, 0x00, 0x0e, 0xfc, 0xb8,
+  0x61, 0x8e, 0x85, 0xbd, 0x86, 0xff, 0x00, 0xae, 0xab, 0x16, 0x69, 0x4a,
+  0x5e, 0x46, 0xb5, 0x2e, 0x06, 0x53, 0xc9, 0xe1, 0xc6, 0x0b, 0xc6, 0xce,
+  0x73, 0x8e, 0x55, 0x19, 0x24, 0x74, 0xce, 0xab, 0x75, 0xfc, 0x15, 0x6e,
+  0xa9, 0xa9, 0x96, 0x7a, 0x87, 0x91, 0xfc, 0x46, 0x27, 0x94, 0x01, 0xdf,
+  0xaf, 0x6d, 0x58, 0x62, 0x95, 0x5e, 0x36, 0xa8, 0xf1, 0xd5, 0xd4, 0x8f,
+  0x21, 0x1b, 0x00, 0x3e, 0xfa, 0x1f, 0x9a, 0x69, 0xf2, 0x2a, 0x13, 0x95,
+  0x41, 0xdc, 0xab, 0xe4, 0x1f, 0x6e, 0x9f, 0xbf, 0xb6, 0xb4, 0x67, 0xc3,
+  0x8b, 0x2a, 0x4a, 0x6a, 0xca, 0xc8, 0x93, 0x5c, 0x95, 0x39, 0xf8, 0x3e,
+  0x3a, 0x4b, 0x6d, 0xc9, 0xa0, 0x91, 0x9e, 0xa4, 0xd3, 0xca, 0xb6, 0xf5,
+  0x6d, 0x96, 0x1f, 0x29, 0x23, 0x1f, 0xf3, 0x6d, 0x9c, 0xeb, 0xc7, 0xdc,
+  0x43, 0x62, 0xab, 0xe7, 0xa8, 0x84, 0x41, 0x21, 0x97, 0x99, 0x94, 0xaf,
+  0x2e, 0xfc, 0xc3, 0xb7, 0xed, 0xaf, 0x77, 0xca, 0x95, 0x02, 0xa9, 0xa7,
+  0x82, 0x68, 0xc4, 0x0c, 0x9e, 0x60, 0xc3, 0x3e, 0x60, 0x46, 0xff, 0x00,
+  0xa6, 0x75, 0x87, 0xfc, 0x49, 0xe3, 0xa8, 0x24, 0xbb, 0x56, 0xc7, 0x45,
+  0x47, 0x4d, 0x1c, 0x48, 0x8e, 0xa2, 0x52, 0x3c, 0xf2, 0x49, 0xd3, 0x9b,
+  0x1e, 0xdd, 0x89, 0xd6, 0x6d, 0x54, 0xfe, 0x24, 0x9c, 0x7f, 0xe0, 0xcd,
+  0x9f, 0x6a, 0x4a, 0xcf, 0x2f, 0x5b, 0xae, 0x97, 0x3a, 0x54, 0xf9, 0x67,
+  0x93, 0x23, 0x3c, 0xbc, 0x8e, 0x33, 0xbf, 0xa6, 0xb8, 0xa5, 0xa5, 0x34,
+  0xb3, 0xbc, 0x8a, 0x9f, 0xcd, 0x99, 0xc8, 0x63, 0x9f, 0xa0, 0x13, 0xd7,
+  0xfe, 0x9a, 0xb8, 0x52, 0x59, 0xd2, 0xb6, 0xbc, 0xd7, 0x54, 0xc2, 0x4c,
+  0x4b, 0xbc, 0xac, 0xc7, 0xeb, 0x7e, 0xd8, 0x1f, 0xae, 0x84, 0xe2, 0x16,
+  0x4a, 0x6a, 0xb4, 0x0b, 0x4c, 0x73, 0xca, 0x0f, 0x9b, 0xa3, 0x7b, 0xea,
+  0xe1, 0x97, 0x7c, 0xb6, 0xc4, 0x5c, 0x64, 0x7c, 0x9e, 0xd6, 0x28, 0xea,
+  0xed, 0x95, 0x14, 0x22, 0x49, 0x69, 0x84, 0x45, 0xdc, 0x63, 0x3c, 0xc5,
+  0x4f, 0x31, 0x20, 0x7e, 0x40, 0xfc, 0xeb, 0xef, 0x1b, 0x5e, 0x45, 0xf7,
+  0x88, 0xab, 0x6f, 0x53, 0x40, 0xb4, 0xf3, 0xd5, 0xc6, 0xbc, 0xc0, 0x28,
+  0x5e, 0x76, 0x00, 0x02, 0xc5, 0x47, 0x4c, 0xe0, 0x6d, 0xed, 0xab, 0x67,
+  0xc2, 0xeb, 0xa4, 0x94, 0xa6, 0xe7, 0xc4, 0x35, 0x53, 0x28, 0x92, 0x9a,
+  0x94, 0xd3, 0xd3, 0xd3, 0x2c, 0x63, 0x05, 0x1b, 0x63, 0xe6, 0x3b, 0x2f,
+  0xb7, 0xb9, 0xce, 0xb3, 0xc7, 0xb5, 0xde, 0xe4, 0xab, 0x68, 0x24, 0xa8,
+  0xf1, 0xa9, 0x0c, 0xd9, 0x4e, 0x67, 0x1f, 0x56, 0xfe, 0xbe, 0x99, 0x23,
+  0x4e, 0x8c, 0xd3, 0x93, 0x8b, 0xf4, 0x35, 0x31, 0xaf, 0xc9, 0x5d, 0x29,
+  0x78, 0x3f, 0xe6, 0x40, 0xa4, 0x92, 0x8a, 0x49, 0x15, 0x32, 0x79, 0x0b,
+  0xc6, 0xcc, 0x33, 0x90, 0x33, 0xcc, 0x3f, 0xb6, 0xab, 0xd5, 0xd0, 0x3c,
+  0x10, 0x09, 0x26, 0x60, 0x99, 0x19, 0x03, 0xae, 0xfa, 0x79, 0x6a, 0x92,
+  0xa2, 0xd7, 0x72, 0x6a, 0x1a, 0xc5, 0x3c, 0x92, 0x31, 0xe5, 0xcf, 0x4c,
+  0xeb, 0xe7, 0x19, 0xa0, 0xae, 0x14, 0xb4, 0xf4, 0xa8, 0x8a, 0xc6, 0x4e,
+  0x56, 0x23, 0xaf, 0xa6, 0x95, 0x1c, 0x8f, 0xe4, 0x49, 0xf4, 0x0c, 0xa6,
+  0x55, 0x69, 0x26, 0x67, 0x5e, 0x63, 0xf4, 0xab, 0x6d, 0xf6, 0xd3, 0xfa,
+  0x51, 0x1a, 0x2f, 0x89, 0x50, 0x39, 0xc3, 0x79, 0x95, 0x71, 0xd4, 0x1d,
+  0x7e, 0xaa, 0xe1, 0x69, 0x6d, 0xf4, 0x80, 0xcb, 0x22, 0x78, 0xc1, 0xfc,
+  0xb8, 0x18, 0xcf, 0x5d, 0x08, 0xbe, 0x24, 0x8e, 0x90, 0xbc, 0x6c, 0xb2,
+  0x0d, 0x97, 0x1d, 0x3f, 0x5d, 0x33, 0xe4, 0x53, 0x57, 0x12, 0xdf, 0x28,
+  0xb4, 0xf0, 0xf4, 0x94, 0x13, 0x19, 0x3c, 0x68, 0xca, 0x96, 0x25, 0x51,
+  0x14, 0xec, 0x17, 0x07, 0xaf, 0xae, 0x74, 0x75, 0x6d, 0x03, 0x57, 0x45,
+  0x5b, 0x54, 0x58, 0xe2, 0xa6, 0x89, 0x5c, 0x05, 0x5e, 0x9c, 0x88, 0x39,
+  0xb3, 0xe9, 0xb9, 0x1a, 0x4b, 0x65, 0x49, 0x61, 0xaa, 0xa3, 0x6e, 0x61,
+  0xcf, 0x14, 0xca, 0x18, 0x0e, 0x99, 0x27, 0xd7, 0x57, 0x35, 0xc4, 0x13,
+  0x5d, 0x28, 0xe7, 0x40, 0x3c, 0x0a, 0x79, 0xd4, 0x64, 0xe3, 0x98, 0x92,
+  0xb8, 0xfb, 0x75, 0x3a, 0x76, 0x9f, 0xa6, 0x6d, 0xd1, 0xcf, 0x72, 0x6b,
+  0xf4, 0x53, 0x78, 0x96, 0x70, 0xb6, 0x1a, 0x48, 0x51, 0xb9, 0x52, 0xa9,
+  0xe3, 0x9c, 0xc6, 0x06, 0xd9, 0x20, 0xab, 0x7e, 0xe3, 0x4c, 0xa8, 0xf0,
+  0xb5, 0x16, 0xe7, 0xa6, 0x01, 0x3c, 0x02, 0x32, 0xec, 0x70, 0x3a, 0x64,
+  0x8f, 0xdb, 0x4b, 0x67, 0x0c, 0x28, 0x78, 0x6e, 0x29, 0xd5, 0xe4, 0x09,
+  0x3d, 0x44, 0xc5, 0x33, 0xb2, 0xa0, 0x61, 0x8c, 0x1f, 0xc6, 0x3b, 0x68,
+  0xc9, 0xe6, 0x49, 0x29, 0x93, 0xe5, 0x61, 0x68, 0x64, 0x9e, 0x62, 0xdc,
+  0x85, 0x89, 0xc6, 0x4e, 0x4e, 0xfd, 0xc6, 0x35, 0xa0, 0xd7, 0x0e, 0xc1,
+  0x69, 0x61, 0x96, 0xe5, 0x7b, 0x86, 0x9a, 0x47, 0x1f, 0x2e, 0xb2, 0x12,
+  0xa4, 0x0d, 0x94, 0x13, 0x9d, 0xb4, 0x5f, 0x11, 0xd2, 0x53, 0xc5, 0x7d,
+  0x16, 0xda, 0x66, 0x73, 0x1f, 0x22, 0xb4, 0x92, 0x36, 0xf8, 0xdb, 0x6f,
+  0xfc, 0x6a, 0x5b, 0x4d, 0x5a, 0xd0, 0x71, 0x07, 0x8a, 0xcd, 0x94, 0x73,
+  0xe4, 0x21, 0x76, 0x39, 0xdc, 0x0c, 0x6a, 0x6b, 0xd2, 0x54, 0x41, 0x5a,
+  0x2a, 0x4c, 0x7c, 0xa6, 0xb0, 0x99, 0x39, 0xc3, 0x67, 0x94, 0xff, 0x00,
+  0xe3, 0x3b, 0x68, 0x46, 0x24, 0x2c, 0x8a, 0x8e, 0x59, 0x88, 0x39, 0x64,
+  0xe4, 0x63, 0xc8, 0xca, 0x7e, 0x9c, 0x76, 0xd7, 0x10, 0x3a, 0xa8, 0x9a,
+  0x22, 0x87, 0x2c, 0xc0, 0x47, 0x83, 0xb0, 0xc6, 0x76, 0xf7, 0x1d, 0x74,
+  0x6b, 0xf8, 0x2d, 0x0a, 0xd1, 0xcb, 0x2a, 0x81, 0x36, 0x4a, 0xc8, 0xc3,
+  0x02, 0x3f, 0x71, 0xe8, 0x4e, 0x82, 0xf9, 0x79, 0x10, 0xc9, 0x07, 0x3a,
+  0x48, 0xc8, 0xde, 0x46, 0x56, 0xce, 0xdd, 0xb5, 0x44, 0x44, 0x82, 0x28,
+  0xd5, 0x9d, 0x64, 0x8f, 0xcf, 0x9c, 0x82, 0x3a, 0x69, 0x6d, 0x73, 0xc9,
+  0x33, 0x98, 0xd5, 0xb0, 0xca, 0x4e, 0xfe, 0x9b, 0xed, 0xfb, 0x68, 0xdb,
+  0xa8, 0x9e, 0x9c, 0xe2, 0x56, 0x1c, 0xdd, 0x48, 0xce, 0x96, 0x54, 0x4a,
+  0x42, 0xc4, 0x85, 0x0f, 0x34, 0xad, 0x93, 0x9d, 0x86, 0x35, 0x0b, 0x25,
+  0x96, 0x70, 0x5d, 0x28, 0x9a, 0x97, 0xc3, 0x66, 0x65, 0x65, 0x98, 0x92,
+  0x72, 0x3e, 0xda, 0x02, 0xa6, 0x08, 0xed, 0xf5, 0xb2, 0x4b, 0x5c, 0xa8,
+  0xc0, 0xf9, 0x57, 0x0b, 0x80, 0x17, 0xfe, 0x5f, 0x4d, 0x18, 0x55, 0x16,
+  0x55, 0x45, 0x05, 0x50, 0xae, 0x0e, 0x0e, 0xea, 0x73, 0xd7, 0x45, 0x9b,
+  0x19, 0xbb, 0x55, 0xa4, 0xd3, 0xcb, 0x27, 0xf0, 0xda, 0x75, 0xe6, 0xcb,
+  0xff, 0x00, 0xee, 0x11, 0xd8, 0x69, 0x51, 0x9b, 0x94, 0xdc, 0x59, 0xc8,
+  0xc9, 0xfe, 0xa3, 0x62, 0xf1, 0x25, 0x7d, 0x7d, 0x4c, 0x13, 0xd1, 0xc9,
+  0x57, 0x94, 0x01, 0x15, 0x49, 0xe7, 0x3c, 0xaa, 0x31, 0x81, 0xd3, 0x6d,
+  0xb1, 0xab, 0xbd, 0x8a, 0xd9, 0x67, 0xb8, 0x45, 0x14, 0x0b, 0x77, 0x36,
+  0xea, 0xc7, 0x20, 0x3d, 0x25, 0x64, 0x4c, 0xa4, 0xb9, 0xea, 0x73, 0xd3,
+  0x1a, 0xad, 0xcb, 0x73, 0x92, 0x9d, 0xdc, 0xdb, 0xff, 0x00, 0xdd, 0x83,
+  0x80, 0x14, 0xa8, 0xf3, 0x22, 0x0e, 0x8a, 0x0f, 0x6e, 0xbf, 0x9d, 0x7e,
+  0xa7, 0x79, 0x2b, 0x2b, 0x60, 0x85, 0xe6, 0xe7, 0xfe, 0x50, 0x2c, 0xcc,
+  0x77, 0x2e, 0xcc, 0xa3, 0x7f, 0x5f, 0xdb, 0xa6, 0xb3, 0xe4, 0xed, 0xc8,
+  0x43, 0x34, 0x6e, 0x20, 0xe0, 0x9b, 0xcd, 0x92, 0x9a, 0x8e, 0x68, 0x0d,
+  0x3d, 0x5c, 0x53, 0xb3, 0x2a, 0x3a, 0x36, 0xcb, 0x82, 0x37, 0x39, 0xe8,
+  0x7d, 0xbd, 0x06, 0x97, 0xd1, 0x59, 0xb8, 0x21, 0xaa, 0xa3, 0xfe, 0x2d,
+  0x78, 0xaa, 0x17, 0x29, 0x58, 0x44, 0xf2, 0xd3, 0xd3, 0x8f, 0x06, 0x39,
+  0x0b, 0x64, 0x9c, 0x9e, 0xa0, 0x0f, 0x4d, 0xbb, 0xe7, 0x7d, 0x36, 0xe3,
+  0x98, 0x6d, 0x16, 0x1e, 0x0f, 0xb4, 0xc3, 0x6e, 0xbc, 0x9a, 0x9b, 0x88,
+  0xcb, 0xd4, 0x88, 0x2b, 0x4c, 0x91, 0xc6, 0x40, 0xc3, 0x02, 0x9b, 0x80,
+  0x49, 0x23, 0x70, 0x7d, 0x46, 0xfa, 0xa5, 0xd0, 0xcb, 0x35, 0x1f, 0x0a,
+  0xd5, 0xf1, 0x19, 0xa6, 0xa5, 0x25, 0x26, 0x14, 0x50, 0x16, 0x07, 0x31,
+  0xc8, 0xe0, 0xb7, 0x30, 0x19, 0xdc, 0x80, 0xac, 0x37, 0xdb, 0x71, 0xa1,
+  0x4e, 0xda, 0x41, 0x17, 0x9a, 0x9b, 0x1f, 0x10, 0xf0, 0xf5, 0x75, 0x5d,
+  0x3b, 0xdc, 0x29, 0x65, 0xa2, 0x58, 0x0c, 0xef, 0x24, 0xd3, 0xa9, 0x32,
+  0x8c, 0x80, 0x15, 0x41, 0xdf, 0x9b, 0x71, 0xb0, 0xed, 0x9d, 0x01, 0x0d,
+  0x86, 0xdd, 0x7c, 0x09, 0x4f, 0x6f, 0xba, 0xc1, 0x43, 0x79, 0x6f, 0x39,
+  0xa7, 0xa8, 0xa8, 0x01, 0x1f, 0x62, 0x72, 0x18, 0xec, 0x35, 0x8e, 0x54,
+  0xdc, 0x6a, 0x65, 0xac, 0x53, 0x56, 0xcf, 0x50, 0x39, 0xc1, 0x2a, 0x64,
+  0x6c, 0xbf, 0xa0, 0xce, 0x75, 0xa0, 0xf0, 0xa5, 0xc7, 0x87, 0x63, 0xe2,
+  0x2a, 0x1b, 0x3d, 0xda, 0x2a, 0xc8, 0x9a, 0x66, 0x22, 0xa2, 0xa1, 0x9f,
+  0x9c, 0xc5, 0xe5, 0x25, 0x79, 0x32, 0x3e, 0x9c, 0x80, 0x33, 0xef, 0xa3,
+  0x7a, 0x7e, 0x77, 0x5f, 0xa0, 0x06, 0x75, 0xf3, 0x9f, 0xe1, 0xe2, 0x9d,
+  0x92, 0x9e, 0x27, 0xa3, 0x8b, 0x96, 0x49, 0xd4, 0x61, 0x64, 0x3d, 0x4e,
+  0x4f, 0xf5, 0x1f, 0x4f, 0xb6, 0xa1, 0xa8, 0xe1, 0x4b, 0xe9, 0x34, 0x72,
+  0x4d, 0x4b, 0x3c, 0x26, 0xa9, 0x99, 0x51, 0x66, 0x1c, 0xac, 0x40, 0xc7,
+  0x9b, 0x97, 0xa8, 0x19, 0x23, 0x7f, 0xbe, 0x99, 0xf0, 0x2f, 0x0f, 0x1e,
+  0x26, 0xe3, 0x43, 0x40, 0x2a, 0x9e, 0x9e, 0x3a, 0x58, 0x9e, 0xa3, 0xc6,
+  0x76, 0x0d, 0xba, 0x83, 0xca, 0x77, 0xdb, 0x39, 0xc7, 0x5e, 0xc4, 0xe9,
+  0x25, 0xff, 0x00, 0x8c, 0x38, 0x8a, 0xe5, 0x75, 0x79, 0x2b, 0xef, 0x73,
+  0xd4, 0x54, 0xc1, 0x21, 0x11, 0xb2, 0xbe, 0x02, 0x80, 0x71, 0xb6, 0x3f,
+  0xcb, 0x58, 0x96, 0x18, 0xf3, 0x40, 0x51, 0xa1, 0xda, 0xb8, 0x66, 0xdd,
+  0xc3, 0xd6, 0x88, 0xea, 0x6b, 0x0b, 0xc9, 0x73, 0x38, 0x6e, 0x68, 0xd8,
+  0xe2, 0x36, 0xc6, 0xd8, 0x00, 0x8d, 0xf7, 0xd0, 0x95, 0x97, 0x5a, 0xfa,
+  0xee, 0x78, 0xc5, 0xda, 0x49, 0x5d, 0x5b, 0x1e, 0x15, 0x46, 0xdc, 0xd8,
+  0xf4, 0x3a, 0x93, 0xe1, 0x2f, 0xc4, 0x1a, 0x48, 0xee, 0xf4, 0xf4, 0x7c,
+  0x5d, 0x04, 0x55, 0x49, 0x2b, 0x11, 0x15, 0x7c, 0x99, 0x2f, 0x19, 0x6e,
+  0xcf, 0x9c, 0xf3, 0x2f, 0xbf, 0x6d, 0x5d, 0xea, 0xbe, 0x1e, 0x56, 0x9b,
+  0xb2, 0x5f, 0x38, 0x76, 0xa2, 0x95, 0xff, 0x00, 0xdf, 0xa4, 0x22, 0x19,
+  0x10, 0x05, 0xe5, 0x0c, 0x70, 0x41, 0x07, 0x07, 0xa7, 0x4c, 0x74, 0x3e,
+  0xda, 0x46, 0x5d, 0x23, 0x6e, 0xd1, 0x7f, 0x13, 0x7d, 0x18, 0xe2, 0xdb,
+  0xa7, 0xaa, 0xe2, 0x78, 0x3c, 0x59, 0x4c, 0x30, 0x49, 0x2f, 0x34, 0xaa,
+  0xbe, 0xa3, 0x39, 0x1f, 0xae, 0xae, 0x15, 0x74, 0xf4, 0x44, 0x81, 0x2b,
+  0xca, 0xd0, 0xe0, 0x8e, 0x5e, 0x6e, 0xa5, 0xba, 0x9f, 0xbe, 0xb4, 0xb4,
+  0xf8, 0x71, 0x47, 0x53, 0x09, 0x17, 0x49, 0x07, 0xce, 0xb3, 0x16, 0x9a,
+  0xaa, 0x12, 0x54, 0x6e, 0x09, 0x01, 0x50, 0x92, 0x01, 0x1b, 0x7d, 0xc6,
+  0x75, 0x8c, 0xdf, 0x66, 0xfe, 0x1f, 0x7a, 0xaa, 0xb3, 0xf8, 0xce, 0xe6,
+  0x09, 0x0a, 0xf3, 0xba, 0x72, 0xe4, 0x82, 0x46, 0xc3, 0x27, 0x6d, 0x6b,
+  0xc3, 0x8a, 0x4b, 0xec, 0xca, 0x78, 0xe8, 0xd9, 0xf8, 0x53, 0x86, 0xe8,
+  0xff, 0x00, 0x88, 0x53, 0xf1, 0x03, 0xd7, 0xc8, 0xa5, 0x11, 0x79, 0x60,
+  0x31, 0x82, 0x55, 0xb9, 0x40, 0x2c, 0x09, 0x27, 0xfb, 0x6a, 0xd9, 0x56,
+  0x22, 0x92, 0x05, 0x85, 0x2b, 0x0a, 0xcd, 0xe5, 0x7f, 0x13, 0x3e, 0x63,
+  0x83, 0xf4, 0x91, 0xd3, 0xee, 0x74, 0x8e, 0x9a, 0xa2, 0xa6, 0x9e, 0xc5,
+  0x48, 0xf4, 0xc3, 0xc7, 0x0d, 0x4e, 0xbc, 0xf2, 0x0c, 0x01, 0x18, 0x00,
+  0x0e, 0x53, 0x9e, 0x9d, 0xc6, 0xdd, 0x71, 0xa0, 0x66, 0xad, 0x09, 0x4d,
+  0x05, 0x5d, 0x12, 0x24, 0x22, 0x49, 0x3c, 0x09, 0xd2, 0x38, 0x4f, 0x21,
+  0xc6, 0xfd, 0xce, 0x4f, 0x4f, 0x6d, 0x56, 0x4c, 0x8a, 0x32, 0x69, 0x9b,
+  0x1f, 0x6e, 0x8b, 0x4d, 0x3d, 0x42, 0xc1, 0x4d, 0x3c, 0x35, 0x46, 0x26,
+  0x75, 0x5c, 0xa8, 0x24, 0x30, 0x39, 0xe8, 0xb8, 0x1f, 0xb6, 0xab, 0x17,
+  0xbe, 0x20, 0x7b, 0x45, 0x4a, 0xf3, 0xd1, 0x54, 0x07, 0x48, 0x8b, 0x98,
+  0xc9, 0x18, 0xf0, 0xc9, 0xdc, 0x92, 0x76, 0xfc, 0x13, 0xaa, 0x97, 0x12,
+  0x71, 0x7c, 0x54, 0x97, 0xda, 0x85, 0x9a, 0xb5, 0x60, 0xa6, 0x8c, 0x73,
+  0x49, 0x84, 0xc0, 0x5d, 0x8e, 0x10, 0x2f, 0xa9, 0xdb, 0x7f, 0x6d, 0x71,
+  0x6a, 0xe2, 0x2a, 0xdb, 0xdf, 0x0c, 0xca, 0x05, 0xae, 0x25, 0x5d, 0xf0,
+  0x6b, 0x1b, 0x06, 0x55, 0x3d, 0x0a, 0x9d, 0xb9, 0x57, 0x1d, 0x4f, 0xf7,
+  0xd2, 0xe3, 0x39, 0x49, 0x5a, 0x66, 0x57, 0x94, 0xbc, 0xf0, 0xb7, 0x13,
+  0x47, 0x74, 0x82, 0xa2, 0x6b, 0x64, 0x6f, 0xf2, 0x71, 0xc4, 0x64, 0xe5,
+  0x09, 0x80, 0xa4, 0xe0, 0xf4, 0x27, 0x7e, 0xfd, 0x3a, 0xeb, 0xb3, 0x72,
+  0xfe, 0x35, 0x04, 0x75, 0x14, 0x2b, 0x35, 0x25, 0x50, 0x3b, 0xcb, 0x2f,
+  0x91, 0xa6, 0x0b, 0xb6, 0x15, 0x8f, 0x4c, 0xee, 0x7a, 0x74, 0xd2, 0x0f,
+  0x87, 0x0f, 0x05, 0x3d, 0x9a, 0x68, 0x26, 0xa3, 0x99, 0xe5, 0xa7, 0x8d,
+  0xc7, 0x89, 0x1b, 0x64, 0x54, 0x31, 0xe9, 0xe1, 0xa6, 0xc4, 0xf4, 0x03,
+  0x27, 0x6d, 0x58, 0xe8, 0x6d, 0x51, 0xcd, 0x47, 0x47, 0x1d, 0x78, 0xf9,
+  0xa9, 0xa5, 0x0d, 0x24, 0xe2, 0x70, 0x57, 0x95, 0x1b, 0x7f, 0x32, 0x13,
+  0xb1, 0x04, 0x74, 0x1b, 0x6d, 0xab, 0x87, 0xc9, 0xe9, 0xd8, 0x71, 0x7b,
+  0xe3, 0x64, 0x7c, 0x6f, 0x73, 0xbc, 0x43, 0xc0, 0xd5, 0x32, 0xc5, 0x32,
+  0x41, 0x5b, 0x28, 0xe5, 0x89, 0x63, 0x42, 0x79, 0x54, 0x92, 0x33, 0x91,
+  0xed, 0xaf, 0x3d, 0xd6, 0xda, 0x2b, 0x11, 0xd8, 0xcf, 0x32, 0x2a, 0x91,
+  0x92, 0x73, 0xb8, 0xc9, 0xf4, 0xd7, 0xa2, 0xe8, 0xed, 0xa6, 0xe5, 0x43,
+  0x72, 0xb6, 0x4d, 0x54, 0xbe, 0x0e, 0x4a, 0x53, 0xf8, 0x52, 0xf3, 0xaa,
+  0x2f, 0x63, 0x8f, 0xf2, 0xdf, 0xa8, 0xd6, 0x5f, 0xf1, 0x13, 0x83, 0xef,
+  0x5c, 0x3f, 0x6c, 0x8e, 0xe5, 0x03, 0x53, 0xdc, 0x8f, 0x89, 0xc8, 0xc8,
+  0x33, 0x94, 0x63, 0xd0, 0x9c, 0xf5, 0xd0, 0x64, 0x59, 0x67, 0x97, 0x73,
+  0xe9, 0x01, 0x97, 0x1b, 0x6e, 0xd1, 0x4b, 0xbc, 0xda, 0xd7, 0x87, 0xed,
+  0x8b, 0x2c, 0xf2, 0xd3, 0xf3, 0xd4, 0x43, 0xce, 0xac, 0x47, 0x98, 0x03,
+  0xd0, 0x6a, 0x99, 0x62, 0xb4, 0x52, 0xdd, 0xab, 0xe6, 0xae, 0xb8, 0xd6,
+  0x47, 0x49, 0x6d, 0x80, 0x9f, 0x1a, 0x79, 0xb3, 0x86, 0x38, 0xd9, 0x54,
+  0x0d, 0xd8, 0x9d, 0x69, 0x09, 0xf0, 0xe6, 0xf1, 0x74, 0x64, 0xbd, 0x71,
+  0x75, 0xc5, 0x69, 0xa8, 0xe3, 0x52, 0x1d, 0x61, 0x1c, 0xe6, 0x35, 0x09,
+  0x95, 0xce, 0xf8, 0xc1, 0xd8, 0x63, 0xae, 0xb3, 0x0b, 0xf0, 0x47, 0xbc,
+  0x7c, 0x85, 0x28, 0x8d, 0xa9, 0xa9, 0xd8, 0x08, 0x80, 0x5f, 0x2f, 0xdf,
+  0x5a, 0xa3, 0x92, 0x2f, 0xe8, 0x02, 0x8d, 0x1f, 0x62, 0x95, 0x22, 0xb7,
+  0x4f, 0x0d, 0x37, 0x34, 0x71, 0x19, 0x0e, 0x41, 0x4e, 0x5f, 0x10, 0x03,
+  0xe5, 0x38, 0xfb, 0x68, 0x27, 0x2b, 0x5f, 0x6b, 0x92, 0x02, 0xd9, 0x31,
+  0x39, 0x6c, 0x7a, 0x64, 0x6c, 0x7f, 0xef, 0xd7, 0x5a, 0x65, 0xb6, 0x81,
+  0x38, 0x9a, 0xd3, 0xf3, 0x30, 0x2c, 0x86, 0xb6, 0xdb, 0x96, 0xac, 0x61,
+  0x1f, 0xf2, 0xcc, 0x1c, 0xbb, 0x60, 0x8c, 0xe0, 0xae, 0x0e, 0xd8, 0xdf,
+  0x39, 0xed, 0xac, 0xf6, 0x4a, 0x58, 0xa8, 0xaf, 0x95, 0x34, 0xb2, 0x11,
+  0x14, 0x55, 0x00, 0xf2, 0x73, 0x7a, 0xe7, 0xa7, 0xf7, 0xd3, 0x78, 0x9b,
+  0xb4, 0x86, 0x45, 0x96, 0xbf, 0x83, 0x97, 0x2b, 0x6d, 0x65, 0xc1, 0x2d,
+  0x97, 0xbb, 0x2d, 0x3d, 0xca, 0xaa, 0x1c, 0xad, 0x1b, 0xcb, 0x8f, 0x2a,
+  0xf4, 0x2b, 0xfe, 0x7a, 0xb8, 0xfc, 0x45, 0xe1, 0x7b, 0x14, 0xfc, 0x49,
+  0x4d, 0xc4, 0x36, 0xa8, 0xe2, 0x5f, 0x05, 0x0a, 0x49, 0x4f, 0x08, 0xc4,
+  0x71, 0x48, 0x36, 0xc8, 0xf5, 0xef, 0xac, 0xd3, 0xe1, 0xbc, 0x17, 0x48,
+  0x3e, 0x23, 0x5a, 0x45, 0xa5, 0x11, 0xaa, 0xfc, 0x7c, 0x44, 0x59, 0xb0,
+  0xbd, 0x08, 0xc9, 0x3e, 0x98, 0xdf, 0x5e, 0x8d, 0xa0, 0xb1, 0xd2, 0xc5,
+  0x05, 0x7c, 0x8f, 0xe0, 0xcb, 0xcf, 0x1c, 0xaf, 0x56, 0xd3, 0xb9, 0x52,
+  0xd2, 0x16, 0x2c, 0x70, 0xbd, 0x87, 0x5d, 0x61, 0xd5, 0x62, 0x6a, 0x54,
+  0x9f, 0x62, 0xe7, 0xc9, 0x91, 0x5f, 0xf8, 0x5b, 0x9f, 0xe1, 0xdd, 0x67,
+  0x10, 0xc9, 0xce, 0xcd, 0x1d, 0x42, 0x45, 0x14, 0x7b, 0x80, 0xa3, 0xa1,
+  0x63, 0xef, 0x9c, 0xe3, 0x1a, 0xca, 0xeb, 0xa5, 0x14, 0xf9, 0x96, 0x1d,
+  0xa4, 0x3e, 0x54, 0x3e, 0x9e, 0xfa, 0xf4, 0xdf, 0xc4, 0x2b, 0xd5, 0x8e,
+  0x4b, 0x6d, 0x07, 0x0f, 0xbd, 0x3d, 0x14, 0xb6, 0xf9, 0x62, 0xf1, 0x43,
+  0x42, 0x85, 0x63, 0x84, 0x93, 0x85, 0xc0, 0x19, 0x24, 0xe1, 0xb5, 0xe7,
+  0x2b, 0xe5, 0xa4, 0x43, 0x57, 0x5f, 0x2b, 0x11, 0x24, 0x14, 0x93, 0x18,
+  0xd0, 0xaf, 0x4d, 0xf2, 0x41, 0x07, 0xec, 0x3a, 0x69, 0xda, 0x75, 0xb3,
+  0xc4, 0x28, 0xb2, 0xb6, 0x6a, 0x6a, 0x14, 0xb1, 0x8a, 0x46, 0x0b, 0x19,
+  0x04, 0x0c, 0xff, 0x00, 0x56, 0x7a, 0xeb, 0x40, 0x59, 0xa5, 0x7b, 0x24,
+  0x95, 0x0f, 0xcc, 0xdc, 0xd4, 0x3e, 0x21, 0x23, 0x66, 0x2c, 0x48, 0xe6,
+  0xfc, 0x6a, 0x91, 0x80, 0xf1, 0x24, 0x81, 0x64, 0xf0, 0xd9, 0x8b, 0x06,
+  0x2b, 0x80, 0xd8, 0xeb, 0x8f, 0x5d, 0x5e, 0x29, 0xea, 0x05, 0x57, 0x0e,
+  0xc9, 0x3b, 0x05, 0x52, 0x68, 0x9e, 0x9d, 0x49, 0x6e, 0xfc, 0xe1, 0x87,
+  0xfd, 0xfb, 0x6b, 0xad, 0x86, 0x06, 0xfd, 0x23, 0x05, 0xb5, 0x54, 0xc9,
+  0x43, 0x71, 0xb4, 0x37, 0xca, 0xfc, 0xc2, 0xc1, 0x40, 0xf3, 0x00, 0x4e,
+  0xec, 0xae, 0x58, 0x30, 0x23, 0xed, 0xcc, 0x73, 0xed, 0xa5, 0xf4, 0x54,
+  0xeb, 0x27, 0x0b, 0xd4, 0x5c, 0xd2, 0x4f, 0xf7, 0xea, 0x7a, 0xc0, 0x4a,
+  0x2f, 0x55, 0x89, 0x80, 0x2b, 0xfd, 0xb4, 0x55, 0xb6, 0x79, 0x57, 0x88,
+  0xe2, 0xb6, 0x1e, 0x46, 0x67, 0xa1, 0x8e, 0x9a, 0x07, 0xe7, 0xdd, 0x1f,
+  0xc3, 0xe6, 0x0c, 0x3d, 0xb7, 0x6e, 0xfd, 0xf5, 0x37, 0x09, 0x23, 0x35,
+  0xaa, 0xfd, 0x6d, 0x9a, 0x37, 0x87, 0x34, 0xc9, 0x32, 0xf3, 0x8d, 0xa5,
+  0x74, 0x7c, 0x10, 0x0f, 0x7c, 0xe7, 0x44, 0xfb, 0x35, 0x3e, 0xc0, 0x6b,
+  0x8f, 0x35, 0xc2, 0x2a, 0xb0, 0xfc, 0xc6, 0x67, 0xe7, 0x56, 0xfe, 0xfb,
+  0x7e, 0x75, 0x63, 0xb9, 0x24, 0x4f, 0x05, 0x14, 0x53, 0x2e, 0x11, 0x23,
+  0xf1, 0x15, 0xd8, 0xe4, 0x85, 0xc1, 0x1b, 0x0f, 0x4e, 0x9a, 0xaf, 0xcd,
+  0x49, 0x32, 0x43, 0x4b, 0x05, 0x45, 0x30, 0xa7, 0x78, 0xdf, 0x9c, 0x96,
+  0xf2, 0xb1, 0x0d, 0x92, 0x3f, 0x1a, 0x71, 0x73, 0x0c, 0x6d, 0x74, 0x41,
+  0xb1, 0x20, 0x8d, 0x08, 0x2e, 0xa7, 0xb7, 0x61, 0xa1, 0x34, 0x44, 0x55,
+  0x58, 0x11, 0x62, 0x80, 0x2a, 0x00, 0xbc, 0xb9, 0xc9, 0xf5, 0xf5, 0xc7,
+  0xa6, 0xa2, 0xa7, 0x56, 0x69, 0x53, 0x1b, 0x76, 0x27, 0x53, 0x73, 0x24,
+  0xb4, 0x6a, 0xaf, 0x1a, 0x18, 0x8a, 0xf2, 0x63, 0x97, 0x24, 0x10, 0x71,
+  0x9d, 0x7e, 0x82, 0x1a, 0x98, 0x26, 0x6a, 0x49, 0x31, 0x21, 0xe4, 0x2c,
+  0x92, 0x8f, 0xa5, 0xd4, 0x77, 0x1a, 0xa2, 0x88, 0x2e, 0x93, 0x3f, 0x8e,
+  0xf1, 0xab, 0x73, 0x78, 0x60, 0x17, 0xdb, 0x76, 0x27, 0xb6, 0x96, 0xcd,
+  0x11, 0x59, 0x7c, 0x39, 0x06, 0x46, 0x39, 0xc1, 0xf4, 0x3e, 0xda, 0x77,
+  0x08, 0x58, 0xae, 0x2e, 0x93, 0xd3, 0x99, 0xa3, 0xc2, 0xbb, 0x0e, 0x6c,
+  0x13, 0xb6, 0x7a, 0xe9, 0x05, 0xd8, 0xf3, 0x54, 0x89, 0xa3, 0xe6, 0x08,
+  0xa4, 0x31, 0x07, 0xaf, 0x2e, 0x48, 0xc6, 0xa1, 0x66, 0x87, 0xf0, 0xb3,
+  0xe1, 0xed, 0x57, 0x1d, 0x5c, 0x18, 0xd2, 0xd5, 0x2d, 0x34, 0x74, 0x50,
+  0xc6, 0xd3, 0x4a, 0xc0, 0x9c, 0xf3, 0xb1, 0xd8, 0x7b, 0xe3, 0x27, 0xf1,
+  0xad, 0x6b, 0xfd, 0xa3, 0x2c, 0x14, 0x16, 0x5f, 0x87, 0xb6, 0x4a, 0x7a,
+  0x0a, 0x54, 0x8a, 0x2a, 0x49, 0x45, 0x3a, 0x30, 0xfa, 0xb0, 0x63, 0x27,
+  0x7f, 0x5c, 0xf2, 0xe7, 0x56, 0x1f, 0xf6, 0x75, 0xb5, 0x7f, 0x0c, 0xe0,
+  0x9a, 0x5a, 0xca, 0x6e, 0x59, 0x69, 0xeb, 0xe1, 0x13, 0xbb, 0xa9, 0xc9,
+  0x2f, 0xb8, 0x0a, 0x7e, 0xc0, 0x63, 0xf3, 0xa5, 0x3c, 0x65, 0xc0, 0x3c,
+  0x61, 0xc7, 0x7c, 0x41, 0x5b, 0x70, 0xbd, 0x56, 0x43, 0x41, 0x6c, 0x81,
+  0x5d, 0x2d, 0xb4, 0x60, 0x97, 0x7c, 0xff, 0x00, 0x4b, 0x30, 0x1b, 0x2e,
+  0x4f, 0x53, 0x92, 0x7d, 0xb4, 0xa8, 0xc7, 0x6c, 0x5c, 0xbd, 0xb3, 0x9b,
+  0x38, 0x2e, 0x68, 0xc0, 0xf8, 0x4f, 0x83, 0xae, 0xdc, 0x61, 0x70, 0x6a,
+  0x2b, 0x3d, 0x3a, 0x4b, 0x2a, 0xc6, 0xd2, 0x3b, 0x33, 0xf2, 0xaa, 0x28,
+  0xc0, 0x3c, 0xc7, 0xb1, 0xc9, 0x18, 0xfb, 0xea, 0x1b, 0xcf, 0x0e, 0xdc,
+  0x78, 0x7a, 0x7f, 0x91, 0xbb, 0xd1, 0xd4, 0x51, 0xd4, 0x15, 0x0c, 0x12,
+  0x45, 0xc7, 0x32, 0xee, 0x32, 0x3d, 0xb6, 0x3a, 0xf6, 0x17, 0xc3, 0xde,
+  0x18, 0xa4, 0xe1, 0x4e, 0x16, 0x86, 0xd3, 0x4d, 0x1a, 0x34, 0xe2, 0x3c,
+  0xcd, 0x37, 0x42, 0xed, 0xd7, 0xf4, 0xdf, 0x03, 0x59, 0x17, 0xfb, 0x4c,
+  0xd9, 0x2a, 0x9a, 0xef, 0x6f, 0xbe, 0x63, 0xfd, 0xdd, 0xe9, 0xc5, 0x3b,
+  0x80, 0x33, 0xc8, 0xe0, 0x92, 0x37, 0xf7, 0xe6, 0xfd, 0xb4, 0x9c, 0xb0,
+  0xdb, 0x14, 0xcc, 0xf9, 0x31, 0xd2, 0x30, 0x6a, 0x88, 0xfc, 0x4e, 0x58,
+  0x23, 0xfa, 0x9b, 0x73, 0xf6, 0xd3, 0x1b, 0xfd, 0xc2, 0x08, 0xbe, 0x16,
+  0x4b, 0x60, 0x68, 0xa4, 0x79, 0x0d, 0xcc, 0x56, 0x2b, 0x96, 0xd8, 0x2f,
+  0x86, 0x50, 0x29, 0xf7, 0xd6, 0x91, 0xc1, 0xdc, 0x22, 0xf7, 0xdf, 0x87,
+  0x15, 0xf1, 0x5b, 0xad, 0x1f, 0x3d, 0x75, 0xa9, 0xae, 0x44, 0x86, 0x53,
+  0x85, 0x58, 0x15, 0x14, 0x64, 0xb3, 0x1e, 0x80, 0x86, 0xe8, 0x3e, 0xf8,
+  0xdb, 0x55, 0xcb, 0x47, 0xc3, 0xeb, 0x97, 0x12, 0xde, 0xeb, 0x78, 0x66,
+  0x26, 0x8a, 0x29, 0xe0, 0x49, 0x8c, 0x85, 0xf7, 0x55, 0xe4, 0x38, 0x03,
+  0x3e, 0xe7, 0x03, 0x3e, 0xfa, 0x4e, 0x37, 0xe5, 0x60, 0x24, 0x62, 0xf6,
+  0xfc, 0xcf, 0x72, 0x46, 0xe5, 0x3c, 0xb0, 0x9c, 0xf5, 0xfc, 0x69, 0xb5,
+  0xa1, 0x26, 0x6e, 0x28, 0x49, 0x23, 0x38, 0xf0, 0xc6, 0x7f, 0x04, 0x63,
+  0xfc, 0xc6, 0xa3, 0xae, 0xb3, 0xd4, 0xf0, 0xed, 0xda, 0xb6, 0xd1, 0x72,
+  0xa7, 0x68, 0x6a, 0xe9, 0xe4, 0x2a, 0xc0, 0x8d, 0x9b, 0x7e, 0xa0, 0xfa,
+  0x77, 0x1a, 0xd0, 0x7e, 0x18, 0xfc, 0x3e, 0xba, 0xf1, 0x05, 0xc1, 0x27,
+  0x86, 0x9c, 0xac, 0x4e, 0x57, 0xce, 0x0e, 0x47, 0x2e, 0xdb, 0x93, 0xdb,
+  0xd7, 0x1a, 0xd1, 0x9b, 0x22, 0x8c, 0x2d, 0x91, 0xa2, 0xdb, 0xf0, 0xe9,
+  0x6a, 0x65, 0xa1, 0xe2, 0x69, 0x12, 0x37, 0x4a, 0xb7, 0xb7, 0x83, 0x1b,
+  0x03, 0x96, 0x74, 0x0c, 0x32, 0xa0, 0x6d, 0xd8, 0x75, 0xd6, 0x7d, 0x4b,
+  0xc3, 0x57, 0x66, 0xb5, 0xcd, 0x75, 0x4b, 0x75, 0x4c, 0x74, 0x71, 0xbf,
+  0xfc, 0x5f, 0x05, 0x82, 0x05, 0xed, 0xb9, 0x1e, 0xfa, 0xd6, 0xef, 0xe6,
+  0xdd, 0xc1, 0xd7, 0x81, 0x65, 0xb4, 0xb1, 0x92, 0xe2, 0x22, 0x06, 0x5a,
+  0x85, 0xcf, 0x90, 0x64, 0x6d, 0xef, 0x9c, 0x74, 0xd7, 0x1c, 0x4f, 0x54,
+  0x78, 0xae, 0xd8, 0x54, 0x54, 0x57, 0xc3, 0x3d, 0x1c, 0x3f, 0xfe, 0x3a,
+  0x4b, 0xfc, 0x83, 0x1a, 0x8f, 0xf0, 0x6c, 0x33, 0x9c, 0x6f, 0xae, 0x3e,
+  0x3d, 0x46, 0xce, 0x7a, 0xb6, 0x2a, 0x8c, 0x9e, 0xa5, 0xa7, 0xf0, 0xa9,
+  0xe2, 0x2f, 0xb5, 0x3e, 0x54, 0x0c, 0x0c, 0x82, 0x4e, 0xfb, 0xeb, 0xd2,
+  0x56, 0xbb, 0x85, 0xf3, 0xff, 0x00, 0x4f, 0x58, 0x55, 0xea, 0x26, 0x8e,
+  0x96, 0x6a, 0x28, 0x52, 0x61, 0x1a, 0x8f, 0x11, 0xb2, 0xa3, 0x05, 0x7e,
+  0xfa, 0xf3, 0x7a, 0xe6, 0x40, 0x91, 0x92, 0x10, 0xf8, 0xb9, 0x3e, 0xc3,
+  0x04, 0x1d, 0x7a, 0x37, 0xe1, 0xe7, 0x11, 0x40, 0x96, 0x98, 0xa2, 0xa6,
+  0x11, 0x2b, 0x2c, 0x31, 0xaa, 0x34, 0xa7, 0x03, 0xc3, 0x5d, 0xca, 0xfd,
+  0xfb, 0xea, 0x6b, 0x1c, 0x54, 0xa2, 0x9b, 0xa2, 0xf1, 0xe4, 0x49, 0xf2,
+  0x5a, 0x2a, 0xe9, 0x2a, 0xad, 0xf4, 0x4e, 0x63, 0x9a, 0x69, 0xa4, 0x46,
+  0xfe, 0x4b, 0x4a, 0xd9, 0x0a, 0x3f, 0xab, 0x9b, 0x03, 0x73, 0xdf, 0x18,
+  0xce, 0x47, 0x5d, 0x79, 0xeb, 0x8e, 0xef, 0xd5, 0xfc, 0x59, 0xc5, 0x4e,
+  0x22, 0xa7, 0x65, 0x8a, 0x91, 0x1a, 0x00, 0xef, 0x19, 0x8d, 0xf6, 0x62,
+  0x72, 0xc0, 0xf4, 0x27, 0xd3, 0xb6, 0xb6, 0x4e, 0x3c, 0xa2, 0xbe, 0x7f,
+  0xe9, 0xa8, 0xae, 0xb4, 0x33, 0x3f, 0x38, 0x98, 0x4c, 0xbe, 0x0e, 0x23,
+  0xe4, 0x42, 0x7a, 0xb2, 0x0c, 0xf3, 0x11, 0x91, 0xdf, 0x4c, 0x78, 0x22,
+  0xc1, 0x41, 0x15, 0x6d, 0x35, 0x6c, 0xa2, 0x3a, 0xeb, 0x93, 0xc2, 0x64,
+  0x9a, 0xa7, 0x1e, 0x45, 0x7c, 0x82, 0x0e, 0x0e, 0xe4, 0xef, 0xb1, 0xf4,
+  0x1a, 0x76, 0x15, 0x2c, 0x72, 0xb6, 0xbb, 0x34, 0xed, 0xba, 0x47, 0xff,
+  0xd9
+};
+
+void
+jpeg_get_video_info (VideoDecodeInfo * info)
+{
+  info->profile = GST_VAAPI_PROFILE_JPEG_BASELINE;
+  info->width = JPEG_CLIP_WIDTH;
+  info->height = JPEG_CLIP_HEIGHT;
+  info->data = jpeg_clip;
+  info->data_size = JPEG_CLIP_DATA_SIZE;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-jpeg.h b/subprojects/gstreamer-vaapi/tests/internal/test-jpeg.h
new file mode 100644 (file)
index 0000000..9fa3ed1
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  test-jpeg.h - JPEG test data
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_JPEG_H
+#define TEST_JPEG_H
+
+#include <glib.h>
+#include "test-decode.h"
+
+void jpeg_get_video_info(VideoDecodeInfo *info);
+
+#endif /* TEST_JPEG_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-mpeg2.c b/subprojects/gstreamer-vaapi/tests/internal/test-mpeg2.c
new file mode 100644 (file)
index 0000000..16e69b7
--- /dev/null
@@ -0,0 +1,1651 @@
+/*
+ *  test-mpeg2.c - MPEG-2 test data
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "test-mpeg2.h"
+
+#define MPEG2_CLIP_WIDTH          320
+#define MPEG2_CLIP_HEIGHT         240
+#define MPEG2_CLIP_DATA_SIZE    19311
+
+/* Data dump of a 320x240 MPEG-2 video clip (mpeg2.m2v), it has a single frame */
+static const guchar mpeg2_clip[MPEG2_CLIP_DATA_SIZE] = {
+  0x00, 0x00, 0x01, 0xb3, 0x14, 0x00, 0xf0, 0x12, 0x07, 0x53, 0x23, 0x80,
+  0x00, 0x00, 0x01, 0xb5, 0x14, 0x8a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0xb5, 0x2b, 0x02, 0x02, 0x02, 0x05, 0x02, 0x07, 0x80, 0x00, 0x00,
+  0x01, 0xb8, 0x00, 0x08, 0x00, 0x40, 0x00, 0x00, 0x01, 0x00, 0x00, 0x0f,
+  0xff, 0xf8, 0x00, 0x00, 0x01, 0xb5, 0x8f, 0xff, 0xf7, 0x5d, 0x80, 0x00,
+  0x00, 0x01, 0x01, 0x43, 0xf8, 0x90, 0x03, 0xee, 0x36, 0xd4, 0x92, 0x85,
+  0x86, 0x37, 0x48, 0x01, 0xb3, 0xf7, 0x9a, 0x1d, 0x5c, 0x38, 0xb1, 0x95,
+  0xb9, 0x42, 0x43, 0xb2, 0xc2, 0x51, 0x24, 0x31, 0xb2, 0xed, 0x20, 0x73,
+  0xd9, 0x08, 0xcc, 0x5b, 0xe2, 0x39, 0xbc, 0xdb, 0x12, 0xb7, 0x8c, 0x31,
+  0xbf, 0x6c, 0x00, 0xc3, 0xeb, 0xc3, 0xd0, 0x6c, 0x3e, 0x16, 0xde, 0xa8,
+  0x89, 0xf3, 0xc1, 0x17, 0xda, 0x5a, 0x4f, 0xca, 0xb0, 0x6b, 0x7c, 0x07,
+  0xbb, 0x6c, 0x95, 0x8f, 0x74, 0x35, 0xaa, 0x45, 0x65, 0xb4, 0x35, 0xbf,
+  0xd4, 0x22, 0xab, 0xfe, 0x80, 0x07, 0x7c, 0xed, 0x7a, 0x97, 0x2b, 0xaf,
+  0x2f, 0x72, 0x64, 0x81, 0x86, 0x0f, 0x6f, 0x9a, 0x7b, 0x02, 0x10, 0x07,
+  0x76, 0x2f, 0x01, 0x30, 0x01, 0x2d, 0x21, 0x37, 0x89, 0xbc, 0x74, 0x00,
+  0xf4, 0xc3, 0x6b, 0xa4, 0x1f, 0x65, 0xa7, 0xb6, 0xff, 0x6d, 0x9f, 0x6f,
+  0x6f, 0x77, 0xa8, 0x5b, 0xa7, 0x95, 0x90, 0x2e, 0x2b, 0x71, 0xec, 0x35,
+  0xf4, 0x96, 0x92, 0x33, 0xa9, 0x92, 0x48, 0xdf, 0xcf, 0x50, 0x39, 0x13,
+  0xd1, 0xbd, 0x25, 0x4f, 0xbe, 0x5b, 0x10, 0x25, 0x6e, 0x14, 0xdc, 0x5e,
+  0xe0, 0x7b, 0x7a, 0x3d, 0x04, 0x2f, 0xf2, 0xb8, 0x84, 0x38, 0xdd, 0x16,
+  0x94, 0xdb, 0x46, 0xfd, 0xdf, 0x3a, 0x00, 0x7a, 0xf9, 0x49, 0x45, 0xb7,
+  0x52, 0xe9, 0x03, 0x9a, 0x4a, 0x40, 0xf8, 0x14, 0xdc, 0xa7, 0x4d, 0xf7,
+  0xbc, 0x25, 0x04, 0xa0, 0x04, 0x2a, 0x81, 0x6d, 0xda, 0x36, 0x67, 0x1b,
+  0xb8, 0x48, 0x96, 0xb7, 0x49, 0xea, 0xd9, 0x1c, 0x8d, 0xf8, 0xfb, 0x80,
+  0x07, 0x50, 0x9c, 0x13, 0x43, 0xae, 0x94, 0x07, 0x36, 0xff, 0x8b, 0x00,
+  0x1c, 0x8a, 0x35, 0x00, 0x20, 0x49, 0x40, 0xdb, 0x74, 0x05, 0x82, 0x10,
+  0x03, 0xcd, 0x28, 0x29, 0x06, 0x56, 0xf1, 0x2f, 0xc0, 0x03, 0xd1, 0x22,
+  0x26, 0xd0, 0x08, 0x0a, 0x03, 0x4d, 0x27, 0x37, 0x5d, 0x2f, 0x36, 0xb7,
+  0xe9, 0xef, 0x7a, 0x00, 0xd0, 0x83, 0xe5, 0x14, 0x65, 0x8a, 0x62, 0xd9,
+  0xe2, 0x31, 0xb8, 0x3e, 0xef, 0x15, 0xbd, 0xdc, 0xb8, 0xf4, 0xa3, 0x4a,
+  0xb9, 0x36, 0x1c, 0xde, 0xe7, 0x41, 0x08, 0x01, 0xb8, 0x79, 0xe0, 0x11,
+  0x4a, 0xbe, 0x07, 0xca, 0xdf, 0x2d, 0xea, 0x5d, 0x11, 0x99, 0xb0, 0x2c,
+  0x3a, 0x6e, 0x41, 0xaa, 0x5b, 0x23, 0xf2, 0xb5, 0x5a, 0x41, 0xcd, 0xd8,
+  0x42, 0xad, 0xf7, 0x78, 0xc8, 0x2d, 0xdc, 0x51, 0x70, 0x72, 0xcc, 0xd8,
+  0xb4, 0x75, 0x85, 0x43, 0x94, 0x25, 0xbd, 0x5e, 0xf9, 0x3c, 0x49, 0xbc,
+  0xe5, 0xa3, 0x2b, 0xb8, 0x49, 0x0a, 0x26, 0xd2, 0xa7, 0xea, 0x8d, 0xfd,
+  0xb1, 0xf7, 0xdd, 0x22, 0x8b, 0xef, 0xce, 0x5a, 0x51, 0x66, 0x64, 0x33,
+  0x8a, 0x85, 0x53, 0xc0, 0x7b, 0x51, 0x22, 0x34, 0xe8, 0xd7, 0xd0, 0x09,
+  0x8f, 0x5a, 0x53, 0xb8, 0x54, 0x1b, 0x4b, 0x2c, 0xbb, 0xaa, 0x18, 0xd5,
+  0x69, 0x6d, 0xd2, 0xfa, 0xba, 0x5b, 0x7c, 0x67, 0xc9, 0x37, 0x51, 0x02,
+  0x37, 0x8a, 0x6a, 0xec, 0x2b, 0x03, 0x94, 0xe4, 0x1e, 0xad, 0xce, 0x96,
+  0x95, 0x84, 0x34, 0x5a, 0x38, 0x63, 0x58, 0x90, 0x44, 0x0e, 0xa1, 0x35,
+  0xf4, 0xa0, 0xf3, 0xe1, 0x55, 0x0a, 0x46, 0x12, 0x5b, 0x93, 0x2c, 0x0c,
+  0x95, 0x51, 0x62, 0x94, 0x34, 0x34, 0x2d, 0xaa, 0x36, 0x8d, 0xf3, 0xbb,
+  0x0e, 0xe3, 0x37, 0x54, 0x02, 0x32, 0x83, 0x29, 0xd0, 0xea, 0xce, 0x7e,
+  0x95, 0x3c, 0x26, 0x9a, 0xd0, 0xcb, 0x9c, 0xba, 0xa8, 0x49, 0x8e, 0x2d,
+  0x68, 0x4d, 0x65, 0xa9, 0xaa, 0x05, 0xb2, 0x8c, 0x37, 0xe9, 0x5e, 0xfc,
+  0x00, 0x7a, 0xe7, 0x4e, 0x1e, 0xa3, 0xe5, 0x9b, 0xb9, 0x42, 0x52, 0xc3,
+  0xe3, 0x3f, 0x3f, 0x39, 0x86, 0x59, 0xb8, 0x80, 0x2a, 0xa9, 0x65, 0x3d,
+  0xa9, 0xd4, 0xfb, 0xf4, 0xf9, 0x65, 0x1e, 0xa9, 0x62, 0x6c, 0x18, 0x30,
+  0xf8, 0xdb, 0x5f, 0xb7, 0x8e, 0xde, 0xe7, 0x1b, 0xe2, 0x84, 0xc0, 0x86,
+  0xe3, 0x71, 0x37, 0x0a, 0x0b, 0x29, 0xbc, 0xe4, 0x33, 0x31, 0xbd, 0x1c,
+  0xf3, 0x40, 0x1e, 0xee, 0x3b, 0x4c, 0x5f, 0xd0, 0x21, 0x00, 0x36, 0x96,
+  0x3c, 0x7b, 0x76, 0xbd, 0xe9, 0xb5, 0xfd, 0x74, 0x81, 0xb6, 0xba, 0xdc,
+  0x25, 0x14, 0xde, 0x6f, 0xda, 0x80, 0x1f, 0xa4, 0xf3, 0x08, 0x0b, 0x38,
+  0x68, 0x6b, 0x75, 0x48, 0xdc, 0x52, 0x27, 0x1e, 0xf6, 0xa8, 0x0a, 0xaf,
+  0x91, 0xb9, 0x68, 0x48, 0x67, 0x8b, 0x70, 0xf7, 0xc7, 0x96, 0x3a, 0x5f,
+  0x59, 0x22, 0x59, 0xe2, 0xdc, 0xd7, 0x0c, 0xb9, 0x40, 0x07, 0xad, 0xf0,
+  0x7e, 0x82, 0x74, 0x8c, 0x01, 0x6a, 0xe9, 0x63, 0x75, 0xcf, 0x59, 0x43,
+  0xa1, 0x92, 0x04, 0x37, 0x86, 0xe2, 0xa5, 0x74, 0x50, 0x90, 0x1c, 0x43,
+  0x3c, 0x6d, 0xf0, 0x18, 0xdb, 0xf6, 0xce, 0x24, 0x28, 0x29, 0xb9, 0xb4,
+  0xac, 0xc0, 0x29, 0xbd, 0x2d, 0xab, 0xb6, 0xa3, 0x6a, 0xdf, 0xa6, 0x8e,
+  0x73, 0xc5, 0xbb, 0x99, 0x90, 0x04, 0x66, 0x17, 0xea, 0xa7, 0xb7, 0xa5,
+  0xe4, 0xa7, 0x6e, 0x69, 0x41, 0xbf, 0x9a, 0x60, 0xf3, 0xe0, 0xc6, 0x41,
+  0x74, 0x02, 0xbe, 0x38, 0x7e, 0x50, 0x4a, 0xff, 0xd9, 0x2d, 0x0d, 0x29,
+  0x7c, 0x1b, 0xaa, 0x27, 0x5c, 0x00, 0xdb, 0xfa, 0x20, 0x5b, 0xe2, 0x52,
+  0xe5, 0x8f, 0x11, 0xa6, 0xd8, 0x58, 0x6a, 0x52, 0x15, 0x6d, 0x0b, 0xb5,
+  0x40, 0xb6, 0x4d, 0xf0, 0x35, 0xb3, 0x76, 0xfa, 0xfe, 0x4b, 0xd0, 0x08,
+  0x31, 0xb4, 0x40, 0x1a, 0xab, 0x62, 0x80, 0x84, 0x01, 0x35, 0xe0, 0x9b,
+  0xff, 0xb2, 0x12, 0x19, 0x53, 0x94, 0x96, 0xd2, 0xdd, 0xbb, 0x0a, 0x66,
+  0xd0, 0x1a, 0x36, 0x21, 0x40, 0x85, 0xff, 0x1b, 0x8f, 0x9e, 0xa6, 0x2a,
+  0xb7, 0x75, 0xe3, 0x09, 0x0d, 0xb4, 0x18, 0xd4, 0xdd, 0xaf, 0x0e, 0x70,
+  0xba, 0x4a, 0x56, 0xe5, 0x11, 0x4f, 0x95, 0x28, 0x0a, 0xa8, 0xc6, 0xf4,
+  0x77, 0xf3, 0x79, 0x52, 0x4b, 0x4a, 0x5a, 0xb7, 0x3e, 0x7e, 0x6d, 0x24,
+  0x23, 0x44, 0x2d, 0x5b, 0xc2, 0x2d, 0x76, 0x6d, 0xa4, 0x3a, 0xdd, 0x61,
+  0x30, 0x00, 0xfe, 0x61, 0x26, 0x46, 0xfa, 0x10, 0x03, 0xf2, 0x2e, 0x00,
+  0x16, 0xfd, 0xb1, 0xfe, 0xdb, 0x32, 0x95, 0xa5, 0x08, 0xaf, 0x9c, 0xc1,
+  0xc5, 0x28, 0x6b, 0x7a, 0x80, 0x02, 0xd1, 0x16, 0xfb, 0xbc, 0x56, 0xe0,
+  0x5e, 0x8f, 0x75, 0x0d, 0x81, 0xac, 0x13, 0x21, 0xa4, 0x8a, 0x48, 0x63,
+  0x62, 0x42, 0xe3, 0x7e, 0xc1, 0xe0, 0x0f, 0xf9, 0x00, 0x72, 0x28, 0x4d,
+  0x14, 0xfb, 0x92, 0x1d, 0x8e, 0xb6, 0xa6, 0x58, 0x5d, 0xf4, 0xac, 0x7e,
+  0x40, 0x15, 0x80, 0x19, 0x7b, 0x3d, 0xf3, 0x65, 0xc2, 0xa7, 0x2e, 0xc3,
+  0xee, 0xc5, 0x28, 0xe6, 0x4f, 0xf8, 0xbf, 0x6f, 0x97, 0x0b, 0xe3, 0xae,
+  0xf5, 0x4a, 0x2f, 0x69, 0x61, 0x63, 0x5b, 0xb6, 0x46, 0x00, 0x63, 0x74,
+  0x4a, 0xdc, 0xd7, 0xe5, 0x4c, 0x42, 0xdb, 0x1d, 0xe3, 0x7b, 0xa4, 0xd7,
+  0x8d, 0x28, 0x32, 0x35, 0x99, 0x75, 0x4b, 0x78, 0x64, 0x0c, 0x8d, 0xfc,
+  0xa0, 0x00, 0x9c, 0x59, 0x10, 0x89, 0x79, 0x77, 0xc8, 0xa7, 0x95, 0x0d,
+  0xc7, 0x96, 0x51, 0x87, 0xc5, 0xad, 0x84, 0x01, 0x1b, 0xaf, 0xdc, 0x40,
+  0xa1, 0x79, 0xce, 0x52, 0xe5, 0x93, 0x1e, 0x56, 0x55, 0x01, 0xec, 0xf5,
+  0x6f, 0xd0, 0xa4, 0x6f, 0xe8, 0x01, 0xef, 0xc4, 0xde, 0x49, 0xef, 0x5b,
+  0x36, 0x6c, 0x3a, 0xa5, 0x2e, 0x56, 0xee, 0xdd, 0x98, 0x62, 0x5a, 0x15,
+  0xb4, 0xb4, 0x6e, 0xfd, 0x44, 0x21, 0x96, 0x31, 0xba, 0x1f, 0x62, 0x20,
+  0x0f, 0x98, 0x00, 0x00, 0x01, 0x02, 0x43, 0xf8, 0x37, 0x13, 0x05, 0xdd,
+  0xbe, 0xa9, 0x4b, 0x6c, 0xa2, 0xbc, 0xc5, 0x6e, 0x6c, 0x21, 0x12, 0x23,
+  0x77, 0x3e, 0x68, 0x05, 0xa2, 0xdf, 0x8e, 0xcf, 0x02, 0xe1, 0x60, 0x73,
+  0x79, 0x09, 0x08, 0x0e, 0x74, 0x25, 0x49, 0x1b, 0xcc, 0x42, 0xca, 0x21,
+  0xb7, 0x90, 0xdf, 0x40, 0x10, 0xff, 0xe7, 0x1d, 0x2e, 0x92, 0x59, 0x94,
+  0x80, 0x94, 0xbf, 0x16, 0xe7, 0xdc, 0x34, 0xb6, 0xd7, 0xb0, 0xd9, 0x2d,
+  0x50, 0x81, 0xc5, 0x35, 0x0f, 0x6a, 0x6f, 0xd4, 0xea, 0xfd, 0x5e, 0xa0,
+  0x03, 0x0a, 0xad, 0xc9, 0xee, 0x5f, 0x8e, 0x78, 0xb2, 0xc0, 0xc0, 0xe2,
+  0xbd, 0x4a, 0x46, 0xd5, 0xed, 0x27, 0x2e, 0xe1, 0xea, 0x13, 0x76, 0xd1,
+  0xc1, 0x65, 0x90, 0x99, 0xb6, 0x00, 0x1a, 0x24, 0x9e, 0x12, 0x87, 0xc8,
+  0x14, 0x96, 0x10, 0xda, 0x60, 0x74, 0xd0, 0x2d, 0x85, 0x30, 0xaa, 0xdf,
+  0x15, 0xff, 0x9c, 0x02, 0xaa, 0x36, 0xdb, 0x2d, 0xdb, 0x9b, 0xa0, 0x10,
+  0xc4, 0x94, 0x87, 0x1b, 0x3e, 0x02, 0x17, 0xfc, 0x6b, 0x88, 0x70, 0xf4,
+  0x21, 0x37, 0x7c, 0x5c, 0x9c, 0xba, 0xda, 0xac, 0x13, 0x59, 0x1f, 0x1b,
+  0xca, 0x2b, 0x30, 0x5e, 0xe3, 0xa2, 0x78, 0xd0, 0xe2, 0x43, 0x7b, 0x87,
+  0x53, 0x70, 0xbc, 0xa1, 0xb0, 0xf8, 0x12, 0xde, 0x44, 0x01, 0xf8, 0xaa,
+  0x94, 0xf9, 0x43, 0x71, 0x51, 0xb4, 0x3f, 0x20, 0x9e, 0x6c, 0x49, 0x03,
+  0x75, 0x76, 0x86, 0x42, 0x96, 0x95, 0x2b, 0x5a, 0x07, 0xb6, 0xfc, 0x97,
+  0x8d, 0xfa, 0x7f, 0xa3, 0xcd, 0x91, 0xe6, 0x78, 0xc2, 0xc2, 0x5b, 0x77,
+  0x7b, 0x48, 0xf6, 0x3d, 0x03, 0x21, 0xbd, 0x62, 0x58, 0x16, 0xb1, 0xbc,
+  0xdc, 0xe7, 0xce, 0x77, 0x2b, 0xf4, 0x05, 0x7d, 0x29, 0x30, 0x69, 0xf2,
+  0x37, 0x55, 0xd8, 0x00, 0x73, 0x3b, 0x89, 0x02, 0xad, 0x2c, 0x84, 0x3d,
+  0xb0, 0x43, 0x25, 0x6c, 0x2c, 0x4a, 0xab, 0xe8, 0xde, 0x7d, 0xe3, 0x40,
+  0x1d, 0x3f, 0xb7, 0x89, 0x90, 0x35, 0x1d, 0x76, 0xa8, 0xd2, 0x6c, 0x2d,
+  0x28, 0x5b, 0x78, 0xb7, 0xf3, 0x7e, 0x57, 0xcc, 0x22, 0x49, 0xdd, 0x2a,
+  0xa0, 0xd2, 0x83, 0x29, 0x6d, 0xf6, 0x3d, 0xbe, 0x73, 0x1c, 0x80, 0x10,
+  0x45, 0x25, 0xa9, 0x5e, 0xad, 0xe0, 0xc5, 0xf2, 0x00, 0x70, 0x27, 0x84,
+  0xd8, 0xa7, 0xee, 0xee, 0x59, 0x9b, 0x83, 0x40, 0x79, 0x22, 0xb5, 0x38,
+  0x0c, 0xc5, 0x6e, 0x8c, 0xa0, 0x16, 0x87, 0x90, 0xa3, 0x6f, 0xed, 0x2f,
+  0x0f, 0xf3, 0x59, 0x20, 0x13, 0x0f, 0x2d, 0x4e, 0x0a, 0x30, 0x39, 0x84,
+  0xd3, 0x69, 0x8b, 0x92, 0x04, 0x17, 0x8e, 0x81, 0x1b, 0x15, 0x6e, 0x8e,
+  0x29, 0xb8, 0x9c, 0x39, 0x53, 0x12, 0x5a, 0x51, 0x65, 0x42, 0xa4, 0x2b,
+  0xd2, 0x9c, 0xdb, 0x38, 0x9e, 0x7a, 0x8b, 0x42, 0x4b, 0x2c, 0x30, 0xe4,
+  0x6e, 0x88, 0x53, 0x7a, 0x27, 0xc6, 0xf0, 0xe8, 0x21, 0x00, 0x45, 0x28,
+  0x92, 0xb5, 0x46, 0x1e, 0x7b, 0x64, 0x32, 0x6c, 0x9e, 0x31, 0x15, 0x15,
+  0xb7, 0xe1, 0x68, 0x52, 0x80, 0x8a, 0xd1, 0xcd, 0xa2, 0x6d, 0xe6, 0x3f,
+  0x65, 0xaa, 0x33, 0x0a, 0xc9, 0x12, 0x05, 0xa8, 0xd0, 0x86, 0x6c, 0x37,
+  0xc6, 0xd8, 0x85, 0x94, 0x07, 0x36, 0x7e, 0xad, 0xeb, 0x92, 0x45, 0x2d,
+  0xb6, 0x69, 0x99, 0xb8, 0x50, 0x16, 0xdc, 0x30, 0x43, 0x00, 0x77, 0x3a,
+  0x80, 0x0c, 0x59, 0x1c, 0xd9, 0xcf, 0xc6, 0xd6, 0xf4, 0x11, 0xb0, 0x00,
+  0xf4, 0x5e, 0x15, 0xe2, 0x91, 0x07, 0xb7, 0xad, 0xc9, 0x99, 0xed, 0x53,
+  0x03, 0x22, 0xea, 0xcb, 0x40, 0x44, 0x3c, 0x73, 0x78, 0x31, 0x91, 0xbd,
+  0x75, 0x04, 0x2f, 0xf7, 0xde, 0xc9, 0x20, 0x73, 0x61, 0x69, 0xcd, 0x82,
+  0x90, 0x7c, 0x90, 0x86, 0xdd, 0x32, 0x25, 0x75, 0xd9, 0x03, 0x10, 0xec,
+  0xb7, 0xc0, 0x73, 0x74, 0x76, 0x65, 0xce, 0x6c, 0xd0, 0x83, 0x65, 0x90,
+  0x34, 0x7b, 0x70, 0xdc, 0x1d, 0xe6, 0x70, 0x46, 0x4c, 0xe0, 0xaf, 0x1a,
+  0xdd, 0xcd, 0x04, 0x20, 0x08, 0xda, 0x62, 0x04, 0xaa, 0xcf, 0x45, 0x52,
+  0x4b, 0x68, 0x37, 0x21, 0x21, 0xb6, 0xda, 0x01, 0x52, 0xe1, 0x0a, 0x96,
+  0xdf, 0x21, 0x7c, 0x8f, 0xf5, 0x8d, 0x6f, 0x60, 0x85, 0xfe, 0x0e, 0x11,
+  0x08, 0x66, 0xd2, 0x11, 0x4b, 0x58, 0x6c, 0xa9, 0x55, 0xbd, 0x08, 0xb9,
+  0x48, 0xbd, 0xd3, 0x82, 0x90, 0xc8, 0x07, 0xb6, 0x81, 0xad, 0xe7, 0x37,
+  0xd0, 0xa5, 0x18, 0x07, 0x36, 0x5e, 0x4a, 0x76, 0x72, 0x42, 0xbe, 0x44,
+  0xb6, 0xd6, 0x8a, 0x8c, 0xbc, 0xda, 0xf7, 0x3a, 0xe6, 0x50, 0xbc, 0xa9,
+  0xe8, 0x74, 0xa4, 0xb6, 0x89, 0xf8, 0xad, 0x03, 0x5b, 0xa3, 0x98, 0x96,
+  0x69, 0x25, 0x5a, 0xc2, 0x3a, 0x8a, 0xc3, 0x70, 0xa1, 0xf1, 0x1e, 0x9b,
+  0x21, 0xc1, 0x95, 0xae, 0xae, 0x27, 0x79, 0x4b, 0x09, 0x11, 0xba, 0xe4,
+  0x6c, 0x00, 0xb3, 0xaf, 0x32, 0x6d, 0x1c, 0x41, 0xf3, 0x96, 0x58, 0x01,
+  0xfb, 0x73, 0x3a, 0xc4, 0x90, 0x96, 0x48, 0x60, 0xf9, 0x63, 0x7e, 0x28,
+  0x8b, 0x28, 0x9e, 0xa6, 0x1b, 0x03, 0x15, 0x64, 0x41, 0xad, 0xec, 0xbe,
+  0x5d, 0xaf, 0x15, 0x9a, 0xfc, 0x81, 0xb7, 0x0e, 0xa9, 0xea, 0xd9, 0xba,
+  0xcb, 0x61, 0xa5, 0xd0, 0xc5, 0x1c, 0xde, 0x87, 0xcf, 0x8f, 0xed, 0x11,
+  0x98, 0x2f, 0x29, 0x69, 0x70, 0x02, 0xb7, 0xe4, 0x85, 0xcf, 0x05, 0xa3,
+  0x1a, 0xf2, 0x17, 0x11, 0x93, 0x7d, 0xb0, 0x06, 0x7b, 0x99, 0xa4, 0x7e,
+  0xa9, 0x03, 0x99, 0x2a, 0x79, 0xc7, 0x3f, 0x52, 0xde, 0x29, 0x94, 0xa5,
+  0x8a, 0x4b, 0x8d, 0xe3, 0xdf, 0xf9, 0x6f, 0xba, 0x80, 0x3d, 0x15, 0xfe,
+  0x00, 0x7d, 0x9e, 0xfc, 0x7b, 0x91, 0x93, 0x62, 0xe9, 0x3f, 0x9c, 0xcf,
+  0x27, 0x07, 0xdb, 0x46, 0x16, 0x5a, 0xc6, 0xe2, 0x8b, 0xfb, 0xe8, 0x02,
+  0x37, 0x88, 0x77, 0xc4, 0x1c, 0x95, 0x64, 0xaf, 0xde, 0x6c, 0xf2, 0x85,
+  0x41, 0xc5, 0xb2, 0xb6, 0x57, 0xcb, 0x28, 0xf4, 0x89, 0x19, 0xd1, 0x96,
+  0x50, 0xa6, 0xfc, 0xf7, 0xfc, 0x53, 0xfd, 0xc8, 0xf9, 0x9c, 0x3e, 0x06,
+  0x27, 0x39, 0x78, 0xd4, 0x01, 0x5c, 0xa8, 0xa7, 0x0e, 0x6f, 0xd4, 0x42,
+  0x01, 0x0b, 0xfc, 0xfe, 0x04, 0xb8, 0x84, 0xf9, 0x6c, 0xf0, 0x2c, 0xa6,
+  0xc9, 0xfd, 0xdb, 0xfe, 0xfa, 0x72, 0xb6, 0x84, 0x38, 0xd4, 0x7f, 0xa8,
+  0xea, 0xda, 0x44, 0xe0, 0x01, 0x9f, 0xb8, 0xbd, 0x72, 0x86, 0x99, 0x52,
+  0x42, 0x14, 0x6e, 0xbd, 0x86, 0xee, 0x12, 0xe4, 0x6e, 0xbd, 0x86, 0xee,
+  0x12, 0xe4, 0x6e, 0x90, 0x07, 0xbe, 0xfd, 0xf3, 0xcc, 0x86, 0x3e, 0xd4,
+  0x92, 0x01, 0x87, 0x64, 0x5f, 0x16, 0xe9, 0x09, 0xef, 0x9d, 0x7d, 0xb6,
+  0xbf, 0x68, 0xd5, 0x6d, 0x6d, 0xe0, 0x80, 0x14, 0x68, 0x20, 0x80, 0xaf,
+  0xde, 0x73, 0xce, 0x50, 0xc9, 0xc4, 0x3b, 0x68, 0xcf, 0x46, 0xdd, 0x4b,
+  0x3d, 0xb5, 0x54, 0xdb, 0x1b, 0xe7, 0x00, 0x3d, 0xfa, 0x40, 0x07, 0x8f,
+  0xc7, 0x11, 0xf1, 0x5e, 0x55, 0x5a, 0xe7, 0x47, 0x47, 0xe4, 0x9e, 0x6a,
+  0x88, 0x10, 0xdf, 0x17, 0x11, 0xf1, 0x84, 0x6b, 0xd0, 0x05, 0x84, 0xe9,
+  0x3f, 0x44, 0xe9, 0x62, 0x5c, 0x1a, 0xdf, 0x4e, 0x00, 0x78, 0x00, 0xbb,
+  0xb1, 0x3d, 0x63, 0x9f, 0xc6, 0x3e, 0x9a, 0xb2, 0xed, 0x19, 0xb1, 0xb1,
+  0x00, 0x39, 0x00, 0x71, 0xf2, 0x00, 0xe0, 0x01, 0x97, 0x4e, 0xce, 0xf9,
+  0xcd, 0xc8, 0x31, 0xf6, 0xea, 0x24, 0x31, 0xa0, 0xe8, 0xdc, 0xd4, 0xac,
+  0x2e, 0xc6, 0x00, 0x00, 0x01, 0x03, 0x43, 0xf9, 0x6d, 0x84, 0xef, 0x3a,
+  0x09, 0x80, 0x07, 0x34, 0x90, 0xde, 0x07, 0x7f, 0x39, 0x63, 0x7b, 0xb7,
+  0x1b, 0xc6, 0xf3, 0x32, 0xc0, 0x8d, 0xe0, 0xbb, 0x14, 0x2a, 0x56, 0xf2,
+  0x02, 0xdc, 0x4f, 0xe5, 0xf3, 0x3c, 0x7c, 0xdc, 0x5a, 0x1c, 0x7a, 0x37,
+  0x04, 0xa6, 0x48, 0xad, 0xe3, 0xa1, 0x6d, 0xd7, 0x6d, 0x55, 0x38, 0x32,
+  0x35, 0x87, 0xed, 0x02, 0x9b, 0x47, 0x21, 0xeb, 0x93, 0xd6, 0x56, 0xae,
+  0x97, 0x24, 0x9b, 0xe2, 0x35, 0xb3, 0x83, 0x99, 0x46, 0xdd, 0xf0, 0x00,
+  0xec, 0x80, 0x58, 0x51, 0xb0, 0x0a, 0x56, 0x5f, 0x6b, 0x05, 0x70, 0x2b,
+  0x22, 0x00, 0x8f, 0x82, 0xc9, 0x76, 0xd2, 0x5b, 0x50, 0xe8, 0x64, 0x8b,
+  0x42, 0x5b, 0x15, 0x0e, 0xad, 0x9c, 0x39, 0xae, 0x0d, 0x6d, 0xf1, 0x73,
+  0x12, 0xdf, 0x4b, 0x0e, 0x09, 0x6f, 0x46, 0xec, 0x00, 0x3d, 0x8f, 0xe0,
+  0xa0, 0xb5, 0x59, 0xe0, 0xde, 0x6e, 0xfe, 0x4d, 0x00, 0x18, 0x37, 0xd0,
+  0x7b, 0x04, 0x2f, 0xf0, 0x7f, 0xb9, 0x94, 0x00, 0x68, 0x9e, 0xa9, 0x1b,
+  0x40, 0x1c, 0xc0, 0x3d, 0x90, 0xd6, 0xec, 0x10, 0x9c, 0xe9, 0x44, 0x35,
+  0x6e, 0x57, 0xb3, 0xed, 0xe7, 0x5d, 0xb1, 0xc0, 0x3d, 0x0e, 0xbd, 0x59,
+  0xe8, 0x85, 0xaf, 0x83, 0x72, 0xb7, 0x1d, 0x9d, 0xbb, 0xcb, 0x8a, 0x1a,
+  0x6c, 0x3f, 0x10, 0xf1, 0x8a, 0xb5, 0xae, 0x15, 0x8f, 0x17, 0xcf, 0x2f,
+  0x2c, 0x31, 0x66, 0x15, 0x1b, 0x48, 0x54, 0x29, 0xb7, 0x71, 0x75, 0xbe,
+  0xbb, 0x9f, 0xbd, 0x8a, 0x99, 0x29, 0xc3, 0x9f, 0x90, 0xaa, 0x36, 0x9d,
+  0x47, 0xb7, 0xb2, 0xe7, 0x1d, 0xf3, 0x1d, 0x90, 0xf3, 0xcd, 0xe6, 0x5b,
+  0x43, 0x46, 0x0d, 0x6f, 0x9a, 0x13, 0x76, 0x90, 0xed, 0xa1, 0xf6, 0xb7,
+  0xbe, 0x70, 0x21, 0x7f, 0xbb, 0xb9, 0x88, 0x01, 0x0b, 0x73, 0x6a, 0x24,
+  0x5a, 0xd3, 0x96, 0xe4, 0x02, 0x9b, 0xf4, 0xda, 0xe9, 0xb6, 0x94, 0x12,
+  0x73, 0x57, 0xef, 0xaf, 0x77, 0x16, 0xf1, 0x14, 0x70, 0x6b, 0x71, 0x30,
+  0x53, 0x88, 0x97, 0xb7, 0x76, 0x60, 0x23, 0xff, 0xea, 0xbe, 0x18, 0xea,
+  0x12, 0x10, 0xda, 0x7d, 0xb8, 0xc7, 0xce, 0x73, 0xb4, 0x87, 0x16, 0x1d,
+  0xb2, 0xaa, 0x90, 0xda, 0x5e, 0xe5, 0xd1, 0xad, 0x8e, 0x8e, 0xb7, 0xd5,
+  0xbe, 0x60, 0x03, 0x39, 0x82, 0x34, 0xce, 0xe4, 0x83, 0x9f, 0x46, 0x0f,
+  0x6f, 0x35, 0x7f, 0x2f, 0x97, 0x21, 0x45, 0x5f, 0x35, 0x81, 0xd6, 0x40,
+  0xea, 0x58, 0x69, 0x0d, 0xbd, 0xe0, 0x03, 0xae, 0x60, 0xb8, 0x6f, 0x0f,
+  0xd0, 0xdf, 0x2a, 0x5e, 0x6a, 0x87, 0x1a, 0x65, 0x3c, 0xe6, 0xe6, 0xff,
+  0xf2, 0x00, 0x38, 0xf6, 0xc1, 0x5d, 0x85, 0xd8, 0xfb, 0xa8, 0xe2, 0xd6,
+  0x07, 0x84, 0x1e, 0x18, 0xdb, 0xe4, 0x34, 0xbc, 0x6e, 0xb7, 0x42, 0x7e,
+  0xcb, 0x9e, 0x0d, 0xf8, 0xc9, 0x22, 0x65, 0x94, 0x2e, 0xd4, 0x58, 0xa7,
+  0x0d, 0x6b, 0xcd, 0x84, 0x67, 0xc7, 0xd9, 0x42, 0x0b, 0x2b, 0xd4, 0x63,
+  0x67, 0x72, 0x48, 0x89, 0x28, 0xd4, 0x76, 0xbe, 0x2d, 0x94, 0xaa, 0x7a,
+  0x8c, 0x6c, 0xb5, 0x05, 0x5c, 0x84, 0xa2, 0x90, 0x29, 0xb7, 0x6f, 0x4e,
+  0x0d, 0x6c, 0x4a, 0x6c, 0xc0, 0x29, 0xb9, 0x20, 0x13, 0x69, 0x22, 0x48,
+  0xdd, 0x42, 0x6e, 0xd8, 0x57, 0x8b, 0x74, 0x7f, 0xe6, 0x09, 0x23, 0x4e,
+  0x1c, 0xfb, 0x03, 0x3b, 0xf3, 0xb1, 0xc8, 0x4d, 0x1a, 0xd9, 0x4b, 0xe5,
+  0xb6, 0x46, 0xe1, 0x80, 0x84, 0x00, 0xc0, 0x7b, 0x7e, 0x78, 0x5e, 0x51,
+  0x7c, 0x45, 0x8d, 0xec, 0x3d, 0xf0, 0xcd, 0x7d, 0x28, 0x02, 0x35, 0x88,
+  0xdb, 0x3b, 0x7d, 0x13, 0x36, 0xf7, 0x02, 0x43, 0xf3, 0x35, 0x27, 0x85,
+  0x6f, 0x6e, 0x45, 0x80, 0x07, 0x0f, 0xe6, 0x96, 0x13, 0x82, 0x7c, 0xec,
+  0x40, 0x82, 0xc0, 0xe6, 0xe4, 0xea, 0xf9, 0x73, 0x94, 0x00, 0x67, 0x00,
+  0xa6, 0xc9, 0xda, 0x41, 0x7f, 0x06, 0x7a, 0xeb, 0x7f, 0x34, 0xf7, 0x94,
+  0x5f, 0x1c, 0x3c, 0x13, 0x3f, 0xe8, 0xa8, 0xde, 0xaf, 0xeb, 0x97, 0xfd,
+  0xd6, 0xed, 0xb4, 0x21, 0x6c, 0x24, 0xb7, 0x43, 0xee, 0xe9, 0x7b, 0xcc,
+  0xb4, 0x26, 0x79, 0xcb, 0x65, 0xf4, 0x1c, 0xd4, 0x80, 0x3a, 0xde, 0x54,
+  0x0c, 0x20, 0xe7, 0xc3, 0xae, 0xe4, 0xa0, 0x53, 0x73, 0x3b, 0x0c, 0x74,
+  0x9c, 0xca, 0x17, 0x6b, 0x57, 0x09, 0xf0, 0xe9, 0xe7, 0x3c, 0x6d, 0x6f,
+  0x88, 0x26, 0x82, 0x17, 0xfc, 0x6e, 0x4f, 0x04, 0xa5, 0x56, 0xe9, 0x1b,
+  0x37, 0x6c, 0xc6, 0xbc, 0x88, 0xfe, 0xc4, 0x4d, 0x7a, 0xc9, 0x50, 0x3a,
+  0xc9, 0x29, 0x9b, 0x14, 0x28, 0x60, 0x4b, 0x75, 0x3f, 0xbd, 0x3f, 0x9f,
+  0x39, 0xe6, 0x1b, 0x8a, 0xa7, 0x4b, 0x10, 0x65, 0x52, 0x82, 0xe0, 0xd6,
+  0xf4, 0x26, 0x51, 0x78, 0x1d, 0x5b, 0x95, 0x0d, 0x53, 0x2b, 0x7e, 0x2f,
+  0xe8, 0xf9, 0x9d, 0x47, 0xf6, 0x58, 0xe9, 0x30, 0xe2, 0xc3, 0xe1, 0x6d,
+  0xdc, 0x50, 0x03, 0xdb, 0xcc, 0x94, 0x00, 0x5d, 0xe0, 0x07, 0xb6, 0x2f,
+  0x97, 0xef, 0xc6, 0x3a, 0xc2, 0xc0, 0x99, 0xe7, 0x65, 0x89, 0x1b, 0x4e,
+  0x59, 0x1f, 0xe7, 0xae, 0xc0, 0x1e, 0x61, 0x92, 0x5f, 0x55, 0xaa, 0x51,
+  0xcc, 0xf6, 0x4e, 0x32, 0x56, 0x76, 0x99, 0x2b, 0x6e, 0xe8, 0x5c, 0xc9,
+  0xe2, 0xa8, 0x78, 0x4b, 0x76, 0x85, 0xf3, 0x34, 0x5c, 0x52, 0x8e, 0xa5,
+  0xed, 0x4a, 0x87, 0x9e, 0x3e, 0x90, 0x9b, 0xcf, 0xec, 0x57, 0x4b, 0x60,
+  0x5a, 0xc9, 0x69, 0x0c, 0x63, 0x7a, 0x01, 0x26, 0x88, 0xb9, 0x32, 0x82,
+  0x48, 0x02, 0x1b, 0x2c, 0xbe, 0x95, 0xb9, 0x2f, 0xe1, 0x4b, 0x6c, 0x4e,
+  0x03, 0xdb, 0xc7, 0xce, 0xcf, 0x67, 0xf1, 0x1f, 0x83, 0xca, 0xb6, 0x20,
+  0x06, 0xcd, 0xb8, 0xd9, 0xcb, 0x94, 0xb0, 0xa1, 0x88, 0xdc, 0xf9, 0x2c,
+  0x4a, 0xb6, 0x85, 0x14, 0x42, 0x6c, 0xbb, 0x0d, 0x48, 0xd6, 0x51, 0x8f,
+  0x21, 0x4a, 0xd4, 0x74, 0x6f, 0xdf, 0x89, 0x76, 0xf2, 0xe7, 0xcd, 0x32,
+  0xc4, 0x4b, 0x52, 0xca, 0x5c, 0x08, 0x2c, 0x6b, 0x76, 0x88, 0xa4, 0x41,
+  0x62, 0xed, 0x96, 0x71, 0xb0, 0xa4, 0x37, 0x2d, 0x91, 0x60, 0x69, 0x6d,
+  0xee, 0x00, 0x18, 0x6f, 0x20, 0x0d, 0x48, 0xff, 0xd7, 0x2c, 0xb5, 0x4b,
+  0x27, 0xf3, 0x91, 0xf3, 0x6a, 0x20, 0x04, 0xc5, 0x95, 0x10, 0x36, 0x0f,
+  0x6f, 0x4c, 0x00, 0xc0, 0x57, 0x3e, 0xc0, 0x16, 0xcd, 0xba, 0x30, 0xcc,
+  0x28, 0xed, 0xa7, 0xcf, 0x35, 0x94, 0xe0, 0xb6, 0x39, 0xdc, 0xb1, 0x25,
+  0x09, 0x42, 0xd1, 0x8d, 0x7c, 0x87, 0x20, 0x53, 0x7b, 0xc0, 0x1b, 0x5d,
+  0x00, 0x7f, 0xc3, 0xdf, 0xc6, 0xa1, 0x68, 0x61, 0x3c, 0xdb, 0x65, 0xf1,
+  0x2d, 0xbd, 0xc3, 0x7c, 0x6c, 0x01, 0xa0, 0x9e, 0xd3, 0x9d, 0xd9, 0xd8,
+  0xeb, 0x73, 0x5f, 0x76, 0xdd, 0x41, 0xe1, 0x6d, 0xcf, 0x00, 0x64, 0x44,
+  0xea, 0x6c, 0x36, 0xdb, 0x40, 0x95, 0x2e, 0x9b, 0x42, 0x5b, 0x32, 0x36,
+  0xba, 0x8b, 0x9b, 0x8e, 0xb4, 0x78, 0x6d, 0x87, 0x1e, 0xda, 0x08, 0xb3,
+  0x75, 0x64, 0x6f, 0xeb, 0x3f, 0xcf, 0x7e, 0x85, 0x77, 0x8f, 0xcd, 0x55,
+  0x87, 0x48, 0x75, 0x4a, 0x48, 0x6e, 0x00, 0xb0, 0x06, 0xe0, 0x07, 0xdc,
+  0xd2, 0x33, 0xa7, 0x38, 0x54, 0x92, 0x1b, 0xa9, 0x5c, 0xa5, 0x64, 0x31,
+  0x07, 0x37, 0x88, 0x00, 0x36, 0x20, 0x88, 0xa5, 0x8b, 0x90, 0xfc, 0xe2,
+  0xcb, 0x24, 0x55, 0x01, 0xec, 0x6e, 0x37, 0xcf, 0xcf, 0xf0, 0x55, 0x99,
+  0xf1, 0xe7, 0x4f, 0x77, 0x7b, 0x22, 0xc1, 0xab, 0x4f, 0x83, 0x23, 0x3f,
+  0x8e, 0x37, 0x5c, 0x81, 0xf0, 0xea, 0x95, 0x0b, 0xad, 0x5c, 0x65, 0x41,
+  0xad, 0xc0, 0x02, 0xe1, 0x53, 0xfc, 0x2a, 0x6b, 0xe8, 0x6d, 0xd7, 0x86,
+  0xa1, 0x4d, 0xdc, 0x23, 0x00, 0x3c, 0xe8, 0x01, 0xb8, 0x03, 0x8f, 0x3e,
+  0xfd, 0xf9, 0xda, 0x51, 0xb3, 0x99, 0xce, 0xd8, 0x71, 0x43, 0x46, 0x64,
+  0x6f, 0x82, 0x11, 0x25, 0x11, 0xb9, 0x74, 0x0f, 0x1d, 0x46, 0x37, 0xb1,
+  0x00, 0x68, 0x44, 0xa0, 0x0e, 0xc4, 0x60, 0x9f, 0x9e, 0xcc, 0x5b, 0x35,
+  0xff, 0x9d, 0xd4, 0x37, 0x00, 0xc2, 0x7e, 0x14, 0x38, 0xa3, 0xe8, 0x5b,
+  0x6f, 0xe4, 0x41, 0xb2, 0x46, 0x84, 0x8f, 0x49, 0x11, 0x80, 0x00, 0x00,
+  0x01, 0x04, 0x43, 0xf9, 0x8e, 0xd8, 0xe7, 0x69, 0x90, 0x2f, 0x79, 0x44,
+  0x6c, 0xf5, 0xf4, 0x47, 0x79, 0x4e, 0x1e, 0xb2, 0x59, 0x54, 0x21, 0x18,
+  0x3d, 0xd3, 0x49, 0x98, 0x1a, 0x07, 0x35, 0x22, 0x72, 0x71, 0xd1, 0x70,
+  0xe2, 0xd5, 0x75, 0x0a, 0x50, 0xd6, 0xf3, 0x52, 0xc6, 0xf1, 0xd1, 0xbc,
+  0xba, 0xa0, 0x16, 0x17, 0xea, 0x39, 0xb4, 0x7c, 0xd3, 0x0d, 0x92, 0x8f,
+  0x92, 0x27, 0x8b, 0x58, 0x28, 0x9f, 0xbc, 0xcd, 0xba, 0x52, 0x87, 0x5c,
+  0x52, 0xdb, 0x41, 0x13, 0xb9, 0xcc, 0x42, 0x74, 0xa3, 0xeb, 0x86, 0x6d,
+  0x55, 0x3a, 0xd6, 0x71, 0xf2, 0x2a, 0x33, 0xa3, 0x9b, 0xf2, 0xde, 0xee,
+  0xd7, 0x3e, 0x15, 0x95, 0x81, 0x1f, 0x8d, 0xe4, 0x44, 0xba, 0x14, 0x7c,
+  0xb2, 0xb7, 0xb1, 0x10, 0xab, 0x32, 0xdf, 0x09, 0x15, 0x5b, 0xb3, 0xda,
+  0xfd, 0x79, 0x12, 0xb9, 0x28, 0x45, 0x92, 0x42, 0x13, 0x72, 0xcb, 0x16,
+  0x12, 0x58, 0x54, 0x46, 0xfc, 0x88, 0x03, 0xf4, 0xb4, 0x9f, 0x54, 0x05,
+  0x51, 0x7c, 0x9d, 0xe2, 0xa8, 0x58, 0x59, 0x6c, 0xa2, 0x93, 0xda, 0x1b,
+  0xa8, 0x13, 0xb2, 0xc5, 0x6f, 0x47, 0x25, 0x15, 0xce, 0x5c, 0xa0, 0x94,
+  0x01, 0x19, 0x6d, 0x04, 0xbf, 0xfd, 0x56, 0xf1, 0xd0, 0x0c, 0x15, 0x6f,
+  0xa3, 0x77, 0x0f, 0x56, 0xd0, 0xe6, 0xe8, 0xb3, 0xcf, 0xac, 0xd4, 0xf5,
+  0x29, 0xba, 0x1b, 0xf8, 0x39, 0xb0, 0xcc, 0x9f, 0x3a, 0xe9, 0xa4, 0x26,
+  0xee, 0xbf, 0x3f, 0x09, 0x08, 0x6d, 0x34, 0xb9, 0x5a, 0x1b, 0xe4, 0xb7,
+  0x53, 0xd8, 0x10, 0xbf, 0xdf, 0x98, 0x4b, 0xd8, 0xb3, 0xc5, 0xa8, 0xef,
+  0x3c, 0xae, 0xc5, 0x08, 0x59, 0x49, 0x32, 0x8c, 0x6e, 0x74, 0x2e, 0xd2,
+  0x4b, 0x21, 0xac, 0x37, 0xf5, 0x69, 0xf9, 0x52, 0x5c, 0x88, 0x4b, 0x6c,
+  0x4f, 0xa0, 0x16, 0xf3, 0xe7, 0x68, 0x04, 0x1b, 0x8b, 0xe2, 0x91, 0x09,
+  0x0c, 0xb9, 0x00, 0x0d, 0xf0, 0x5c, 0x04, 0xcf, 0xfd, 0x5a, 0x49, 0x67,
+  0xe1, 0x31, 0xfc, 0x19, 0xb4, 0x30, 0xd7, 0x1b, 0x3d, 0x14, 0xef, 0x14,
+  0xac, 0xc6, 0x23, 0x41, 0xe0, 0x73, 0x7e, 0x53, 0x78, 0xdf, 0xb7, 0x3f,
+  0x1c, 0x73, 0x20, 0x6a, 0xe6, 0x72, 0x60, 0xe2, 0x62, 0xa5, 0xf5, 0x6d,
+  0xbf, 0x6c, 0x84, 0x7f, 0xad, 0x4e, 0x2c, 0x80, 0x4e, 0xf3, 0x32, 0xe6,
+  0xc3, 0xe9, 0x49, 0x06, 0xb6, 0x69, 0xc6, 0x4f, 0x8e, 0x04, 0x3d, 0xf3,
+  0x29, 0x36, 0x5e, 0x73, 0x7c, 0xcc, 0x96, 0x2a, 0x15, 0x51, 0x67, 0x85,
+  0x8d, 0x89, 0xfa, 0x7c, 0x84, 0x39, 0x80, 0x5b, 0x3b, 0x52, 0x54, 0x6f,
+  0x57, 0x69, 0xb9, 0xb6, 0x37, 0xf4, 0x70, 0x07, 0x22, 0xe7, 0xc7, 0xdb,
+  0x78, 0x7b, 0xc2, 0x73, 0x2c, 0xb1, 0x17, 0xf1, 0x1b, 0xe7, 0x3f, 0x7e,
+  0xb7, 0xfc, 0x47, 0x9e, 0x41, 0x17, 0x28, 0xed, 0x3a, 0xc6, 0xf7, 0xbf,
+  0xe7, 0x82, 0x0f, 0xf6, 0x4a, 0x2e, 0x00, 0x41, 0xba, 0xb7, 0x28, 0x5b,
+  0x7b, 0xad, 0xda, 0x4e, 0xb7, 0x25, 0x0c, 0xb5, 0x0a, 0x6e, 0x5c, 0x8b,
+  0xb2, 0xc6, 0xe1, 0xe3, 0x10, 0x5c, 0xb2, 0x04, 0x2b, 0x7f, 0x9e, 0x2d,
+  0xf3, 0xf3, 0x03, 0x87, 0x86, 0x96, 0xdd, 0x61, 0x38, 0xed, 0x77, 0xcc,
+  0x35, 0x60, 0xfb, 0x64, 0xa6, 0x0d, 0x1f, 0x69, 0x6d, 0x39, 0xb4, 0x01,
+  0xb0, 0x9f, 0xf7, 0x2f, 0xd0, 0x9d, 0x7f, 0x0a, 0xeb, 0x69, 0xe0, 0x4c,
+  0xa8, 0xdd, 0x27, 0x15, 0x9d, 0xed, 0x0b, 0x57, 0xea, 0x96, 0x03, 0x26,
+  0xd2, 0x2b, 0xa2, 0x90, 0xf6, 0x36, 0xf0, 0x0c, 0x4b, 0x00, 0x06, 0x72,
+  0xb7, 0xa6, 0x02, 0x17, 0xf8, 0x91, 0x63, 0xa4, 0x80, 0x3d, 0x37, 0xdf,
+  0x78, 0x33, 0x21, 0xe4, 0xd5, 0x2a, 0x20, 0x4b, 0x7d, 0x7b, 0xe6, 0x02,
+  0x0f, 0xf5, 0x80, 0x2c, 0xfe, 0x66, 0x89, 0xe2, 0x69, 0x59, 0x9b, 0xef,
+  0xed, 0xe7, 0x27, 0x91, 0xf6, 0x93, 0xf6, 0x54, 0xa0, 0x11, 0x4b, 0x5b,
+  0xe5, 0x30, 0x10, 0xbf, 0xea, 0xbe, 0xd8, 0x37, 0xf5, 0x62, 0x6d, 0xbe,
+  0x0d, 0xd8, 0xfa, 0x7f, 0xb8, 0x00, 0x77, 0xef, 0x9e, 0x69, 0x47, 0xa3,
+  0xb8, 0xf3, 0xc8, 0x32, 0x87, 0xe9, 0x52, 0x2b, 0x73, 0xce, 0x6e, 0x26,
+  0x45, 0x08, 0x2d, 0xb8, 0xf2, 0xa2, 0x23, 0x7e, 0xbf, 0x1f, 0x9b, 0x73,
+  0x53, 0x60, 0x4c, 0x29, 0x46, 0x52, 0xdb, 0xa4, 0x00, 0xa4, 0x8b, 0x9f,
+  0x7e, 0x05, 0x88, 0x9a, 0xe9, 0x46, 0x51, 0x5f, 0x4f, 0x73, 0x37, 0xcc,
+  0xf9, 0xfa, 0x85, 0xa9, 0xe3, 0x9b, 0xe7, 0x22, 0xe0, 0x01, 0xf6, 0x8a,
+  0x8f, 0xd0, 0x9b, 0x78, 0xc4, 0x2c, 0x04, 0x68, 0x53, 0x7b, 0x5a, 0xa4,
+  0x52, 0x0e, 0x4d, 0x30, 0x05, 0x7c, 0xae, 0x9e, 0x1d, 0x60, 0xd0, 0xb6,
+  0xf2, 0x72, 0x82, 0x17, 0xfd, 0x57, 0x5c, 0x81, 0xb7, 0x4c, 0x29, 0xb0,
+  0x85, 0xec, 0x2b, 0xc6, 0x46, 0xf3, 0x80, 0x14, 0xf0, 0xf0, 0x07, 0x3f,
+  0x4e, 0x7d, 0xb1, 0xd0, 0x27, 0x7a, 0x7e, 0x2b, 0xa5, 0x2e, 0x15, 0x29,
+  0xd5, 0xb2, 0xfc, 0x3e, 0x00, 0x3a, 0xf7, 0xbb, 0x64, 0x41, 0xdd, 0x3a,
+  0x2e, 0x21, 0xc7, 0x16, 0xaa, 0x17, 0x55, 0xbe, 0xac, 0x00, 0xab, 0xa7,
+  0x7c, 0x80, 0x57, 0xbd, 0xbf, 0x68, 0x11, 0xf9, 0xd0, 0xfc, 0x29, 0x00,
+  0x8a, 0x34, 0x92, 0xdf, 0x37, 0x00, 0x75, 0xed, 0xee, 0x00, 0xfb, 0xdb,
+  0x33, 0xa8, 0x47, 0xed, 0xf6, 0x2e, 0x87, 0x1d, 0x31, 0xce, 0x88, 0x54,
+  0x29, 0xbd, 0x47, 0x3e, 0x0b, 0x15, 0x33, 0x4c, 0x09, 0x2e, 0xa5, 0xbe,
+  0x2d, 0xbe, 0x6a, 0xc2, 0xd0, 0x25, 0xbf, 0x9b, 0x57, 0x66, 0xf0, 0x63,
+  0xb2, 0x05, 0x0f, 0x0b, 0x6d, 0x2f, 0x2e, 0xd0, 0x29, 0xb6, 0x88, 0xdd,
+  0xeb, 0x80, 0x09, 0xec, 0x2c, 0x07, 0xb6, 0x4f, 0x16, 0x8e, 0x12, 0x08,
+  0x3f, 0xd8, 0x00, 0xfb, 0x39, 0x4a, 0x3d, 0x60, 0x8e, 0x64, 0xd7, 0x14,
+  0xb0, 0xed, 0x2e, 0x5b, 0x43, 0x28, 0xe6, 0xdc, 0xc5, 0x80, 0x53, 0x4c,
+  0x94, 0xb4, 0x6f, 0x29, 0x1b, 0x9b, 0x7e, 0xa4, 0xe3, 0x32, 0xd4, 0x8b,
+  0x78, 0x8f, 0x4e, 0x4d, 0x01, 0xc2, 0x98, 0x6a, 0x0d, 0x2c, 0xf0, 0xc5,
+  0x6f, 0x68, 0x22, 0xf6, 0x23, 0xe9, 0x05, 0x5e, 0xf2, 0x8e, 0xab, 0xd6,
+  0xba, 0x2c, 0x0f, 0x85, 0x4b, 0x0a, 0x94, 0x28, 0x7b, 0x69, 0x00, 0x5e,
+  0x4f, 0x00, 0x6a, 0x00, 0xe3, 0xdb, 0xb1, 0x79, 0xb4, 0x73, 0x85, 0x93,
+  0xd7, 0x8e, 0x7b, 0x3f, 0x2a, 0x6c, 0x40, 0x1c, 0x51, 0x8d, 0xfa, 0x34,
+  0x01, 0x0f, 0xdf, 0x5f, 0x44, 0x89, 0xcc, 0x90, 0xbb, 0x43, 0xde, 0xf2,
+  0xc7, 0xdf, 0x5a, 0xd4, 0x2c, 0xae, 0x34, 0xbf, 0x06, 0xd9, 0xe5, 0xbb,
+  0x4b, 0x6f, 0xf2, 0x77, 0x29, 0xc4, 0x85, 0xb6, 0x7e, 0xe2, 0xd8, 0x8d,
+  0xfa, 0xc8, 0x00, 0x9c, 0x01, 0xc8, 0xbd, 0xd8, 0x1d, 0x1d, 0x90, 0x98,
+  0x12, 0xd9, 0x40, 0x08, 0x7f, 0xfa, 0x46, 0x11, 0x49, 0xe2, 0x64, 0x2a,
+  0x79, 0x98, 0xb4, 0xab, 0x4a, 0x8d, 0x98, 0x9e, 0x25, 0xb4, 0xf6, 0x5d,
+  0xba, 0x55, 0x3d, 0xbf, 0x9b, 0x80, 0x3b, 0xf8, 0x70, 0x02, 0xf2, 0x30,
+  0x03, 0xbb, 0xde, 0xad, 0xa5, 0x66, 0x80, 0x1e, 0x4e, 0x26, 0xbb, 0x50,
+  0xba, 0x7e, 0xd4, 0x48, 0x58, 0x4b, 0x79, 0xa2, 0x27, 0x0f, 0xf7, 0xeb,
+  0x48, 0xfd, 0x5a, 0x32, 0xc4, 0xeb, 0x72, 0x2c, 0x38, 0xed, 0xb5, 0x61,
+  0x0a, 0x37, 0xe9, 0x7f, 0x9d, 0xbf, 0x5f, 0xef, 0xb8, 0xbd, 0xf5, 0xed,
+  0xf6, 0xc8, 0x15, 0x87, 0x48, 0x14, 0xdf, 0x9f, 0x80, 0x1e, 0xf5, 0xa0,
+  0x05, 0x14, 0x8d, 0xec, 0x2c, 0xe2, 0xe3, 0xed, 0xc1, 0x0e, 0x79, 0x47,
+  0x13, 0x0b, 0xa9, 0xe0, 0x5a, 0xb4, 0x8b, 0xa4, 0xe3, 0x4e, 0x0a, 0x4b,
+  0x63, 0x3e, 0x7f, 0x0a, 0x4a, 0xa7, 0x37, 0xcd, 0xfb, 0xb9, 0xc2, 0xdd,
+  0xc6, 0xeb, 0xec, 0x1b, 0x92, 0x59, 0xfb, 0x39, 0xbe, 0x96, 0x00, 0xfc,
+  0x5e, 0x09, 0xf7, 0x13, 0x38, 0xe8, 0x6a, 0x68, 0x05, 0x44, 0xcc, 0x7d,
+  0x01, 0x5e, 0xd2, 0x8e, 0x1a, 0xad, 0xf3, 0x5f, 0xee, 0x7b, 0x7d, 0x44,
+  0x5d, 0x15, 0x62, 0x25, 0x9b, 0xa1, 0x86, 0x14, 0x6f, 0x89, 0x41, 0x25,
+  0x56, 0xfb, 0x57, 0xf0, 0x8b, 0x84, 0x5f, 0xbf, 0x7b, 0xc6, 0x8c, 0x47,
+  0x64, 0x87, 0x3a, 0x21, 0x54, 0x7d, 0x3d, 0xb8, 0x7b, 0x78, 0x05, 0xa4,
+  0xc9, 0xa1, 0x91, 0x1a, 0x1f, 0xa4, 0xfa, 0x52, 0xb7, 0xe4, 0x88, 0x00,
+  0x15, 0x0a, 0x16, 0x96, 0xac, 0x55, 0x7d, 0x7e, 0x99, 0x86, 0xd2, 0xce,
+  0xb0, 0x6d, 0x09, 0x6f, 0x19, 0xe7, 0x3d, 0xac, 0x8e, 0x7e, 0xd5, 0x36,
+  0x9f, 0x86, 0xd5, 0x0b, 0x6f, 0x60, 0x00, 0xe8, 0x8b, 0x08, 0xc8, 0xfd,
+  0x99, 0xa5, 0x96, 0xeb, 0x26, 0x45, 0x0b, 0xaa, 0x73, 0x7c, 0x9f, 0xda,
+  0xd0, 0x06, 0xdf, 0x42, 0x27, 0x62, 0xc0, 0x45, 0xe6, 0xfb, 0x56, 0x0c,
+  0x26, 0x4b, 0x0a, 0x2d, 0xa7, 0x93, 0x27, 0x42, 0x16, 0x0f, 0x53, 0x69,
+  0xd0, 0x69, 0xc5, 0xb7, 0x3d, 0xb2, 0x4c, 0x58, 0xdf, 0x24, 0x01, 0xf9,
+  0x3b, 0xa1, 0x04, 0x6e, 0xc4, 0xfc, 0x6a, 0x5b, 0x3c, 0xe3, 0xb7, 0x83,
+  0x43, 0xe0, 0x65, 0xb0, 0xab, 0x65, 0x46, 0xfd, 0x38, 0x00, 0x8c, 0x8a,
+  0x08, 0x3f, 0xcc, 0x00, 0xfc, 0x8e, 0xf0, 0x0b, 0x34, 0x11, 0xc0, 0x13,
+  0x8f, 0x20, 0x31, 0x0a, 0x53, 0xb4, 0x7e, 0x9f, 0xe8, 0xde, 0x0f, 0xfb,
+  0xcd, 0x00, 0x4a, 0x47, 0xd7, 0x79, 0x41, 0xf8, 0x01, 0x66, 0x49, 0x6e,
+  0xd3, 0xc0, 0x72, 0x19, 0x09, 0x2d, 0xef, 0xdd, 0x1d, 0x04, 0xbe, 0x19,
+  0x80, 0x2b, 0xc7, 0x07, 0x6a, 0x0e, 0x45, 0x43, 0x9b, 0xd6, 0xe3, 0x6f,
+  0x39, 0x15, 0x60, 0xca, 0x6c, 0xab, 0x47, 0x37, 0x6c, 0xa6, 0xd6, 0x00,
+  0x00, 0x01, 0x05, 0x43, 0xf9, 0x7d, 0x74, 0xbc, 0x58, 0xed, 0x01, 0x5e,
+  0xd0, 0x82, 0x99, 0x05, 0xde, 0x29, 0x32, 0x84, 0xea, 0x9f, 0x46, 0x37,
+  0x4e, 0x3e, 0x5b, 0x4c, 0xb6, 0x0e, 0x68, 0x2b, 0xdd, 0xc6, 0x95, 0x92,
+  0xc5, 0x4d, 0xf0, 0x6e, 0x02, 0x9b, 0xc7, 0xc5, 0xd3, 0xa3, 0x7c, 0xf1,
+  0x6e, 0xbb, 0x25, 0x90, 0x22, 0x69, 0xb2, 0x21, 0x46, 0xb3, 0x0b, 0xe7,
+  0x9a, 0xfd, 0x76, 0x5a, 0xa6, 0xcf, 0x38, 0x8e, 0x9b, 0xa7, 0x19, 0x50,
+  0xc8, 0xdd, 0x93, 0x43, 0x9e, 0x1e, 0xed, 0xb1, 0x66, 0x07, 0x2a, 0xa5,
+  0x6d, 0xbb, 0x45, 0xba, 0x7d, 0x44, 0xce, 0x3b, 0xd2, 0xe5, 0x9d, 0x47,
+  0xd7, 0x75, 0x77, 0x89, 0x15, 0x0f, 0x02, 0x75, 0xb9, 0x4d, 0x27, 0x45,
+  0x3d, 0xb7, 0x2e, 0xa8, 0x1c, 0xdf, 0x96, 0xda, 0x6d, 0x88, 0xde, 0xcd,
+  0xdc, 0x80, 0x1f, 0xf2, 0xfc, 0x92, 0x41, 0xf5, 0xf1, 0x02, 0xe0, 0xda,
+  0x84, 0x36, 0xf2, 0xdc, 0x97, 0xc7, 0x04, 0x8b, 0x1b, 0x03, 0x9d, 0x05,
+  0x7b, 0xf4, 0x6d, 0x9e, 0x18, 0x85, 0xb4, 0x5a, 0x38, 0x86, 0xdc, 0xd4,
+  0xa9, 0x1b, 0xeb, 0x67, 0x37, 0xfd, 0xd6, 0x3b, 0xb7, 0xe4, 0x2c, 0xcc,
+  0xd7, 0x98, 0x8f, 0xb2, 0x15, 0x0b, 0x44, 0x54, 0x6f, 0x1a, 0x08, 0x60,
+  0x0d, 0x55, 0xbb, 0x02, 0x2a, 0xe5, 0xf2, 0xf4, 0x36, 0xd4, 0x6e, 0x56,
+  0xc3, 0x1d, 0x29, 0x2f, 0x25, 0x6f, 0x42, 0x50, 0xea, 0xa4, 0x36, 0xd8,
+  0x7b, 0x7b, 0xc4, 0x82, 0x17, 0xfa, 0xd7, 0xe4, 0x40, 0xb4, 0x46, 0xb4,
+  0x8d, 0xd6, 0xf5, 0xa6, 0xbe, 0xd1, 0x85, 0x41, 0xed, 0xe8, 0x2a, 0xe5,
+  0xe7, 0x49, 0x76, 0xda, 0xde, 0x66, 0x54, 0x73, 0xac, 0xbe, 0x3a, 0x89,
+  0xe2, 0x39, 0xae, 0x87, 0x69, 0xed, 0x27, 0x37, 0xb4, 0x45, 0x00, 0x3e,
+  0x84, 0x5e, 0x57, 0x01, 0x20, 0x00, 0xf9, 0x99, 0x38, 0x9e, 0x0a, 0x5c,
+  0x21, 0x37, 0x9b, 0x81, 0xcd, 0xdb, 0xe9, 0xf3, 0xfd, 0xc7, 0x1e, 0x72,
+  0x51, 0xb2, 0x58, 0xdc, 0x22, 0x63, 0x72, 0x8d, 0xac, 0xce, 0x6f, 0xd2,
+  0x11, 0xb8, 0x04, 0x1f, 0xed, 0xc1, 0x1d, 0xca, 0x13, 0xe7, 0xbb, 0x56,
+  0x0c, 0x19, 0x31, 0xaf, 0xc5, 0x00, 0x74, 0xf2, 0x31, 0x88, 0x1b, 0x37,
+  0xbf, 0x3b, 0x76, 0x1e, 0x03, 0x88, 0x52, 0xa3, 0x72, 0xf9, 0x40, 0x07,
+  0x3b, 0xf1, 0x99, 0x60, 0x4c, 0x32, 0xdb, 0x28, 0x4a, 0xa9, 0x2e, 0x35,
+  0x9c, 0x60, 0x20, 0x80, 0x9f, 0x5e, 0xd2, 0xcf, 0x1e, 0x05, 0xc5, 0xf0,
+  0xbc, 0x92, 0x1b, 0x53, 0xdb, 0xaa, 0xad, 0x45, 0x21, 0xab, 0x7b, 0xf7,
+  0x99, 0xcf, 0x1b, 0x0c, 0xca, 0x39, 0x3d, 0xb5, 0xd3, 0x28, 0xca, 0x76,
+  0xd2, 0xe9, 0x66, 0x36, 0x57, 0x99, 0xf1, 0xcd, 0xbe, 0x55, 0x3f, 0x69,
+  0x66, 0xc1, 0xaa, 0x3e, 0x01, 0xcd, 0xe8, 0xfa, 0x7e, 0x80, 0x33, 0xc2,
+  0x7c, 0xf3, 0x0a, 0xe1, 0xd6, 0x63, 0xa8, 0x0a, 0xe4, 0xb6, 0x94, 0x10,
+  0x18, 0xd9, 0x79, 0xdb, 0xf4, 0xa2, 0x75, 0xf4, 0x2a, 0x7c, 0x9b, 0x84,
+  0x38, 0x8a, 0xda, 0x35, 0xe7, 0xe4, 0xca, 0x4a, 0x6f, 0x85, 0xd0, 0x21,
+  0x7f, 0xd3, 0xd7, 0x77, 0xc2, 0x18, 0xb7, 0xc2, 0xd6, 0xfa, 0xef, 0xd2,
+  0xcf, 0xf8, 0x8d, 0x45, 0x01, 0x14, 0xb2, 0xc8, 0x34, 0x63, 0x7c, 0x75,
+  0x17, 0x72, 0x12, 0xa2, 0x92, 0x0e, 0x6e, 0x8d, 0x90, 0x5f, 0x3a, 0xed,
+  0x30, 0x2a, 0x3e, 0x36, 0x1a, 0x1d, 0x1b, 0x7e, 0x40, 0xc7, 0x56, 0xfa,
+  0x46, 0xee, 0xd8, 0x08, 0x20, 0x27, 0x40, 0x1c, 0x79, 0x4a, 0x17, 0xd6,
+  0x3e, 0xda, 0x17, 0x36, 0x55, 0xa1, 0x4d, 0xec, 0x85, 0xcd, 0xf7, 0x17,
+  0xbc, 0x10, 0x2d, 0x2f, 0x6d, 0x0f, 0xc7, 0x9a, 0xf1, 0x87, 0x06, 0x50,
+  0x96, 0xf0, 0xfd, 0x02, 0x10, 0x06, 0x8a, 0xe8, 0x41, 0x0b, 0x63, 0xf7,
+  0x3c, 0x26, 0xd6, 0xf7, 0x3f, 0xcd, 0x84, 0x7d, 0x12, 0x84, 0x3b, 0x57,
+  0xc4, 0x7f, 0xab, 0x71, 0x4c, 0x00, 0xab, 0x76, 0x5f, 0x57, 0xa5, 0xcf,
+  0x16, 0xe4, 0xb8, 0x40, 0xd7, 0x80, 0x0c, 0x6a, 0xb7, 0xe7, 0xb5, 0xd5,
+  0xd7, 0x8e, 0x28, 0xc4, 0x57, 0xc9, 0x4e, 0xb4, 0xba, 0x5d, 0x6f, 0xa0,
+  0xe6, 0x0b, 0xff, 0x8a, 0x17, 0x79, 0xf2, 0x59, 0x2c, 0x37, 0x3a, 0xe6,
+  0xba, 0x18, 0x7c, 0x2e, 0x01, 0xed, 0xe5, 0xba, 0xe4, 0x00, 0xe3, 0xa1,
+  0x7d, 0x3e, 0xd8, 0x3c, 0xed, 0xb2, 0x85, 0x18, 0x5b, 0x7a, 0x3c, 0x73,
+  0xc1, 0x03, 0xf3, 0x39, 0xe2, 0xd9, 0x88, 0x71, 0x3b, 0xbe, 0x3c, 0xe9,
+  0x67, 0xc0, 0xe2, 0xe0, 0x14, 0xd9, 0x77, 0x41, 0x08, 0x01, 0xab, 0xe2,
+  0x10, 0x9b, 0x91, 0xe0, 0x67, 0x89, 0x72, 0xb7, 0xe4, 0x7e, 0x3a, 0x00,
+  0xb3, 0x5d, 0x85, 0xd9, 0x6c, 0x52, 0x8b, 0xbe, 0xb0, 0x08, 0x6e, 0x98,
+  0x03, 0xed, 0x78, 0x03, 0xf1, 0x66, 0x3b, 0x8c, 0x83, 0x97, 0x30, 0x9a,
+  0x5a, 0x40, 0xe9, 0x6c, 0x3e, 0x86, 0xb7, 0xe9, 0x10, 0x40, 0xfd, 0x40,
+  0x07, 0x3d, 0xf0, 0x00, 0xf3, 0x8f, 0x61, 0x5a, 0xec, 0x85, 0xf2, 0xff,
+  0x24, 0x29, 0xc6, 0x87, 0x7e, 0x83, 0x24, 0x6d, 0x60, 0x04, 0xa0, 0x0e,
+  0x7d, 0xfa, 0x17, 0xb8, 0xf9, 0xe5, 0x92, 0x4c, 0x97, 0xcd, 0xf9, 0x13,
+  0x6d, 0x32, 0x1c, 0xdd, 0x9f, 0x27, 0xad, 0x50, 0xb6, 0xea, 0x16, 0x7c,
+  0xb5, 0x5b, 0xfc, 0xda, 0x00, 0xf3, 0xe3, 0xbe, 0x39, 0xf2, 0xe1, 0xef,
+  0xe4, 0xb5, 0xcc, 0x78, 0x01, 0xf3, 0x88, 0x3b, 0xe5, 0x09, 0xf2, 0x42,
+  0xac, 0x4b, 0x54, 0x7d, 0xad, 0xd4, 0xe2, 0xec, 0x15, 0xb8, 0x64, 0x08,
+  0xb9, 0xb4, 0xf1, 0x9e, 0x10, 0x2d, 0xbe, 0xb6, 0x00, 0x8f, 0xa8, 0x00,
+  0xc0, 0x01, 0x16, 0xef, 0x3c, 0xf2, 0x85, 0xf9, 0x63, 0xc4, 0x8b, 0x72,
+  0x53, 0x43, 0xcb, 0x5c, 0x52, 0x4b, 0x6e, 0x04, 0x0f, 0xd3, 0x00, 0xb3,
+  0x28, 0xbe, 0xdf, 0x75, 0xf2, 0x1d, 0x15, 0x6c, 0x8d, 0xbb, 0xe5, 0xba,
+  0xb7, 0xd6, 0x42, 0x98, 0xee, 0x79, 0x6c, 0xb6, 0x37, 0xf8, 0xdd, 0xd8,
+  0x00, 0x26, 0x5a, 0x09, 0x80, 0x06, 0xe9, 0x67, 0xab, 0x7d, 0x14, 0x10,
+  0x3f, 0x38, 0x8c, 0x08, 0x3f, 0xae, 0x00, 0xf3, 0x04, 0x08, 0x23, 0xf0,
+  0x84, 0xd3, 0x3e, 0x5f, 0xb2, 0x10, 0x38, 0x42, 0x7d, 0x85, 0x86, 0xb8,
+  0x6b, 0x7e, 0xaa, 0x00, 0x27, 0x00, 0x7e, 0x2c, 0x01, 0xc8, 0x03, 0xb7,
+  0x82, 0x10, 0x03, 0x3f, 0x6a, 0x4c, 0xeb, 0xae, 0xa9, 0x50, 0xcb, 0x4d,
+  0xda, 0x81, 0x2d, 0xed, 0xb0, 0x3a, 0xd5, 0x6e, 0x9d, 0x2e, 0xb6, 0xda,
+  0x5d, 0xa8, 0xde, 0x62, 0x28, 0x9e, 0x48, 0xbf, 0x71, 0x62, 0xc4, 0xf7,
+  0xa0, 0x3d, 0xde, 0x5e, 0xfb, 0x74, 0x74, 0x85, 0x0e, 0x92, 0x23, 0x74,
+  0xdb, 0x2e, 0x16, 0xc7, 0x22, 0x36, 0xcd, 0xab, 0x61, 0xd3, 0xcb, 0x69,
+  0x21, 0xa7, 0x54, 0x83, 0xd5, 0x95, 0xb1, 0xe0, 0x21, 0x00, 0x35, 0xd6,
+  0xc0, 0xe8, 0x00, 0x6f, 0x65, 0x9e, 0xb9, 0x24, 0x66, 0xc3, 0x70, 0x53,
+  0xa8, 0x03, 0x0f, 0x7f, 0xaf, 0x5b, 0x1c, 0x5c, 0x57, 0xd2, 0x03, 0xec,
+  0x93, 0x24, 0x2e, 0xa8, 0xe3, 0x83, 0x1b, 0xe6, 0xe6, 0x91, 0x1e, 0x44,
+  0xfb, 0x80, 0x5a, 0xf1, 0x24, 0xd7, 0x16, 0xfa, 0xf9, 0x03, 0x89, 0x96,
+  0x19, 0xb3, 0x03, 0x0a, 0x19, 0x1b, 0xed, 0x0a, 0x1d, 0x69, 0x21, 0xbf,
+  0x18, 0xbd, 0xc0, 0x06, 0x8f, 0xf8, 0x7c, 0xa1, 0xab, 0x3e, 0x28, 0xa4,
+  0x04, 0xb0, 0x03, 0x31, 0x47, 0x8e, 0x6f, 0x2e, 0x50, 0x03, 0xea, 0x92,
+  0x78, 0xd2, 0xc9, 0x4d, 0xc9, 0x00, 0xc6, 0xa3, 0x7e, 0x9b, 0xfe, 0x2b,
+  0x3b, 0xeb, 0x8b, 0xbd, 0xc1, 0xd7, 0x31, 0xcf, 0xd8, 0x62, 0x15, 0x2a,
+  0x1c, 0x7b, 0x75, 0xb2, 0x76, 0x45, 0x17, 0xed, 0xbf, 0xee, 0x2e, 0x96,
+  0x99, 0x8f, 0xd2, 0xe2, 0x42, 0xc7, 0x0d, 0x6e, 0x01, 0x13, 0x1c, 0x00,
+  0xa4, 0x4f, 0xb7, 0x6e, 0xd8, 0x38, 0x02, 0x9d, 0xe1, 0x66, 0xd3, 0xd5,
+  0x20, 0xd6, 0xfa, 0x8c, 0x17, 0x80, 0x0f, 0x38, 0x9f, 0x8c, 0xa9, 0x15,
+  0x4d, 0xc9, 0x25, 0x1a, 0x31, 0x54, 0xa6, 0xf3, 0x9e, 0x9c, 0xcd, 0x58,
+  0xa3, 0x91, 0x51, 0x28, 0x5b, 0x72, 0xd2, 0xe5, 0x95, 0xbc, 0x00, 0x0e,
+  0x7e, 0xef, 0x23, 0x47, 0xe3, 0xf5, 0xce, 0x2a, 0x13, 0xc3, 0xd5, 0x14,
+  0x04, 0x45, 0x29, 0x29, 0xbe, 0x72, 0x00, 0xf7, 0x0d, 0x17, 0xed, 0xc7,
+  0x7c, 0x00, 0xaa, 0x4e, 0x35, 0xea, 0xf2, 0xc7, 0x42, 0xa9, 0x47, 0x9e,
+  0xde, 0xf3, 0x3a, 0x7f, 0x3b, 0xcb, 0xd3, 0x06, 0x5c, 0x26, 0x96, 0xa3,
+  0x0b, 0x43, 0xda, 0xae, 0xa7, 0xbf, 0x31, 0x34, 0xc4, 0x1b, 0x38, 0xbc,
+  0x42, 0xae, 0xd0, 0xc5, 0x6e, 0xbd, 0xbb, 0xb2, 0xe1, 0xb4, 0x34, 0xc4,
+  0x56, 0xa5, 0xa8, 0x8a, 0xdf, 0x40, 0x8d, 0x39, 0xfe, 0xf1, 0xcc, 0x94,
+  0x68, 0x79, 0x99, 0xdd, 0x8e, 0x8a, 0x5a, 0xab, 0xa8, 0xd5, 0x29, 0xb9,
+  0xc0, 0x0e, 0x05, 0x80, 0x19, 0x73, 0x3a, 0x31, 0x00, 0x25, 0x8f, 0xda,
+  0x4c, 0x94, 0x38, 0xed, 0xf5, 0x6e, 0x48, 0x8e, 0x9f, 0xf1, 0xcb, 0xb7,
+  0xad, 0xb4, 0x05, 0x7c, 0xc2, 0x60, 0xdf, 0x06, 0xf9, 0x71, 0xa0, 0x02,
+  0x6d, 0x15, 0xaf, 0xb2, 0x0c, 0x86, 0xf1, 0xb2, 0xdf, 0x46, 0xc7, 0xb7,
+  0x9a, 0x2c, 0xcb, 0xe9, 0x30, 0xa8, 0xa0, 0x53, 0x25, 0x31, 0xf5, 0x51,
+  0x80, 0x00, 0x00, 0x01, 0x06, 0x43, 0xf8, 0xce, 0x95, 0xb6, 0x28, 0x43,
+  0x6a, 0xca, 0xf1, 0x3b, 0x30, 0xc4, 0x1c, 0x79, 0x7e, 0x81, 0x8d, 0x9b,
+  0x67, 0x9f, 0x09, 0x81, 0x4d, 0xd8, 0x13, 0x08, 0x2e, 0x3f, 0xc5, 0x5b,
+  0xc6, 0x45, 0x6f, 0x08, 0x73, 0x68, 0x2b, 0x2b, 0xa4, 0xcc, 0xf1, 0xa3,
+  0x47, 0x35, 0x3d, 0x3a, 0x3b, 0xad, 0x4b, 0x24, 0x1b, 0x55, 0xb6, 0x5d,
+  0x00, 0xb2, 0xda, 0xb0, 0x31, 0x25, 0x2d, 0xb9, 0xe4, 0xdc, 0x6c, 0x49,
+  0x92, 0x44, 0x65, 0x92, 0x45, 0xad, 0xf7, 0xb4, 0x10, 0xbf, 0xc8, 0x67,
+  0xa3, 0x07, 0xf6, 0x40, 0x10, 0x23, 0x97, 0x58, 0x1b, 0x23, 0xbc, 0xd6,
+  0xc0, 0x08, 0xd1, 0xba, 0xcf, 0x04, 0x2f, 0xf1, 0x36, 0x12, 0x9b, 0xc0,
+  0x7b, 0x60, 0x21, 0x80, 0x53, 0xa0, 0x5a, 0x3b, 0x32, 0x97, 0xe1, 0x4b,
+  0x6e, 0x95, 0x58, 0x50, 0x00, 0xd5, 0xac, 0xf6, 0xf6, 0x91, 0x64, 0x23,
+  0x76, 0x9b, 0x9e, 0x2a, 0x8a, 0xd5, 0xa8, 0x01, 0xee, 0x3b, 0x24, 0xf5,
+  0xa7, 0x85, 0x37, 0xab, 0xea, 0xdc, 0x76, 0xba, 0xa8, 0x4c, 0xaa, 0x93,
+  0xc4, 0x63, 0x78, 0xc4, 0xbb, 0xce, 0x52, 0x87, 0x52, 0xa4, 0x54, 0x09,
+  0x6d, 0x00, 0x4a, 0xe5, 0xf5, 0x46, 0xb1, 0xad, 0xfa, 0xd8, 0x1c, 0x68,
+  0x16, 0xde, 0x33, 0x01, 0x08, 0x02, 0xbb, 0x76, 0x6a, 0xf8, 0xe4, 0x01,
+  0xf3, 0x7a, 0x23, 0x29, 0x3b, 0x81, 0x66, 0xba, 0x86, 0xce, 0x5c, 0x74,
+  0x3c, 0xf0, 0xc6, 0xf9, 0xe7, 0x40, 0x84, 0x00, 0xce, 0x10, 0x58, 0x5e,
+  0xcd, 0xc5, 0xa3, 0x8b, 0x4a, 0x31, 0x87, 0x01, 0x8c, 0x9b, 0x48, 0x4d,
+  0x67, 0xc6, 0xfa, 0xc7, 0x48, 0xd5, 0xd2, 0xa4, 0x6d, 0x52, 0x99, 0x24,
+  0xbe, 0xa8, 0x8d, 0xd7, 0x12, 0xe7, 0xff, 0x5c, 0xee, 0x2e, 0x69, 0xf7,
+  0xc9, 0x7c, 0xff, 0x63, 0x0a, 0x1e, 0xc9, 0x93, 0x75, 0x22, 0x7c, 0xd7,
+  0x1e, 0x80, 0x12, 0x4b, 0xbc, 0xdd, 0xa7, 0x7e, 0x8e, 0x28, 0xf3, 0xca,
+  0x6c, 0xef, 0xbe, 0x77, 0x99, 0x28, 0x51, 0x93, 0x64, 0x90, 0x05, 0x45,
+  0x97, 0x02, 0x9b, 0xb0, 0x4e, 0x00, 0x34, 0x73, 0xfc, 0x94, 0xe5, 0xa8,
+  0xe0, 0x17, 0xb5, 0x0e, 0x5b, 0x2b, 0xec, 0xa7, 0x9d, 0x31, 0xdd, 0x87,
+  0xc3, 0xc7, 0xea, 0x7a, 0xb6, 0xa7, 0xab, 0x7a, 0x64, 0xd3, 0x63, 0x79,
+  0x72, 0x80, 0x1b, 0xde, 0x72, 0xcc, 0x87, 0xad, 0xcd, 0xe5, 0x66, 0x05,
+  0xdc, 0x90, 0x86, 0xde, 0x9d, 0xdb, 0x7d, 0x85, 0x09, 0x36, 0x4a, 0x04,
+  0xdc, 0xe7, 0x79, 0x76, 0xda, 0x79, 0xfa, 0xf2, 0xe7, 0xa2, 0xb7, 0x0b,
+  0x8b, 0x7e, 0xbb, 0x5d, 0xda, 0x2c, 0xa6, 0xe4, 0x20, 0x3d, 0xe5, 0x24,
+  0x2e, 0xaa, 0x01, 0x07, 0x8c, 0x69, 0xa8, 0x2f, 0x45, 0x53, 0x29, 0xd4,
+  0x3a, 0x8a, 0x7b, 0xc8, 0x45, 0x07, 0xd0, 0xa2, 0x9b, 0x43, 0x9a, 0x69,
+  0x73, 0x1b, 0xaa, 0x55, 0x8a, 0x80, 0x11, 0x28, 0x0b, 0x9b, 0x4c, 0x03,
+  0x2f, 0x88, 0x9e, 0x38, 0x57, 0x83, 0x63, 0xdf, 0xca, 0xc2, 0x5d, 0x95,
+  0xba, 0xbc, 0x82, 0x10, 0x05, 0x3e, 0x44, 0x00, 0x87, 0x2e, 0x7a, 0x29,
+  0x71, 0xa1, 0xbb, 0x9b, 0xc9, 0xd8, 0x7d, 0xc7, 0xe5, 0x08, 0xbe, 0x52,
+  0xca, 0xdc, 0xc8, 0xbf, 0x4b, 0xef, 0x89, 0x06, 0xd2, 0xa7, 0x2b, 0x14,
+  0x24, 0xa8, 0xde, 0xc7, 0x6c, 0x8e, 0x15, 0x24, 0x2c, 0x27, 0x05, 0x80,
+  0x0c, 0x4e, 0x6c, 0x1d, 0xed, 0xe7, 0x8f, 0x3c, 0x81, 0x0b, 0xc4, 0xb4,
+  0x0a, 0x56, 0x4d, 0x34, 0x3a, 0x56, 0xfc, 0x87, 0xe3, 0xdd, 0x4c, 0xe6,
+  0xc3, 0xf3, 0x0d, 0xb8, 0x90, 0xb2, 0x91, 0x5b, 0xef, 0x8e, 0x78, 0xa0,
+  0x40, 0xfd, 0x31, 0x60, 0x0f, 0x3b, 0xd7, 0x28, 0x0f, 0x77, 0x97, 0x72,
+  0x36, 0x96, 0x57, 0x92, 0xb7, 0xc6, 0x5d, 0xef, 0x99, 0xaf, 0x7f, 0x0f,
+  0x2c, 0xbc, 0xfc, 0x29, 0xdb, 0x49, 0xa5, 0xb5, 0x5e, 0xd9, 0x9f, 0xf2,
+  0x38, 0x8e, 0x39, 0xb2, 0x06, 0x3b, 0x9e, 0x66, 0x68, 0xe0, 0xd1, 0xa1,
+  0x2c, 0x17, 0xb5, 0xbc, 0xb1, 0xb2, 0x37, 0xfd, 0x08, 0xfb, 0x71, 0xdb,
+  0xf7, 0xe0, 0x5c, 0xb1, 0x01, 0x14, 0x01, 0x39, 0x2e, 0x59, 0x65, 0xf1,
+  0x66, 0xff, 0x60, 0xb7, 0x67, 0xc7, 0xbd, 0xcc, 0x4a, 0x08, 0x80, 0x09,
+  0xb6, 0x24, 0xb5, 0x42, 0x46, 0xb7, 0xce, 0x00, 0x09, 0xb6, 0x80, 0x2d,
+  0x00, 0x75, 0xef, 0xaf, 0xa1, 0x86, 0x88, 0x73, 0xec, 0x4a, 0x14, 0x3a,
+  0x84, 0x37, 0xd0, 0xfd, 0xb2, 0xf6, 0xee, 0x6c, 0x4a, 0x02, 0xad, 0x2b,
+  0x14, 0x20, 0x73, 0x74, 0x94, 0x03, 0x46, 0xec, 0x0c, 0x6f, 0xd4, 0xdd,
+  0x27, 0xda, 0x6b, 0x3e, 0x53, 0x35, 0xb0, 0xe0, 0x05, 0x36, 0xb5, 0xd2,
+  0x93, 0xa5, 0x24, 0xb5, 0xc6, 0x51, 0xbb, 0x9d, 0x5b, 0x0e, 0x01, 0x89,
+  0x09, 0x2d, 0x44, 0x86, 0x56, 0xa7, 0x0a, 0x67, 0x19, 0x37, 0xbc, 0x9a,
+  0xd7, 0x4a, 0x5b, 0x62, 0x9f, 0x9c, 0x6d, 0x54, 0x3a, 0x56, 0x6c, 0xdb,
+  0xe2, 0xf0, 0x08, 0x40, 0x13, 0x15, 0xab, 0x00, 0x9f, 0x61, 0x25, 0xb3,
+  0x00, 0xe0, 0x9c, 0x84, 0xb6, 0xdc, 0xab, 0x76, 0x40, 0xa5, 0xcb, 0xb2,
+  0x10, 0x9a, 0x20, 0x75, 0xb0, 0x94, 0xc1, 0xd6, 0xb7, 0xdb, 0x77, 0xe6,
+  0x21, 0x2d, 0xbe, 0x20, 0x00, 0xaf, 0x8a, 0x00, 0x4d, 0x04, 0x7d, 0x39,
+  0x9b, 0x0e, 0xaa, 0xf7, 0x3a, 0xf9, 0x58, 0x30, 0x3a, 0x6d, 0x54, 0x29,
+  0xbe, 0x99, 0xf0, 0xf7, 0x7b, 0xb8, 0xde, 0x70, 0xa2, 0x8b, 0x2e, 0x85,
+  0x37, 0x75, 0xcf, 0xa4, 0x0d, 0xd7, 0x4a, 0x19, 0x6c, 0x8b, 0x15, 0xb8,
+  0xee, 0xa7, 0xb7, 0x20, 0x03, 0xe6, 0xc2, 0xd4, 0xe2, 0xd6, 0xff, 0x23,
+  0x73, 0x2a, 0x9f, 0xe0, 0xb1, 0xbe, 0x90, 0x2b, 0x8d, 0xe7, 0xad, 0xdd,
+  0xcd, 0xa0, 0x2a, 0xda, 0xb1, 0x02, 0x0a, 0xa7, 0x04, 0x2d, 0x6f, 0xa4,
+  0x80, 0x21, 0xfb, 0x80, 0x58, 0x29, 0xce, 0xaf, 0xc8, 0x54, 0x36, 0xad,
+  0x1a, 0xdb, 0x88, 0xbf, 0x5d, 0x12, 0x00, 0xf7, 0x67, 0x31, 0x3f, 0x59,
+  0x32, 0x01, 0x03, 0x6b, 0x72, 0x89, 0x70, 0x05, 0xbc, 0xc4, 0xf5, 0x87,
+  0xb6, 0x3c, 0xcf, 0x3d, 0x84, 0xb8, 0xdf, 0x24, 0x01, 0xcf, 0x1b, 0xf5,
+  0xeb, 0x70, 0x8d, 0xe7, 0x40, 0x05, 0x35, 0x2c, 0xaf, 0x74, 0x3a, 0x24,
+  0xb4, 0x7b, 0x79, 0x72, 0x2f, 0x00, 0x06, 0x9f, 0x51, 0x46, 0xe3, 0xa5,
+  0x28, 0x39, 0x1d, 0x6b, 0xed, 0x52, 0xcf, 0x48, 0x5c, 0x6f, 0x42, 0x00,
+  0xfa, 0x8a, 0xfe, 0x77, 0x66, 0x73, 0x65, 0x96, 0x13, 0x24, 0xab, 0x4b,
+  0x1f, 0x03, 0x0f, 0x6f, 0x2a, 0x08, 0x00, 0x5b, 0xf5, 0xe3, 0x91, 0x35,
+  0xfd, 0x7b, 0x29, 0xd2, 0xe5, 0xda, 0x04, 0x15, 0x9b, 0x2c, 0x0c, 0x28,
+  0x63, 0x77, 0x5a, 0x95, 0x6b, 0x69, 0xb4, 0x38, 0xda, 0x4b, 0x6f, 0x18,
+  0x03, 0x97, 0x67, 0xc8, 0x97, 0x71, 0xc7, 0xb2, 0x1c, 0x5c, 0x73, 0x89,
+  0xa8, 0x34, 0xb6, 0xf9, 0x29, 0x1f, 0x8e, 0x40, 0x1d, 0x5f, 0xa3, 0xed,
+  0xc3, 0xae, 0x5d, 0x9c, 0x3b, 0x26, 0xc8, 0x7c, 0x3c, 0xc2, 0xdb, 0xe8,
+  0x40, 0x05, 0x9e, 0xfd, 0x88, 0xfe, 0x40, 0x0a, 0xf3, 0xe2, 0x55, 0xe2,
+  0x93, 0xb8, 0xe2, 0x07, 0xbd, 0xf3, 0x4c, 0x45, 0xa1, 0x0d, 0xe7, 0x6f,
+  0x45, 0x4e, 0x84, 0x6c, 0x15, 0xaf, 0x7e, 0x57, 0x64, 0x44, 0xd8, 0xf9,
+  0xa5, 0x6e, 0x5f, 0x52, 0xdb, 0x93, 0x97, 0x5f, 0x28, 0x96, 0xc1, 0x95,
+  0x62, 0x2b, 0x48, 0xb8, 0x1c, 0x55, 0x60, 0x00, 0x00, 0x01, 0x07, 0x43,
+  0xf9, 0xef, 0xbc, 0xbd, 0xf1, 0x2e, 0xf8, 0x28, 0xda, 0x7b, 0x6b, 0xe9,
+  0xf8, 0x44, 0xed, 0xfc, 0xf3, 0xe1, 0x2d, 0x92, 0x40, 0xa6, 0xf6, 0xa0,
+  0x0f, 0xc5, 0x69, 0x17, 0xdb, 0x08, 0xe2, 0x62, 0x0d, 0x41, 0x5b, 0xd5,
+  0x93, 0x9b, 0x03, 0xaf, 0xe7, 0x16, 0x20, 0x4b, 0x5c, 0x08, 0x1f, 0x9e,
+  0x44, 0xe0, 0x01, 0x87, 0xff, 0xdf, 0xe2, 0x0a, 0xdb, 0x0a, 0xf3, 0xdb,
+  0xc6, 0xba, 0xcd, 0x87, 0x00, 0x4f, 0xc0, 0x49, 0x54, 0xa0, 0xc6, 0xf2,
+  0xec, 0xb9, 0x6b, 0x78, 0xef, 0x94, 0x3e, 0x56, 0xfe, 0x39, 0x92, 0x3b,
+  0x12, 0x4f, 0x09, 0x1b, 0x66, 0x82, 0x17, 0xfc, 0xcd, 0x6c, 0xfc, 0xca,
+  0x55, 0xb0, 0x25, 0xbd, 0x28, 0x98, 0x4f, 0x17, 0xb4, 0xb0, 0xa7, 0xbb,
+  0x10, 0x30, 0xf5, 0xb2, 0xdf, 0x4a, 0xdc, 0x96, 0x1b, 0x91, 0xb0, 0xd8,
+  0xb1, 0xbb, 0xc4, 0x69, 0x3f, 0xe7, 0x93, 0x00, 0x06, 0x90, 0xb4, 0x08,
+  0x6f, 0x99, 0x4f, 0xd4, 0x21, 0x15, 0x00, 0xa8, 0xdf, 0x53, 0x13, 0x6b,
+  0xf2, 0xcc, 0x50, 0x11, 0x66, 0x2a, 0x8d, 0x3e, 0xc0, 0x29, 0xbe, 0x64,
+  0xf2, 0xab, 0xa9, 0x2a, 0xc6, 0xde, 0xc2, 0xca, 0x21, 0xab, 0x69, 0x43,
+  0xeb, 0x7e, 0xc0, 0x52, 0x91, 0xf6, 0xe9, 0x9a, 0x03, 0xca, 0x61, 0x55,
+  0xbd, 0x30, 0x9d, 0x04, 0x1f, 0xeb, 0x22, 0x0a, 0xa0, 0x15, 0x8e, 0x88,
+  0x64, 0x35, 0x40, 0x21, 0x30, 0xb0, 0xb2, 0x9b, 0xc2, 0xcf, 0xc9, 0xab,
+  0xe1, 0x36, 0xb7, 0xd3, 0xa3, 0x9e, 0x00, 0xff, 0xb7, 0xc3, 0xc3, 0x2c,
+  0x77, 0x2e, 0x31, 0x22, 0x9c, 0x66, 0x9f, 0xe2, 0xb2, 0x36, 0xce, 0x2b,
+  0x6c, 0x80, 0x03, 0x36, 0xb3, 0x9b, 0xbc, 0x8e, 0x47, 0xe9, 0xc0, 0x0f,
+  0x40, 0x1a, 0x64, 0xf6, 0x75, 0xa1, 0xe7, 0xf0, 0x2e, 0x5e, 0xf3, 0x4e,
+  0x54, 0xb1, 0x56, 0xa1, 0x47, 0x14, 0xad, 0xf1, 0xaf, 0xfb, 0xf8, 0x14,
+  0x67, 0x13, 0x75, 0x28, 0x09, 0x40, 0x0f, 0xbc, 0xaf, 0x39, 0x07, 0x15,
+  0x12, 0x4d, 0xa3, 0xcb, 0x18, 0xde, 0xfb, 0xe0, 0xc1, 0x5e, 0xd9, 0xd3,
+  0xf6, 0x86, 0x43, 0x70, 0xf1, 0x84, 0xc2, 0x9b, 0xca, 0xce, 0x5e, 0x00,
+  0xe8, 0x50, 0x8e, 0x44, 0xbf, 0x27, 0xea, 0x4a, 0x2f, 0xcf, 0xbc, 0x83,
+  0x40, 0x71, 0xc6, 0xc8, 0x64, 0xa0, 0x2a, 0x88, 0x5b, 0x72, 0x24, 0xb8,
+  0xe5, 0xf5, 0x91, 0xaa, 0x07, 0xc8, 0xdf, 0x8e, 0xe3, 0x2b, 0x85, 0xbe,
+  0xdc, 0x1e, 0x92, 0x6c, 0x83, 0x42, 0x80, 0xb6, 0xe8, 0x80, 0x34, 0xf8,
+  0x9d, 0xf2, 0xf5, 0xf3, 0x79, 0x6a, 0x6d, 0x2e, 0xad, 0x03, 0x9b, 0x97,
+  0x92, 0x7b, 0x3b, 0xaf, 0x30, 0x08, 0x67, 0x7e, 0x7b, 0x02, 0xe1, 0xb2,
+  0xd9, 0xe1, 0x1b, 0x36, 0x6c, 0xc9, 0x69, 0x41, 0x76, 0x92, 0x9b, 0xbe,
+  0xd6, 0xde, 0xd4, 0x8d, 0xfb, 0x2e, 0x1c, 0x00, 0x6e, 0x2b, 0xcb, 0xac,
+  0x41, 0xa9, 0xb1, 0xd6, 0xca, 0x36, 0xd2, 0xcf, 0x2d, 0x91, 0x2c, 0xd7,
+  0xa9, 0x61, 0x13, 0x99, 0x7d, 0x43, 0x1b, 0x86, 0x46, 0x80, 0x16, 0xf7,
+  0x75, 0x02, 0x2b, 0xf6, 0x44, 0x1f, 0x5b, 0xd4, 0x13, 0x45, 0x3e, 0xdc,
+  0x09, 0xb8, 0xaa, 0x10, 0x74, 0x89, 0x59, 0xb7, 0x58, 0x04, 0xea, 0xda,
+  0x77, 0x63, 0xf3, 0x26, 0xe8, 0x64, 0x27, 0xb9, 0xda, 0x50, 0xd3, 0xb6,
+  0xc3, 0xe0, 0x50, 0xd6, 0xeb, 0x79, 0x80, 0x1d, 0x80, 0x59, 0x2d, 0x1a,
+  0x51, 0x3e, 0x7c, 0x73, 0x74, 0x34, 0x3a, 0xba, 0xd4, 0xb0, 0x21, 0xb9,
+  0x50, 0xcf, 0x7b, 0xb5, 0x7c, 0x33, 0x6e, 0x6c, 0x01, 0x10, 0xdb, 0x60,
+  0x51, 0x8c, 0xee, 0xd2, 0x7c, 0xfb, 0x97, 0x00, 0x45, 0xe6, 0xe5, 0x38,
+  0x08, 0x54, 0x0e, 0x2c, 0x09, 0x6b, 0x6d, 0x87, 0x36, 0xd4, 0xbb, 0x57,
+  0xd6, 0x52, 0x9b, 0xaa, 0xe5, 0xe1, 0xc2, 0xf7, 0x02, 0xcc, 0xdd, 0x4b,
+  0x02, 0xcc, 0x1a, 0xdc, 0xf1, 0x33, 0x78, 0xdc, 0xcc, 0x41, 0xcf, 0x8f,
+  0xf2, 0xb0, 0xbf, 0x16, 0x5e, 0x26, 0x10, 0x66, 0x3f, 0x03, 0x0f, 0xb5,
+  0x4b, 0x2a, 0x9e, 0x31, 0xa5, 0xba, 0x1b, 0x7e, 0xb1, 0x61, 0x9a, 0x16,
+  0x08, 0x5f, 0xf0, 0xbb, 0x84, 0x34, 0x29, 0xb5, 0xd9, 0x05, 0xd7, 0x62,
+  0x06, 0xa1, 0x3a, 0xe4, 0x21, 0x2e, 0x36, 0x7e, 0xd1, 0xdc, 0x73, 0xc7,
+  0x3a, 0x80, 0x4d, 0xc5, 0x26, 0x69, 0xf4, 0xf3, 0xa5, 0x95, 0xb7, 0xe5,
+  0xbb, 0xc5, 0x72, 0x51, 0xa5, 0xc4, 0xee, 0xb8, 0x02, 0x23, 0x1e, 0x70,
+  0x5c, 0x66, 0xd0, 0xdf, 0x89, 0x16, 0x68, 0xaa, 0x21, 0x22, 0x84, 0x8a,
+  0xb8, 0x6a, 0x8f, 0x0c, 0x6a, 0xce, 0xd3, 0x0f, 0x1a, 0xb2, 0x2d, 0x6f,
+  0x4e, 0x2b, 0x34, 0x01, 0xe0, 0xb8, 0xe7, 0xb8, 0x22, 0xed, 0x76, 0xc2,
+  0xd4, 0x72, 0xcb, 0x03, 0x1b, 0xc5, 0x7c, 0x75, 0xce, 0xf4, 0x7e, 0xd0,
+  0xa2, 0xca, 0xa5, 0xc2, 0xa8, 0xe8, 0xca, 0xb7, 0x9b, 0x43, 0xae, 0x12,
+  0x1b, 0xfa, 0xe7, 0xfb, 0xb0, 0x41, 0xfc, 0xf2, 0x38, 0x03, 0xec, 0xe3,
+  0x6c, 0x1d, 0x2b, 0xf8, 0xaf, 0x2d, 0x42, 0x30, 0x94, 0xdf, 0xb3, 0x9d,
+  0xaa, 0xaa, 0xdf, 0xcf, 0x3d, 0x9b, 0xdb, 0xec, 0x8a, 0x02, 0x2d, 0x38,
+  0x7b, 0x7e, 0xb4, 0x00, 0x6d, 0x01, 0x07, 0xf6, 0x3f, 0x84, 0x77, 0xe0,
+  0x25, 0x00, 0x25, 0xec, 0xd9, 0x00, 0x47, 0x06, 0xb5, 0x40, 0xf6, 0xa8,
+  0x1e, 0xdf, 0xd9, 0x78, 0x03, 0x2d, 0xa1, 0xc5, 0x56, 0xe4, 0xe0, 0x19,
+  0xc4, 0x66, 0xe0, 0x0c, 0x5a, 0xdb, 0xb6, 0xed, 0xea, 0xe2, 0x99, 0x1b,
+  0x99, 0xc7, 0xe1, 0xb9, 0x62, 0x2c, 0x96, 0x49, 0xb6, 0x0d, 0x8b, 0x1b,
+  0x8f, 0xf6, 0xd0, 0x03, 0xcf, 0x77, 0xe4, 0x99, 0x4f, 0x9b, 0x2c, 0x59,
+  0xb2, 0xc0, 0xa6, 0x50, 0xaa, 0xd1, 0x2a, 0x37, 0xeb, 0x05, 0x02, 0x17,
+  0xfb, 0xa6, 0xcf, 0x41, 0xad, 0xea, 0x25, 0x36, 0x54, 0x6f, 0xce, 0xdf,
+  0xcf, 0x69, 0xae, 0x14, 0xe5, 0xc5, 0x39, 0xe2, 0xe0, 0xb7, 0x38, 0xd2,
+  0xbf, 0x15, 0x2c, 0xda, 0x75, 0xb0, 0x69, 0x71, 0xbe, 0xde, 0x20, 0x10,
+  0x80, 0x2f, 0xdd, 0xf3, 0xd6, 0x22, 0xb6, 0x3c, 0x5f, 0x37, 0x16, 0x42,
+  0x65, 0x29, 0xb8, 0x5b, 0x78, 0x09, 0x97, 0xa0, 0x4d, 0x00, 0x34, 0x6d,
+  0xbd, 0xc4, 0x14, 0x2f, 0x41, 0x30, 0x01, 0x26, 0x94, 0xde, 0x2c, 0x8d,
+  0xd0, 0x05, 0x62, 0x3d, 0x95, 0xda, 0x1b, 0x39, 0xe3, 0x69, 0x70, 0xe3,
+  0x8b, 0x29, 0xbd, 0x58, 0x80, 0x0a, 0x75, 0xcf, 0x2c, 0x26, 0x6b, 0x96,
+  0x90, 0x95, 0xa7, 0x8d, 0x97, 0x87, 0xca, 0x00, 0x34, 0x2f, 0xd1, 0x2b,
+  0x10, 0x99, 0x54, 0x84, 0xdf, 0x3c, 0x01, 0xb8, 0x9c, 0xf2, 0xae, 0x97,
+  0x1d, 0x16, 0xd7, 0xcc, 0x40, 0x1c, 0xc5, 0xba, 0x70, 0xf6, 0xf3, 0x7c,
+  0x7f, 0x2d, 0xf9, 0xf8, 0x13, 0x7d, 0xa5, 0x01, 0xe3, 0xf1, 0xe8, 0x56,
+  0x54, 0x45, 0x5c, 0x2d, 0x1a, 0xcf, 0x8d, 0x22, 0x00, 0x3a, 0xfb, 0xe5,
+  0x15, 0xd8, 0xbc, 0x2a, 0xcb, 0xaf, 0x4b, 0x32, 0xf0, 0xf8, 0x6c, 0x83,
+  0x4e, 0x1a, 0xde, 0x4c, 0x10, 0x00, 0xb0, 0x48, 0x01, 0xb0, 0x05, 0xb7,
+  0xdf, 0x38, 0xd8, 0xb5, 0x09, 0xd8, 0x4d, 0xba, 0x93, 0x15, 0x5b, 0xe7,
+  0xf3, 0xd9, 0xfc, 0x98, 0x6d, 0x90, 0x71, 0xc3, 0x4e, 0x18, 0x1a, 0x48,
+  0x6c, 0x77, 0x2d, 0x8a, 0xad, 0xfb, 0x80, 0x07, 0x4b, 0xc7, 0x66, 0xf0,
+  0xfc, 0x0c, 0xb3, 0x1e, 0x51, 0x44, 0x8a, 0xde, 0x64, 0x00, 0xb3, 0xdf,
+  0x8f, 0x61, 0x78, 0x6f, 0x1d, 0xe4, 0x2d, 0x2c, 0xd8, 0x53, 0xcc, 0x0e,
+  0xb5, 0xbe, 0x32, 0xff, 0x69, 0x40, 0x1e, 0x57, 0x3b, 0x1d, 0x4a, 0xbb,
+  0x26, 0xe3, 0xcf, 0xee, 0x87, 0xe2, 0x4a, 0x74, 0x30, 0xe4, 0x6e, 0x50,
+  0x00, 0x9f, 0x8c, 0x7a, 0x0a, 0xe9, 0xc3, 0x00, 0x2d, 0x7c, 0xc9, 0x6d,
+  0xfc, 0x5b, 0x2d, 0x92, 0x51, 0xaa, 0x53, 0x7d, 0x01, 0x93, 0x55, 0x20,
+  0x1b, 0x6e, 0xae, 0x64, 0xa4, 0xc8, 0xdf, 0xa6, 0xe0, 0x8b, 0xf6, 0x23,
+  0x7d, 0x3d, 0xba, 0xf6, 0x78, 0xbf, 0x25, 0xf2, 0xdd, 0xa8, 0xbb, 0xa3,
+  0x64, 0x5a, 0x52, 0xa4, 0x29, 0xa8, 0xfb, 0x00, 0x3b, 0x7e, 0x76, 0x41,
+  0xef, 0xd9, 0xcf, 0x92, 0xcf, 0x37, 0x87, 0x2f, 0x94, 0x87, 0x59, 0x14,
+  0x62, 0xb7, 0x91, 0x82, 0x7e, 0xae, 0xc3, 0x7e, 0x66, 0x4c, 0x2f, 0x05,
+  0x3a, 0x19, 0x34, 0xad, 0xa6, 0x94, 0x70, 0xc6, 0xf5, 0x60, 0x09, 0x67,
+  0x42, 0xdf, 0xb1, 0xdf, 0x3a, 0xa1, 0xd4, 0x6d, 0x44, 0x90, 0xba, 0x3c,
+  0x73, 0x59, 0x6d, 0xd0, 0x13, 0x5b, 0xec, 0xfb, 0x08, 0xe9, 0xd9, 0xdd,
+  0x10, 0x00, 0xf4, 0x5e, 0x5b, 0x2e, 0x3f, 0x45, 0xc0, 0x45, 0x00, 0x6d,
+  0xb4, 0xd2, 0x6a, 0x9e, 0x50, 0xf6, 0xf2, 0x1f, 0x40, 0x07, 0xe2, 0xfa,
+  0x4c, 0x00, 0x3e, 0x14, 0xe9, 0x25, 0x9e, 0xce, 0xc2, 0x91, 0xd0, 0x37,
+  0xd6, 0x8f, 0x6e, 0x6f, 0xf5, 0xf9, 0xcf, 0x0e, 0xf3, 0x88, 0x04, 0x3b,
+  0x9c, 0xd2, 0x61, 0xb1, 0x52, 0x98, 0xa5, 0x29, 0xfe, 0x8d, 0xb8, 0x00,
+  0x4e, 0xe7, 0x0b, 0xda, 0x65, 0x45, 0xb8, 0x1d, 0x0d, 0x54, 0x55, 0x21,
+  0x2b, 0x38, 0xc3, 0x00, 0x00, 0x00, 0x01, 0x08, 0x43, 0xf3, 0xc0, 0x0f,
+  0xbd, 0x85, 0x00, 0x3b, 0xfb, 0x8a, 0xeb, 0x9e, 0x5c, 0x74, 0x97, 0xca,
+  0x4d, 0xd3, 0x21, 0x32, 0x45, 0x52, 0xbd, 0x20, 0xe6, 0xfb, 0x10, 0x20,
+  0x01, 0x6b, 0xaf, 0xd7, 0xa9, 0xcf, 0xd1, 0xd7, 0x6f, 0xee, 0x72, 0x65,
+  0xdc, 0x86, 0x87, 0x4a, 0xa5, 0x15, 0xe2, 0xdf, 0x0a, 0x7d, 0xf3, 0xb2,
+  0x44, 0x1c, 0x51, 0x48, 0xde, 0x82, 0x6d, 0x7c, 0x6e, 0x51, 0xf5, 0xbc,
+  0xa2, 0xa5, 0x2d, 0xbe, 0x71, 0x1e, 0xdf, 0x61, 0x7d, 0x2a, 0xc3, 0xe6,
+  0xaf, 0x56, 0x13, 0xd6, 0x1d, 0xf9, 0x88, 0x77, 0x8c, 0x6d, 0x54, 0x0c,
+  0x20, 0x26, 0xff, 0xdd, 0x80, 0x02, 0xd2, 0x43, 0x6a, 0xd5, 0x73, 0xb5,
+  0xef, 0x50, 0xa9, 0x13, 0x50, 0x23, 0x56, 0x95, 0x42, 0x47, 0x35, 0xdf,
+  0x34, 0x50, 0x03, 0x7f, 0xb7, 0xd8, 0x4b, 0x9e, 0xa3, 0x2a, 0x89, 0xc0,
+  0xba, 0x55, 0xbb, 0x4a, 0x0b, 0x2d, 0xb9, 0x6d, 0x5b, 0x2b, 0x03, 0x29,
+  0x24, 0x0e, 0x6f, 0xd2, 0x80, 0x3b, 0x50, 0x05, 0x7f, 0xcf, 0x8d, 0xc3,
+  0x87, 0x76, 0xfd, 0x93, 0x89, 0x60, 0x23, 0xff, 0xed, 0xfd, 0x46, 0xf8,
+  0x80, 0xb3, 0x40, 0x1e, 0x09, 0xf8, 0xb4, 0x2e, 0x68, 0x8d, 0x14, 0xfb,
+  0x01, 0x28, 0x01, 0x75, 0xc4, 0x86, 0xfd, 0xa9, 0xbd, 0xf9, 0x80, 0x3b,
+  0xef, 0x9b, 0x68, 0xeb, 0x7b, 0x73, 0xf7, 0x38, 0x48, 0x5a, 0x07, 0x5b,
+  0x0e, 0x38, 0x75, 0x6f, 0xca, 0x42, 0xaf, 0x3f, 0xce, 0xbf, 0xef, 0xb6,
+  0x86, 0x71, 0x2d, 0x11, 0xed, 0x31, 0xc3, 0x49, 0xae, 0xe1, 0x57, 0x42,
+  0x54, 0x63, 0x68, 0x4c, 0x90, 0x0b, 0x62, 0xd2, 0xdb, 0xf1, 0x6e, 0xa4,
+  0xfb, 0x25, 0x8d, 0xf7, 0xd7, 0x72, 0xf7, 0x38, 0x01, 0xef, 0x74, 0x5b,
+  0xb0, 0x65, 0xe0, 0x57, 0xcf, 0x7d, 0xee, 0x45, 0x3c, 0x08, 0x40, 0x08,
+  0x13, 0x1b, 0xe4, 0xc0, 0x0f, 0xd4, 0x01, 0x18, 0x03, 0xef, 0xa7, 0x28,
+  0x17, 0x5f, 0x6f, 0x19, 0x07, 0x1f, 0x29, 0x70, 0x2a, 0xa3, 0x7e, 0x94,
+  0x00, 0x5b, 0x98, 0x23, 0x9e, 0x70, 0x50, 0x9e, 0x60, 0xc0, 0xfe, 0x37,
+  0x62, 0x43, 0xec, 0x2c, 0x30, 0x2d, 0xbc, 0x1e, 0x85, 0x51, 0x06, 0x3f,
+  0x98, 0xa1, 0x97, 0xf4, 0xad, 0x89, 0x86, 0x1f, 0xea, 0x31, 0xbf, 0xcf,
+  0x40, 0x0f, 0xe6, 0x70, 0xfd, 0xb2, 0x51, 0xf4, 0xdb, 0x64, 0x8d, 0xc9,
+  0xf7, 0xec, 0x00, 0xf1, 0xd6, 0xed, 0x81, 0xb1, 0x68, 0xc8, 0xdd, 0xe1,
+  0x58, 0x00, 0x65, 0xe6, 0xf2, 0xf2, 0x9e, 0x4c, 0x96, 0xac, 0xf0, 0x6f,
+  0x9f, 0x09, 0x9d, 0x09, 0xf8, 0x5a, 0x90, 0x25, 0xda, 0x1d, 0x29, 0xf0,
+  0x6b, 0x75, 0x82, 0x1f, 0xfd, 0x4d, 0x84, 0x2a, 0xc2, 0x1a, 0xad, 0xe1,
+  0xf9, 0x2f, 0xb8, 0xf4, 0x0a, 0xd7, 0x64, 0x56, 0x5e, 0x6d, 0xcc, 0x7f,
+  0x25, 0x86, 0xcb, 0x76, 0x44, 0x90, 0x2a, 0x01, 0xed, 0xde, 0x7e, 0xa0,
+  0xb7, 0xdf, 0x4a, 0x38, 0x29, 0x98, 0x4d, 0x37, 0xad, 0x76, 0xcf, 0x16,
+  0xeb, 0x90, 0xb2, 0x9b, 0x5c, 0x1a, 0xdf, 0x8e, 0xe5, 0x5c, 0x6d, 0xa8,
+  0x14, 0xb2, 0x7a, 0xd2, 0xdb, 0xd6, 0xc7, 0xcf, 0x9a, 0x92, 0xd0, 0xbd,
+  0x76, 0xec, 0xd0, 0xa8, 0xb5, 0x4a, 0x0c, 0xaa, 0xd8, 0xbb, 0x80, 0x16,
+  0x53, 0x37, 0x65, 0x0b, 0xa3, 0x42, 0xda, 0x02, 0x1f, 0xfd, 0x66, 0x3e,
+  0x50, 0xab, 0x72, 0x12, 0x49, 0x05, 0xb6, 0xf9, 0xf9, 0x8d, 0xd7, 0x00,
+  0x29, 0x6f, 0x4c, 0xd2, 0x78, 0xb1, 0x49, 0x02, 0x56, 0xbf, 0x0a, 0xb0,
+  0x24, 0x63, 0x59, 0xde, 0xcf, 0x2b, 0x2b, 0xd4, 0x00, 0x53, 0x04, 0x41,
+  0x4e, 0xb6, 0x82, 0x3f, 0xfe, 0x64, 0xa0, 0x51, 0xed, 0x97, 0x6d, 0xcd,
+  0xdd, 0x93, 0x46, 0x95, 0x9c, 0x19, 0x36, 0x8d, 0xa5, 0x9a, 0x51, 0x61,
+  0x2d, 0xd8, 0xee, 0x00, 0x1e, 0xbb, 0xaa, 0xf7, 0x0f, 0xae, 0x97, 0x33,
+  0x5e, 0xf0, 0xc3, 0xd6, 0x15, 0x09, 0x2d, 0xd0, 0xdd, 0xc3, 0x9b, 0xaf,
+  0xac, 0xa4, 0x5c, 0xba, 0x96, 0x45, 0x59, 0xba, 0x31, 0xba, 0x1c, 0xbe,
+  0x6f, 0x9e, 0xdc, 0x00, 0x85, 0xdb, 0x0d, 0x42, 0x8e, 0x09, 0x6a, 0x74,
+  0x9f, 0xf2, 0xfc, 0xe5, 0xd6, 0x86, 0xa7, 0x46, 0x50, 0xf0, 0x11, 0x9e,
+  0x5b, 0x0a, 0xaf, 0xfb, 0xf5, 0x24, 0x09, 0x8f, 0xb2, 0x10, 0xe8, 0xca,
+  0xd0, 0xda, 0x9e, 0xd8, 0xc4, 0xf9, 0xef, 0xa4, 0x08, 0x5d, 0x29, 0x14,
+  0x2a, 0x36, 0xfb, 0x40, 0x2b, 0x17, 0xc7, 0x21, 0xe1, 0x16, 0x64, 0x73,
+  0xe0, 0x5e, 0xfe, 0xa0, 0x59, 0x4d, 0x57, 0x69, 0xf6, 0x13, 0x9c, 0x72,
+  0x81, 0x69, 0x13, 0x40, 0xea, 0xd4, 0x67, 0x37, 0xdb, 0x1e, 0xed, 0xd0,
+  0x4a, 0xff, 0x9c, 0xca, 0x58, 0x40, 0xef, 0x05, 0x6b, 0x64, 0xde, 0x8a,
+  0xbc, 0xc7, 0xd9, 0x14, 0x08, 0xdb, 0x9e, 0xf2, 0x4a, 0x30, 0x07, 0x33,
+  0x88, 0x96, 0x85, 0x37, 0x87, 0xc8, 0x68, 0x8f, 0x6c, 0x7e, 0x84, 0xdb,
+  0x68, 0x7a, 0x04, 0x23, 0x7d, 0x02, 0x82, 0x10, 0x03, 0x89, 0xf6, 0xc9,
+  0x94, 0x12, 0x3f, 0xf7, 0x1d, 0x39, 0x77, 0x8e, 0x19, 0xb2, 0x90, 0xdb,
+  0xe6, 0x8f, 0x90, 0x57, 0xd7, 0xae, 0x65, 0x0a, 0xc1, 0x56, 0x1a, 0xa7,
+  0x9f, 0x06, 0xc0, 0xb6, 0x88, 0x53, 0x71, 0xd0, 0x30, 0x53, 0x7e, 0xe9,
+  0xe9, 0xd1, 0x1c, 0x5e, 0x3b, 0xc7, 0x83, 0x16, 0xdf, 0x46, 0xf7, 0x9f,
+  0xc8, 0x08, 0x3f, 0x95, 0xcf, 0xf8, 0x4a, 0x50, 0x49, 0xff, 0xde, 0x2c,
+  0x80, 0x96, 0x00, 0x65, 0x12, 0x5b, 0xe0, 0x62, 0xac, 0x77, 0x9e, 0xdc,
+  0x83, 0x12, 0x4a, 0x54, 0xf0, 0x6f, 0xb7, 0x7b, 0xc0, 0x41, 0xfc, 0x40,
+  0x01, 0x16, 0x20, 0x04, 0x37, 0x99, 0x28, 0x59, 0x8b, 0x69, 0x29, 0xad,
+  0x4e, 0x24, 0xb6, 0x14, 0xba, 0xdf, 0xec, 0x25, 0x41, 0xbe, 0x8a, 0xde,
+  0x30, 0x01, 0xf3, 0xc1, 0x04, 0x06, 0x40, 0x1f, 0xfc, 0x8a, 0x77, 0x8d,
+  0xe1, 0xf5, 0x60, 0x08, 0xaa, 0x07, 0xc0, 0xa6, 0xf5, 0x90, 0xaa, 0x00,
+  0x2e, 0x6f, 0xcb, 0xe0, 0x0f, 0x90, 0x10, 0x00, 0xeb, 0x8e, 0x3e, 0xba,
+  0x09, 0x7f, 0xf7, 0x49, 0xce, 0xa3, 0x0e, 0xb4, 0x9b, 0xe3, 0x0e, 0x6d,
+  0x4e, 0xad, 0xbc, 0x29, 0x5b, 0xf0, 0x00, 0x0c, 0x3d, 0xba, 0x7f, 0xdb,
+  0x8c, 0xf8, 0xce, 0x20, 0xfd, 0xe7, 0x7c, 0xa6, 0x2d, 0x0d, 0x39, 0xac,
+  0xff, 0x0a, 0xe1, 0xfd, 0x57, 0xd7, 0xe4, 0x91, 0x77, 0x5f, 0xb9, 0x61,
+  0xb6, 0xda, 0x87, 0xa0, 0xe0, 0x96, 0xe0, 0x89, 0xf2, 0xe4, 0xd8, 0xb5,
+  0x00, 0x95, 0x1c, 0xad, 0xab, 0xce, 0x80, 0x3b, 0x00, 0x32, 0xc1, 0x5b,
+  0x2c, 0x04, 0x6f, 0xfa, 0x7f, 0x91, 0x98, 0x34, 0x9a, 0x6d, 0x89, 0x02,
+  0xdb, 0xcf, 0x44, 0x76, 0xda, 0x42, 0x46, 0xe5, 0xb0, 0x39, 0x5b, 0xfd,
+  0x1f, 0xf7, 0xea, 0x82, 0x07, 0xe7, 0xf1, 0x08, 0x9e, 0xd7, 0x06, 0x79,
+  0x79, 0xce, 0x57, 0xbc, 0x1c, 0x1d, 0x83, 0x2d, 0x6e, 0xf8, 0x03, 0x2e,
+  0x78, 0x00, 0x4d, 0xce, 0x6f, 0x9d, 0x0c, 0x80, 0x3d, 0x0b, 0x0c, 0x87,
+  0xb7, 0x8d, 0x04, 0x00, 0x2a, 0x73, 0xc0, 0x1b, 0x39, 0xef, 0xf9, 0x17,
+  0x69, 0x6b, 0x99, 0xca, 0xd3, 0x62, 0xd3, 0x6c, 0x50, 0x96, 0xf9, 0xd8,
+  0xae, 0x35, 0xdf, 0x13, 0x20, 0x8b, 0x85, 0xa6, 0x4c, 0x45, 0x8b, 0x36,
+  0xae, 0x97, 0x7c, 0x5b, 0x67, 0xd8, 0x6b, 0xf7, 0x69, 0x08, 0xa6, 0xea,
+  0xe4, 0xbb, 0xb6, 0xd0, 0x29, 0xbf, 0xa5, 0x80, 0x17, 0x7d, 0x4d, 0xf7,
+  0xbb, 0xf3, 0xc3, 0xb9, 0x8a, 0x86, 0xa0, 0xc9, 0x85, 0x17, 0x10, 0xf3,
+  0xc3, 0x15, 0xbc, 0x68, 0x03, 0x22, 0x37, 0x5d, 0x7b, 0x0a, 0x70, 0x05,
+  0xbe, 0xd6, 0x93, 0x79, 0x78, 0xdd, 0x32, 0x40, 0xf1, 0xc5, 0x2b, 0x64,
+  0x00, 0x71, 0xf6, 0xe6, 0x7b, 0xc5, 0x78, 0x9d, 0xb0, 0x9b, 0x77, 0x6a,
+  0xdd, 0x58, 0x92, 0x14, 0x10, 0x34, 0xb6, 0xe6, 0x00, 0x36, 0x23, 0x70,
+  0x66, 0x2d, 0xef, 0x6f, 0xed, 0xdc, 0x21, 0xd9, 0x0f, 0xa5, 0x86, 0xb2,
+  0x7e, 0xd7, 0xf3, 0xbb, 0xb7, 0xc5, 0xb7, 0x7d, 0x37, 0x6d, 0xad, 0xf5,
+  0xba, 0x00, 0x39, 0xde, 0x65, 0xdd, 0xe7, 0x30, 0x10, 0xc0, 0x18, 0x50,
+  0xa7, 0x18, 0x92, 0xe6, 0xed, 0x1a, 0xef, 0xd5, 0x8d, 0x90, 0x01, 0xe7,
+  0x64, 0x77, 0x89, 0xc5, 0xf6, 0x32, 0xd0, 0xff, 0x67, 0x47, 0x48, 0x90,
+  0x83, 0x4d, 0xd8, 0x4b, 0xad, 0xe6, 0xc5, 0x3a, 0x74, 0x22, 0x4e, 0x84,
+  0x70, 0x34, 0xd9, 0xc6, 0x7e, 0xf6, 0xd3, 0x82, 0x9a, 0xe7, 0xed, 0x79,
+  0x8f, 0x5e, 0x72, 0xa2, 0xb8, 0xcd, 0x28, 0x98, 0x1c, 0x3a, 0x94, 0x06,
+  0xdb, 0x48, 0xda, 0xd6, 0xfb, 0xa4, 0x4e, 0x05, 0x70, 0x46, 0xda, 0xef,
+  0x7a, 0xfc, 0x53, 0x04, 0xf2, 0xf9, 0x0e, 0x98, 0x52, 0x87, 0xc8, 0x3e,
+  0xd6, 0x6f, 0x60, 0x07, 0xa4, 0x71, 0x3d, 0xe6, 0xbf, 0x8c, 0x53, 0x03,
+  0xac, 0xb1, 0x46, 0x14, 0x54, 0x1d, 0x06, 0xb7, 0x20, 0x00, 0xf7, 0xa7,
+  0x77, 0xb1, 0xd3, 0x99, 0x8a, 0x82, 0xf4, 0x80, 0xbe, 0x72, 0xca, 0x38,
+  0xa3, 0xe1, 0xde, 0xad, 0x97, 0xd9, 0xe2, 0xfd, 0xf9, 0x90, 0xc9, 0x46,
+  0xa9, 0xb5, 0x10, 0xc8, 0x04, 0x1e, 0xa3, 0x98, 0xf1, 0x66, 0xdf, 0xa3,
+  0x00, 0x58, 0xef, 0x97, 0x59, 0xcf, 0xd7, 0xdd, 0xfb, 0x4e, 0x99, 0x6a,
+  0x80, 0xe3, 0x0f, 0x38, 0x61, 0x4d, 0xc0, 0xae, 0xeb, 0x32, 0xb8, 0x43,
+  0xa1, 0x45, 0x16, 0x91, 0x0b, 0x0a, 0x6c, 0xde, 0xcb, 0x4c, 0x20, 0x4c,
+  0x39, 0x74, 0xa8, 0x56, 0x8e, 0xf0, 0x02, 0xdb, 0xa7, 0xf1, 0x9c, 0xc7,
+  0x50, 0x0b, 0x7b, 0xda, 0x74, 0x2e, 0xa2, 0xc7, 0x43, 0xd9, 0xc6, 0x6d,
+  0xf9, 0xf3, 0x74, 0xcc, 0x36, 0x62, 0x8d, 0xa6, 0x1e, 0x8a, 0x58, 0x6b,
+  0x27, 0x79, 0x5f, 0x83, 0x69, 0xe1, 0x65, 0x56, 0xee, 0x7c, 0xba, 0x8b,
+  0xd9, 0x72, 0x00, 0x45, 0x98, 0x61, 0x67, 0x31, 0x7d, 0xe0, 0x57, 0xbd,
+  0x58, 0x13, 0xb0, 0xeb, 0x3d, 0x51, 0x15, 0x86, 0x55, 0x80, 0x00, 0x00,
+  0x01, 0x09, 0x43, 0xf1, 0xf9, 0x49, 0xf9, 0x85, 0x04, 0xad, 0x6e, 0xaf,
+  0x32, 0x6e, 0x16, 0xdf, 0x2a, 0x77, 0x52, 0x11, 0xf8, 0xb7, 0x60, 0xe5,
+  0x32, 0xc8, 0x58, 0xc2, 0xca, 0x4a, 0xa1, 0x2d, 0xf6, 0xba, 0x47, 0x22,
+  0x00, 0x2d, 0x00, 0x7d, 0xbb, 0xbc, 0xdd, 0x4b, 0x49, 0xdd, 0x88, 0xe6,
+  0x07, 0x2e, 0x07, 0xc3, 0xa5, 0x1a, 0x8d, 0xe5, 0xb8, 0xa6, 0xf3, 0x55,
+  0x5b, 0xc0, 0xf7, 0x49, 0xde, 0xf0, 0x42, 0x36, 0x4b, 0xe0, 0xb6, 0x2b,
+  0x6f, 0x73, 0xf4, 0x51, 0x1c, 0x01, 0xe7, 0xdb, 0x9a, 0x13, 0x7b, 0xf9,
+  0x15, 0x1c, 0x4f, 0x04, 0x80, 0x03, 0xdd, 0x2f, 0x8a, 0x15, 0x0e, 0xa7,
+  0xb7, 0xa8, 0x16, 0x45, 0xf6, 0xfa, 0x11, 0x4d, 0xf8, 0x82, 0xcc, 0x36,
+  0xe6, 0xbf, 0x2f, 0x95, 0x55, 0x86, 0x7e, 0xad, 0x3d, 0x4b, 0x90, 0x21,
+  0xba, 0x22, 0x7b, 0xa0, 0x0f, 0xbe, 0x9f, 0x77, 0x73, 0xc5, 0x8f, 0x7f,
+  0x2f, 0x7d, 0x9b, 0x1f, 0xb1, 0xfa, 0xfd, 0x44, 0x43, 0xca, 0x8e, 0x0b,
+  0x56, 0xe7, 0x75, 0xf2, 0xa3, 0x02, 0xab, 0x2d, 0x44, 0x6f, 0xd8, 0x73,
+  0xae, 0x23, 0x7f, 0x04, 0xee, 0x3e, 0x00, 0x0a, 0x5d, 0xcf, 0x4b, 0x38,
+  0xc9, 0x03, 0xc0, 0x4b, 0x0a, 0x43, 0x0a, 0xad, 0xf0, 0x40, 0x03, 0xb8,
+  0xe7, 0xf9, 0xfb, 0x58, 0x7a, 0x6d, 0xd9, 0x9b, 0x57, 0x07, 0x15, 0x8a,
+  0x6d, 0x0a, 0x46, 0xfd, 0x0f, 0xf4, 0x16, 0x00, 0x6b, 0xc7, 0xff, 0xb1,
+  0x51, 0xf2, 0x9f, 0x78, 0xcd, 0x00, 0xb7, 0x6e, 0x53, 0xa9, 0x34, 0x3e,
+  0x9b, 0x0e, 0x1b, 0x1b, 0xf2, 0x63, 0xe4, 0x11, 0x82, 0xa4, 0x80, 0x94,
+  0x00, 0x66, 0x52, 0x51, 0x25, 0x9e, 0x16, 0xab, 0x3d, 0x23, 0x48, 0x0e,
+  0x35, 0xbf, 0xae, 0x08, 0xfa, 0xb8, 0x10, 0x3f, 0x2c, 0x4e, 0x8b, 0xe3,
+  0xbb, 0x40, 0x8e, 0x3e, 0x38, 0xeb, 0x88, 0xf9, 0xb0, 0xf0, 0xf7, 0xed,
+  0xab, 0x14, 0x32, 0x14, 0xdf, 0x50, 0xf9, 0xf8, 0xc0, 0x02, 0x8e, 0x1c,
+  0xe8, 0xb0, 0x11, 0xff, 0xee, 0xdb, 0x69, 0x60, 0x3c, 0x58, 0x52, 0x12,
+  0x5b, 0xf2, 0xfe, 0x80, 0x53, 0x5b, 0xf4, 0x38, 0x03, 0xc7, 0xc0, 0x04,
+  0xff, 0xe1, 0x7f, 0xdf, 0xb4, 0xc8, 0x08, 0xc0, 0x0a, 0xb4, 0x0c, 0xa6,
+  0x07, 0x50, 0x1c, 0xd1, 0x88, 0x58, 0xd1, 0xb5, 0xb9, 0x75, 0x1d, 0xd3,
+  0xf5, 0x7c, 0x21, 0x49, 0x4e, 0x1f, 0x5b, 0x38, 0x5b, 0xae, 0xcf, 0x04,
+  0x3d, 0xbf, 0xce, 0x9f, 0x71, 0x0f, 0x00, 0x2e, 0xfb, 0xbb, 0x1d, 0x65,
+  0x01, 0xe6, 0xbc, 0x46, 0xbb, 0x60, 0xca, 0x58, 0x45, 0x25, 0xb7, 0xce,
+  0x3a, 0xe8, 0x02, 0xbe, 0xdc, 0x4f, 0x2c, 0x62, 0xc3, 0x15, 0xbf, 0x5c,
+  0x00, 0x30, 0x17, 0xa0, 0x80, 0x05, 0x59, 0xef, 0xff, 0x16, 0x22, 0x4f,
+  0xd7, 0x5c, 0x3d, 0xc8, 0x66, 0xd4, 0x27, 0x9d, 0x4d, 0x8b, 0x50, 0x68,
+  0xd6, 0xfc, 0xd0, 0xfa, 0xf1, 0x7f, 0x24, 0x67, 0x71, 0x21, 0xd9, 0x5e,
+  0x4f, 0xec, 0xc9, 0x93, 0x21, 0x74, 0x3c, 0x74, 0x6e, 0x82, 0x6f, 0x3b,
+  0xa8, 0x43, 0xad, 0xa2, 0x96, 0xb5, 0xbc, 0x8f, 0xeb, 0x1c, 0x22, 0x47,
+  0x64, 0xf5, 0x3e, 0xda, 0xa3, 0x4b, 0x6b, 0x08, 0xce, 0x00, 0x33, 0xf7,
+  0x9b, 0x25, 0x0c, 0xaf, 0x32, 0x19, 0x46, 0xb7, 0xa7, 0x42, 0x01, 0xaf,
+  0x7c, 0xb8, 0x03, 0xde, 0x79, 0x93, 0x80, 0xa2, 0xb2, 0x0c, 0x81, 0xa5,
+  0xd6, 0xc1, 0xf7, 0x37, 0x0a, 0x44, 0x3d, 0x4a, 0x87, 0x86, 0x00, 0xd5,
+  0x96, 0x4b, 0xae, 0x46, 0x4a, 0x52, 0xb7, 0xd0, 0xec, 0x5e, 0x11, 0xb8,
+  0x7e, 0xbf, 0xac, 0x2c, 0xad, 0xe7, 0x1f, 0x93, 0x8b, 0x76, 0xa3, 0x8f,
+  0x8a, 0x51, 0x94, 0xb4, 0x2b, 0x0f, 0x8d, 0xc0, 0xe6, 0x68, 0x19, 0xca,
+  0x9e, 0x25, 0x29, 0x29, 0xb0, 0xf1, 0x28, 0xa1, 0x6e, 0xb7, 0x72, 0x06,
+  0x45, 0x58, 0x9e, 0x10, 0x68, 0x4b, 0x52, 0x46, 0xcc, 0x7b, 0xb6, 0xe2,
+  0x50, 0xab, 0x0a, 0x02, 0xeb, 0x5d, 0x87, 0x2d, 0xf5, 0x6d, 0xcf, 0xa0,
+  0x5b, 0x7d, 0x61, 0x6b, 0xcd, 0xe2, 0xd9, 0x2f, 0x83, 0xf0, 0xaa, 0x10,
+  0x31, 0xb7, 0xe4, 0xc8, 0x47, 0x94, 0xde, 0x02, 0xb5, 0xfb, 0x2e, 0x5b,
+  0x16, 0x9d, 0xa0, 0x5b, 0x69, 0x23, 0x7e, 0x7b, 0x23, 0x75, 0xbb, 0x29,
+  0xd0, 0xbf, 0x7f, 0x3b, 0x4b, 0x0c, 0x30, 0xda, 0x7b, 0x61, 0xd9, 0x39,
+  0x14, 0x23, 0x70, 0xc8, 0x55, 0x31, 0xd4, 0xc7, 0x1c, 0x4c, 0x51, 0x81,
+  0x67, 0xb7, 0xa0, 0x32, 0xb7, 0xa2, 0x8a, 0x8d, 0xea, 0xf6, 0xcb, 0xe5,
+  0x78, 0xd8, 0xa7, 0xd2, 0xd5, 0xd2, 0x1c, 0x58, 0xe1, 0xed, 0xb7, 0x87,
+  0xf9, 0x11, 0x95, 0x50, 0x72, 0x6e, 0x17, 0xa3, 0x09, 0x88, 0x31, 0xb9,
+  0x76, 0x1b, 0xf3, 0x9b, 0x54, 0x05, 0x77, 0x8d, 0xc2, 0xe1, 0x30, 0x71,
+  0xfe, 0xad, 0xd2, 0x17, 0x40, 0x0e, 0x05, 0xbe, 0x97, 0x46, 0x9a, 0x6b,
+  0xb3, 0x32, 0x94, 0x04, 0x50, 0xf2, 0xef, 0x8c, 0x29, 0x93, 0x6e, 0xde,
+  0x5c, 0xc2, 0x7f, 0x34, 0x9d, 0x81, 0x92, 0x72, 0xfc, 0x9b, 0x47, 0x0d,
+  0x28, 0xf0, 0x98, 0xce, 0x45, 0x7c, 0xe8, 0x00, 0xfe, 0x1a, 0x19, 0x49,
+  0xce, 0xe4, 0xc4, 0xd8, 0x1b, 0x64, 0xcb, 0x4a, 0x0d, 0x62, 0xe7, 0xef,
+  0x59, 0xef, 0xbb, 0x25, 0x1c, 0x82, 0xf4, 0xc9, 0x29, 0xe3, 0x92, 0x92,
+  0x1b, 0x1c, 0x33, 0xe1, 0xfd, 0xdb, 0x40, 0x47, 0xe6, 0xe5, 0x51, 0x83,
+  0x0d, 0x18, 0x10, 0xd4, 0xd2, 0x73, 0x74, 0x08, 0x96, 0x71, 0x45, 0xe4,
+  0xd4, 0x1c, 0x4f, 0x3f, 0x21, 0xd7, 0xc5, 0xb1, 0xdd, 0xa0, 0x0e, 0xbe,
+  0x9d, 0x63, 0xed, 0x0d, 0xb3, 0xcf, 0x75, 0x29, 0xe3, 0xf7, 0x6c, 0xf4,
+  0xb5, 0x97, 0x94, 0xb9, 0x66, 0x1b, 0xe2, 0x05, 0x1c, 0xdd, 0x5e, 0x45,
+  0xc7, 0x6f, 0xe6, 0x4a, 0x59, 0x53, 0x75, 0x4c, 0x1e, 0x70, 0x4d, 0x61,
+  0xa6, 0x95, 0x1b, 0xf1, 0x9e, 0xf2, 0x89, 0x99, 0x32, 0xca, 0x39, 0x43,
+  0x4e, 0x6f, 0xd3, 0x1f, 0xde, 0xb4, 0x10, 0x3f, 0x2f, 0xee, 0xe2, 0x37,
+  0xb7, 0xbc, 0xa5, 0xe6, 0xf5, 0x9d, 0xfb, 0x6b, 0xf5, 0xf9, 0x4f, 0x85,
+  0xe5, 0x92, 0x2d, 0x09, 0x2d, 0xbe, 0x46, 0x6c, 0x9b, 0x23, 0xcb, 0x19,
+  0x85, 0x86, 0x96, 0x88, 0xa5, 0x37, 0xbf, 0xff, 0x3b, 0x8c, 0x00, 0x79,
+  0x77, 0xe3, 0xa1, 0x14, 0xf0, 0x0b, 0x45, 0xba, 0xd5, 0x79, 0xa6, 0xc9,
+  0x61, 0x45, 0xda, 0x07, 0xb6, 0x67, 0xa4, 0x6c, 0x39, 0x45, 0x8d, 0xfd,
+  0xc4, 0x00, 0xb0, 0x01, 0xf8, 0x8f, 0x6b, 0xcf, 0x9b, 0xaa, 0x5b, 0x16,
+  0x21, 0x52, 0x7e, 0xc6, 0xc1, 0x90, 0xf1, 0xad, 0xf9, 0x59, 0x1d, 0xf1,
+  0xf6, 0xf8, 0xf8, 0xf6, 0x99, 0x49, 0x86, 0xee, 0x75, 0xc6, 0x61, 0xb7,
+  0x2d, 0x5a, 0xbb, 0x0f, 0xda, 0x79, 0xf5, 0xbb, 0xc2, 0xa0, 0x92, 0x7e,
+  0xbf, 0x90, 0x0b, 0x61, 0x44, 0xed, 0x26, 0xe5, 0x91, 0xd9, 0x52, 0x69,
+  0x95, 0x0b, 0x2e, 0x84, 0x56, 0xc9, 0xd8, 0xae, 0x45, 0x2e, 0x0a, 0x7c,
+  0xb4, 0x9b, 0x15, 0x20, 0xfa, 0x6d, 0x2c, 0x28, 0xe6, 0xd2, 0x15, 0x1b,
+  0x4d, 0xa5, 0x14, 0xdf, 0x3f, 0x9f, 0x3d, 0x89, 0xba, 0x87, 0x41, 0xaa,
+  0x56, 0x0d, 0x56, 0xdf, 0x95, 0xf3, 0xdf, 0x2b, 0xf3, 0x68, 0xc7, 0x60,
+  0xc9, 0x4b, 0x38, 0xaa, 0x71, 0x4d, 0x9f, 0xa9, 0x39, 0xdc, 0x5c, 0x29,
+  0x7f, 0x57, 0x52, 0xdd, 0x42, 0x9b, 0xa5, 0x9d, 0x3f, 0x7e, 0x2c, 0xb7,
+  0x61, 0x41, 0xd0, 0xa8, 0x54, 0x54, 0x0d, 0x38, 0x29, 0xa1, 0xb5, 0xab,
+  0x4f, 0x6f, 0x3f, 0xd3, 0x89, 0xd7, 0x55, 0xe4, 0xed, 0xe7, 0x69, 0x35,
+  0x06, 0x59, 0x22, 0x97, 0x4b, 0xfd, 0xb2, 0x74, 0x21, 0xf2, 0x45, 0x7d,
+  0x50, 0xa3, 0xea, 0xa0, 0xf6, 0xe8, 0xfd, 0x44, 0x65, 0xe8, 0x07, 0x2f,
+  0x55, 0xa6, 0xae, 0x52, 0xb1, 0x0a, 0x46, 0xe1, 0x3d, 0xdc, 0x60, 0xbf,
+  0x38, 0x6c, 0x28, 0xf3, 0x0a, 0x85, 0x94, 0x3e, 0x56, 0x43, 0x19, 0xb7,
+  0xaa, 0xf3, 0x79, 0xcc, 0x9c, 0x61, 0x94, 0xab, 0x62, 0x0c, 0x0a, 0x6d,
+  0x80, 0x64, 0x59, 0x1b, 0x88, 0xe7, 0xec, 0x3c, 0x9d, 0x9c, 0xd7, 0xda,
+  0xba, 0x8a, 0x34, 0x6b, 0x73, 0x5d, 0xd9, 0x07, 0xbd, 0xbc, 0xb8, 0xa2,
+  0xee, 0x63, 0xae, 0x07, 0x5a, 0x85, 0x1e, 0x87, 0xd1, 0x8c, 0x80, 0x07,
+  0xd1, 0xde, 0xd3, 0x9c, 0x2c, 0xb5, 0x58, 0x34, 0xb2, 0xe4, 0x0a, 0x8c,
+  0xda, 0x63, 0x7d, 0xd1, 0x22, 0xc8, 0x9a, 0xec, 0xd3, 0x0d, 0x01, 0xc7,
+  0x2f, 0xe4, 0xe8, 0x1f, 0x28, 0xcd, 0x81, 0x03, 0x55, 0xba, 0x93, 0xfe,
+  0xff, 0x6b, 0xce, 0xcd, 0xef, 0x64, 0xd9, 0x8f, 0x9b, 0x2e, 0xdb, 0x38,
+  0xc3, 0xe2, 0x0e, 0x29, 0xb8, 0x3f, 0x7e, 0x48, 0xc2, 0x3b, 0xd9, 0xb2,
+  0xd3, 0xea, 0xef, 0x26, 0xe4, 0xae, 0x42, 0x8a, 0xa7, 0xdf, 0x02, 0x9b,
+  0x3f, 0x26, 0x7c, 0xf4, 0x23, 0x5e, 0x3a, 0x4e, 0x21, 0xa9, 0x6c, 0xb4,
+  0x62, 0x4a, 0x1a, 0xc0, 0xd6, 0x8c, 0x4b, 0x95, 0xbc, 0x4f, 0xde, 0x5c,
+  0xec, 0x82, 0xde, 0xe2, 0xe9, 0x8e, 0x9c, 0xad, 0xa9, 0x87, 0xd2, 0x1b,
+  0x5b, 0xee, 0x88, 0x92, 0xc8, 0x78, 0xd3, 0x88, 0x4d, 0xdf, 0x13, 0x3a,
+  0xff, 0x7c, 0xe5, 0x76, 0x65, 0x4a, 0x1e, 0x9e, 0x56, 0x22, 0xd0, 0x21,
+  0x07, 0x8f, 0x6f, 0x3b, 0xb6, 0x39, 0xef, 0xf2, 0x33, 0xc7, 0x24, 0xd4,
+  0x38, 0x2d, 0x93, 0x69, 0x2a, 0xca, 0xda, 0x71, 0x6c, 0x7b, 0xf5, 0x42,
+  0x92, 0x0f, 0x85, 0x46, 0xd9, 0xfc, 0xe7, 0x9f, 0x7e, 0x46, 0x0e, 0x48,
+  0x5d, 0x64, 0x7e, 0xdf, 0x9c, 0x97, 0x8d, 0x94, 0x62, 0x1b, 0x84, 0xb4,
+  0xa7, 0x05, 0x36, 0x98, 0xfb, 0xa2, 0x5d, 0x73, 0x85, 0xa3, 0x69, 0xea,
+  0x50, 0x71, 0xd5, 0x88, 0xcd, 0xb4, 0x23, 0x3a, 0xf1, 0x96, 0x1b, 0xb2,
+  0x04, 0x0e, 0x87, 0xfa, 0xb6, 0x67, 0xe4, 0xd7, 0x3a, 0x79, 0x50, 0xc3,
+  0x12, 0x97, 0xbe, 0x07, 0x33, 0xba, 0x51, 0x1d, 0x24, 0x7d, 0x1d, 0xaf,
+  0xd4, 0x2c, 0xe6, 0xe6, 0xcc, 0x9e, 0x7a, 0xb4, 0x26, 0xca, 0x7a, 0x50,
+  0x1e, 0xb3, 0x8d, 0x6c, 0x00, 0x00, 0x01, 0x0a, 0x43, 0xf9, 0x00, 0x03,
+  0xbf, 0xe0, 0xb1, 0x5c, 0x93, 0xba, 0x30, 0x72, 0x79, 0xf1, 0x4d, 0x53,
+  0xac, 0x3e, 0x58, 0x53, 0x6f, 0xf9, 0x99, 0xc9, 0x1e, 0xf5, 0x2c, 0x80,
+  0x4f, 0x96, 0xd8, 0xba, 0x81, 0x8a, 0x39, 0xbd, 0x28, 0x03, 0x87, 0xb8,
+  0x8c, 0x29, 0xd6, 0xe4, 0x09, 0xdf, 0x3b, 0xaf, 0xa5, 0xa1, 0xf1, 0x55,
+  0x21, 0xc3, 0x1b, 0xce, 0x08, 0xcf, 0x21, 0x4b, 0x2f, 0x8c, 0x6f, 0x1b,
+  0x70, 0x9e, 0x4f, 0x8e, 0x50, 0x9c, 0xb1, 0x15, 0xbc, 0x74, 0x1c, 0xde,
+  0xd0, 0xee, 0xf1, 0xd3, 0x20, 0x66, 0x61, 0x44, 0xda, 0x15, 0x21, 0x55,
+  0xbd, 0x68, 0x03, 0xc7, 0xf1, 0xd7, 0x98, 0xbd, 0x4a, 0x7d, 0x97, 0x97,
+  0xbe, 0xee, 0x97, 0x22, 0x42, 0xa8, 0xc8, 0x14, 0xde, 0x14, 0x9b, 0xce,
+  0xad, 0x6b, 0x76, 0x51, 0x69, 0x90, 0x28, 0xa3, 0xda, 0x21, 0x52, 0x52,
+  0x5b, 0x46, 0x1f, 0x15, 0xbf, 0xa0, 0x7b, 0x25, 0x11, 0xdf, 0x61, 0x20,
+  0x13, 0xfe, 0x22, 0x14, 0x58, 0x70, 0xd2, 0xdb, 0xca, 0xda, 0x01, 0x53,
+  0xdd, 0xb6, 0x20, 0xc2, 0xe7, 0x8b, 0x71, 0x04, 0x3a, 0x0a, 0xe6, 0x6e,
+  0xec, 0x0d, 0x59, 0x12, 0x4f, 0x14, 0xad, 0xba, 0x02, 0x17, 0xfd, 0x3b,
+  0x69, 0x2e, 0x92, 0x58, 0x2a, 0xd8, 0xa4, 0x26, 0xac, 0x2b, 0x15, 0xbf,
+  0xb6, 0x80, 0x3b, 0x00, 0x5f, 0xec, 0x00, 0x5f, 0xfc, 0x8f, 0xe2, 0x74,
+  0xa8, 0x4f, 0xc1, 0x62, 0x35, 0x61, 0x97, 0x13, 0x72, 0x9e, 0x10, 0xdf,
+  0x6e, 0x11, 0xff, 0xe7, 0xa0, 0x06, 0x6f, 0xe5, 0xeb, 0xa3, 0x39, 0x79,
+  0x97, 0x64, 0xa8, 0x9c, 0x5c, 0x59, 0x07, 0xb7, 0xe4, 0xfe, 0xf9, 0x00,
+  0x35, 0xf6, 0x9c, 0xf9, 0xa4, 0x2e, 0x90, 0x3a, 0x49, 0x3b, 0xe4, 0x71,
+  0x46, 0xd2, 0xa4, 0x3d, 0xbd, 0x0f, 0xfb, 0xed, 0x9f, 0x04, 0x70, 0x0a,
+  0xfe, 0x05, 0x6d, 0x2f, 0xf2, 0x41, 0x5f, 0xc6, 0x61, 0x84, 0x0c, 0xcf,
+  0xc2, 0x55, 0xb8, 0x78, 0x63, 0x67, 0xd3, 0xcc, 0xdf, 0x3b, 0x6a, 0x0f,
+  0x74, 0x58, 0x81, 0x6d, 0xae, 0x5b, 0xa5, 0xd5, 0x0a, 0x6f, 0x9e, 0x2b,
+  0x9a, 0x00, 0xf8, 0x8d, 0x9c, 0x65, 0x5b, 0x57, 0x79, 0x47, 0x48, 0x5d,
+  0x55, 0x1a, 0x4a, 0x6f, 0x00, 0x2d, 0x61, 0x91, 0x47, 0x42, 0xc7, 0x48,
+  0x51, 0xed, 0xea, 0xf5, 0xdc, 0x00, 0x3a, 0xec, 0x8a, 0x44, 0xec, 0x9f,
+  0x00, 0x05, 0x3d, 0x90, 0x33, 0xbe, 0x6e, 0x69, 0xf0, 0x38, 0xb3, 0x2a,
+  0x78, 0x94, 0xde, 0x0b, 0xfd, 0x40, 0x2d, 0xd7, 0xeb, 0x90, 0x35, 0x2e,
+  0xd5, 0x83, 0x08, 0x4d, 0x35, 0x76, 0x54, 0xb0, 0x30, 0x29, 0xb0, 0xb0,
+  0xb6, 0xfa, 0x36, 0xd7, 0xc8, 0xf9, 0x7d, 0x0a, 0xa0, 0x6d, 0xae, 0x27,
+  0x10, 0x04, 0xdc, 0x40, 0x85, 0xb1, 0x5b, 0x81, 0xd6, 0x00, 0x19, 0x59,
+  0x9a, 0xf0, 0x9b, 0x04, 0xcb, 0x81, 0x87, 0x05, 0xb6, 0x5f, 0xa7, 0x40,
+  0x16, 0x08, 0x13, 0xcc, 0x81, 0x31, 0x0c, 0x84, 0xba, 0xdb, 0x4b, 0xe6,
+  0xb2, 0x90, 0xd9, 0xd8, 0x39, 0xba, 0x78, 0x80, 0x07, 0xc2, 0x1d, 0x32,
+  0xbe, 0x06, 0xcd, 0x47, 0x86, 0x0c, 0x94, 0x69, 0xe1, 0x8d, 0xbb, 0xdc,
+  0xd0, 0x03, 0x9a, 0x40, 0x2a, 0xa5, 0x86, 0xe2, 0x26, 0xcf, 0x0d, 0x96,
+  0x51, 0xc1, 0x8d, 0x92, 0xd7, 0xfd, 0x76, 0x0a, 0xc7, 0x28, 0xcc, 0x0f,
+  0xe7, 0x22, 0x3e, 0x87, 0x43, 0xf4, 0x60, 0x62, 0x16, 0x5b, 0x6b, 0x22,
+  0x6d, 0xf6, 0x23, 0x47, 0x62, 0x5a, 0xb6, 0xd8, 0x2b, 0xa8, 0xe9, 0xb7,
+  0x76, 0x97, 0x4d, 0xd5, 0xb6, 0x90, 0xdb, 0x3f, 0xd4, 0x25, 0xb6, 0xd4,
+  0xb6, 0xef, 0x32, 0x47, 0x45, 0x2c, 0xa3, 0xb3, 0xbd, 0x2b, 0x68, 0x1f,
+  0x0a, 0x66, 0xe3, 0x00, 0x0f, 0xa1, 0x39, 0xf4, 0x6a, 0x20, 0x7e, 0x4a,
+  0xa8, 0x70, 0xd5, 0x0d, 0x6b, 0x26, 0x5f, 0xbb, 0xf3, 0x64, 0xa1, 0x8b,
+  0x5d, 0xbb, 0x2c, 0x08, 0x92, 0x17, 0xe0, 0xd4, 0xb9, 0xcb, 0xce, 0xf7,
+  0x14, 0x24, 0x81, 0x66, 0x42, 0x13, 0x77, 0x40, 0x32, 0xa0, 0x5b, 0x7a,
+  0x50, 0x0c, 0xcd, 0x24, 0xd6, 0xcb, 0xb5, 0x63, 0x9d, 0x28, 0x61, 0xb9,
+  0xdb, 0xb0, 0xc8, 0x83, 0x07, 0x1e, 0x16, 0xdd, 0xb7, 0xe0, 0x00, 0x92,
+  0xbd, 0xd2, 0x3a, 0xcf, 0xd0, 0x09, 0x2d, 0xa8, 0x7c, 0x58, 0x89, 0x14,
+  0x22, 0xa3, 0x73, 0xfb, 0xb7, 0xdc, 0x40, 0x99, 0x2d, 0x01, 0x54, 0x9a,
+  0x85, 0x1c, 0x37, 0x29, 0xc3, 0x4e, 0x6f, 0x57, 0xd7, 0x90, 0x8f, 0x81,
+  0x62, 0x5d, 0xcb, 0xac, 0x01, 0x27, 0x90, 0xbc, 0xa9, 0x03, 0xd6, 0x02,
+  0x27, 0xfe, 0x5b, 0x22, 0xf8, 0x28, 0xf6, 0xdd, 0xba, 0x23, 0x7c, 0xad,
+  0xef, 0x7d, 0x9e, 0x27, 0x8c, 0xb9, 0x07, 0xee, 0xd7, 0x73, 0xbc, 0xef,
+  0xe8, 0xe8, 0xa5, 0x7a, 0x37, 0x93, 0xd3, 0x45, 0x66, 0x27, 0x28, 0x19,
+  0x6e, 0x6f, 0x9c, 0x18, 0x32, 0xd6, 0xd9, 0x78, 0x82, 0x81, 0x0b, 0xfe,
+  0xab, 0xa0, 0xc2, 0xe5, 0x2a, 0xd2, 0x11, 0x5e, 0x25, 0xb6, 0x9c, 0xe5,
+  0xef, 0x15, 0xaa, 0xe7, 0x02, 0x40, 0x01, 0x9b, 0xbb, 0x5f, 0xa1, 0x45,
+  0x1c, 0x16, 0xc3, 0x4a, 0x23, 0x71, 0xdb, 0xbd, 0xbd, 0x79, 0x96, 0xd2,
+  0x63, 0xb2, 0x3e, 0x2c, 0xb2, 0xd3, 0x51, 0x26, 0xf8, 0xb7, 0x4c, 0x49,
+  0x31, 0xca, 0x65, 0x29, 0x10, 0xe4, 0xb1, 0x47, 0x35, 0x3f, 0x5e, 0x9f,
+  0xc9, 0x75, 0x21, 0x72, 0xfe, 0xa2, 0xae, 0x12, 0xa8, 0xc6, 0xeb, 0xba,
+  0xce, 0xc5, 0xde, 0x7a, 0xb4, 0x11, 0xbf, 0xf3, 0x75, 0xcf, 0x92, 0xcc,
+  0xc0, 0xe8, 0x54, 0xab, 0x0b, 0x69, 0x67, 0x0f, 0xad, 0xd1, 0x9d, 0xed,
+  0x17, 0x97, 0xbe, 0x86, 0xdc, 0x29, 0x4a, 0xbf, 0xaa, 0x36, 0x1c, 0x53,
+  0x59, 0xed, 0xf1, 0x1c, 0xf7, 0xef, 0x1d, 0xc9, 0x40, 0x73, 0xb7, 0x56,
+  0x3a, 0x64, 0x18, 0x16, 0x59, 0x61, 0x8d, 0x9c, 0x51, 0x05, 0xdd, 0x4a,
+  0x27, 0x98, 0x34, 0x3a, 0xf2, 0xa9, 0x91, 0x0a, 0x2b, 0x00, 0xb6, 0x5d,
+  0xef, 0x51, 0x5d, 0x62, 0x14, 0x4e, 0x92, 0xd2, 0xb1, 0xc7, 0xda, 0x58,
+  0xe5, 0x0c, 0x66, 0xca, 0x16, 0x73, 0x7d, 0x22, 0x27, 0x09, 0x9a, 0x27,
+  0xdf, 0x4d, 0x28, 0xb9, 0xba, 0xa8, 0x64, 0x2c, 0xe2, 0x8a, 0x88, 0x53,
+  0x5b, 0xf5, 0xe2, 0x68, 0x18, 0x15, 0x24, 0xfd, 0x43, 0x6e, 0xd4, 0x43,
+  0xb7, 0x16, 0x0e, 0x29, 0x5b, 0x17, 0x5b, 0x78, 0x78, 0x19, 0xe5, 0x3f,
+  0x75, 0xcb, 0xbb, 0x46, 0x28, 0xd8, 0x73, 0x65, 0x8e, 0x77, 0x22, 0xb7,
+  0x4d, 0x86, 0x0d, 0xbb, 0x6a, 0x98, 0x30, 0x60, 0x4b, 0x26, 0x1b, 0xb3,
+  0xe1, 0xfa, 0x2b, 0xf2, 0x26, 0xa9, 0x52, 0xec, 0xda, 0x76, 0x49, 0x10,
+  0x86, 0x31, 0xb4, 0xdf, 0x67, 0xfb, 0xbd, 0xf3, 0x5f, 0xaa, 0x52, 0x47,
+  0xd9, 0x09, 0x67, 0x34, 0xde, 0x54, 0x4c, 0xb7, 0x28, 0x4e, 0x43, 0xc0,
+  0x7c, 0xd6, 0x71, 0xa4, 0xe9, 0x76, 0xc8, 0xa7, 0x93, 0x6c, 0x98, 0xb4,
+  0xb1, 0xb0, 0x74, 0x69, 0x6d, 0x02, 0x5b, 0xbb, 0xd8, 0x52, 0x71, 0xaf,
+  0xbc, 0xc5, 0x50, 0xec, 0x94, 0xa8, 0x8a, 0x94, 0xb9, 0x3c, 0x5b, 0x95,
+  0xc8, 0xb7, 0x0a, 0x7d, 0x97, 0x31, 0x0e, 0xb2, 0x3a, 0xa9, 0x91, 0x4b,
+  0x29, 0x61, 0x5e, 0xac, 0xc4, 0xfa, 0x2a, 0x41, 0x83, 0x2e, 0x9a, 0x92,
+  0x0e, 0x1e, 0x48, 0x6d, 0xdf, 0x63, 0x5f, 0x7b, 0xe6, 0xeb, 0xf7, 0x4f,
+  0x9f, 0x89, 0x46, 0x42, 0x8b, 0x96, 0x8c, 0x60, 0xf6, 0x84, 0xb2, 0x9c,
+  0xde, 0x5d, 0xdd, 0xf9, 0x85, 0xad, 0x9f, 0xa8, 0xa7, 0x59, 0xfa, 0x0c,
+  0x1a, 0x16, 0xd7, 0xf3, 0xf3, 0xc7, 0x1c, 0xc9, 0x3a, 0xe0, 0x6d, 0xb5,
+  0xd8, 0xb0, 0xe0, 0xc4, 0x6a, 0xba, 0x92, 0x45, 0x3e, 0x9e, 0x62, 0x42,
+  0xfc, 0x4f, 0x6c, 0x1c, 0x3e, 0xf2, 0x65, 0x48, 0x75, 0x42, 0xe8, 0xd8,
+  0x54, 0x61, 0x8d, 0x39, 0xbf, 0x5b, 0xf3, 0xce, 0x77, 0xf0, 0x27, 0x20,
+  0x91, 0x68, 0x4c, 0xfc, 0xde, 0x52, 0x4e, 0x20, 0x66, 0x6c, 0x1b, 0x4a,
+  0xa7, 0xc1, 0x8d, 0xcf, 0x13, 0xa2, 0x80, 0x0f, 0xdd, 0x82, 0xe6, 0x17,
+  0x16, 0xe4, 0x18, 0x71, 0xa7, 0x28, 0x63, 0x73, 0x1d, 0x2b, 0x8a, 0x2c,
+  0xa3, 0xcd, 0x7c, 0x85, 0x2c, 0x6e, 0x87, 0xb3, 0x8d, 0xcd, 0xba, 0xa3,
+  0xe4, 0xa6, 0xe2, 0x50, 0xa6, 0x50, 0xa6, 0xdb, 0x75, 0x6d, 0x6e, 0xbf,
+  0xc7, 0x96, 0x3b, 0x83, 0x90, 0xa7, 0x22, 0x19, 0x31, 0x14, 0x6a, 0x35,
+  0x4e, 0xf3, 0x10, 0x29, 0xce, 0xb7, 0x6d, 0x3c, 0x3e, 0xf6, 0xb6, 0x0c,
+  0x19, 0x69, 0xed, 0x5e, 0xdc, 0x11, 0xc6, 0x24, 0x09, 0x99, 0x6a, 0x16,
+  0x16, 0x18, 0xda, 0x66, 0xaf, 0x9d, 0x36, 0x8d, 0x43, 0xc9, 0x8a, 0xc4,
+  0x65, 0x68, 0x68, 0x16, 0xdf, 0x2b, 0xa7, 0x4e, 0xaf, 0x4f, 0xb2, 0x53,
+  0x8a, 0xb6, 0xa5, 0xa4, 0x82, 0xe1, 0x2d, 0xac, 0xe3, 0xbc, 0xe3, 0x92,
+  0xe6, 0x28, 0x0f, 0x10, 0xe1, 0x9e, 0x8d, 0x83, 0xab, 0xae, 0x32, 0x49,
+  0x11, 0x20, 0xd0, 0x82, 0x9a, 0xcf, 0x8d, 0x7c, 0x73, 0x8d, 0xb6, 0xa8,
+  0x10, 0x7d, 0x01, 0xab, 0x07, 0x30, 0x7d, 0x6d, 0xe6, 0x6b, 0x9d, 0xb6,
+  0xbe, 0x8c, 0x08, 0x6a, 0x16, 0x72, 0xb2, 0x94, 0x04, 0x64, 0x85, 0xc0,
+  0x92, 0xda, 0xae, 0x5d, 0xc6, 0x62, 0x71, 0xa1, 0x36, 0x86, 0x36, 0x0c,
+  0xdd, 0xc9, 0x2b, 0xc2, 0xa0, 0x67, 0x84, 0x64, 0xc3, 0x00, 0x00, 0x00,
+  0x01, 0x0b, 0x43, 0xf9, 0x16, 0xdf, 0x37, 0xad, 0x9e, 0xa7, 0x46, 0xde,
+  0xf0, 0xfc, 0xc2, 0xef, 0x8b, 0x71, 0xd3, 0xcf, 0x16, 0x92, 0x8a, 0x6f,
+  0x57, 0xc8, 0x21, 0x7f, 0xc8, 0x16, 0xb5, 0xbc, 0xb8, 0x52, 0xda, 0x43,
+  0x6f, 0x16, 0x37, 0x5b, 0xd7, 0x0f, 0x0a, 0x1e, 0x1a, 0xd2, 0x53, 0x39,
+  0xa0, 0x5b, 0x6c, 0x9f, 0x8b, 0x72, 0x7a, 0xca, 0xdc, 0xa9, 0x25, 0xc9,
+  0x00, 0x20, 0x43, 0xa8, 0x09, 0x69, 0xed, 0x3a, 0x1f, 0x23, 0x4d, 0x2d,
+  0xbe, 0x59, 0x84, 0x04, 0x99, 0x40, 0x47, 0x0c, 0x85, 0x85, 0x97, 0x49,
+  0x2d, 0xda, 0x04, 0x3f, 0xfa, 0xb4, 0x92, 0xdc, 0x48, 0x08, 0x40, 0x0e,
+  0x4e, 0x2b, 0xd7, 0x6d, 0x25, 0x95, 0x09, 0x4d, 0xe9, 0x39, 0xcb, 0xc9,
+  0xb8, 0x43, 0xb1, 0xb1, 0xa3, 0x09, 0x0c, 0x8e, 0x46, 0xfa, 0x72, 0x10,
+  0x76, 0x66, 0xdf, 0x0d, 0xb2, 0x2b, 0x68, 0x00, 0x6c, 0x28, 0x00, 0xf9,
+  0xe4, 0x45, 0x35, 0x6a, 0x62, 0xd2, 0x21, 0x19, 0xe0, 0x66, 0x80, 0x47,
+  0x69, 0xc1, 0x2a, 0x8c, 0x45, 0xc8, 0x2f, 0x2e, 0x2d, 0x38, 0xa5, 0x1b,
+  0x83, 0x61, 0x55, 0xbd, 0x29, 0x17, 0xef, 0x84, 0x4f, 0x9b, 0xc3, 0xa0,
+  0xf8, 0x6b, 0x84, 0xf5, 0x5f, 0xd1, 0x6e, 0xf3, 0xa1, 0xf9, 0x64, 0x9b,
+  0x32, 0x14, 0x75, 0x52, 0xeb, 0x79, 0xf1, 0xe4, 0xe3, 0x0a, 0xa1, 0x54,
+  0xb2, 0x89, 0x5e, 0x8d, 0x56, 0x1a, 0xdf, 0x82, 0xed, 0xfb, 0xc7, 0x41,
+  0xe6, 0x58, 0x96, 0x1a, 0xae, 0x0b, 0x1c, 0x35, 0x0a, 0x18, 0xde, 0x64,
+  0x5f, 0x39, 0xc7, 0xbe, 0x47, 0x66, 0xc3, 0xe6, 0xd5, 0x88, 0x51, 0xd4,
+  0xf0, 0xca, 0xde, 0x88, 0x01, 0x87, 0xc7, 0x3d, 0x7f, 0x5d, 0xf3, 0xcf,
+  0x2f, 0xe4, 0x99, 0x4c, 0x78, 0xa7, 0x65, 0x80, 0x16, 0x66, 0x2d, 0x57,
+  0xa0, 0xca, 0x12, 0xdc, 0x3a, 0x2f, 0xa1, 0x1e, 0x5b, 0xcf, 0x57, 0x4e,
+  0xdd, 0x4d, 0x89, 0x2d, 0x91, 0x70, 0xfa, 0xb2, 0x54, 0xa7, 0x96, 0xdd,
+  0xb7, 0x12, 0x6c, 0x84, 0x30, 0x2d, 0xb7, 0xa5, 0x37, 0x9d, 0xf9, 0x78,
+  0xeb, 0x64, 0xa1, 0x1b, 0x29, 0x5a, 0x80, 0x2b, 0x6c, 0x93, 0xf3, 0xce,
+  0x61, 0x61, 0x85, 0xd9, 0x09, 0x2d, 0x8c, 0x57, 0x19, 0xf0, 0x29, 0xd3,
+  0x24, 0x1b, 0x4f, 0xda, 0xfd, 0xa3, 0x49, 0xb6, 0xd5, 0xad, 0xa3, 0x87,
+  0xe8, 0x9c, 0xe7, 0x78, 0x88, 0x00, 0x28, 0xce, 0x24, 0xbb, 0x54, 0xe1,
+  0xb4, 0xe2, 0x13, 0x2b, 0x16, 0xd6, 0x8a, 0xdd, 0xc4, 0x6e, 0x35, 0xd8,
+  0x9e, 0x7b, 0x46, 0xe9, 0xb8, 0xec, 0xc9, 0x2a, 0xad, 0xa8, 0x83, 0x6b,
+  0x74, 0xfe, 0x6b, 0x80, 0x1c, 0xfc, 0x58, 0xee, 0xdf, 0x06, 0xe6, 0x3f,
+  0x87, 0xf3, 0xc6, 0x44, 0x89, 0x29, 0x32, 0xa2, 0x4a, 0x59, 0xd5, 0x0f,
+  0x6f, 0x31, 0x27, 0x96, 0xee, 0xa0, 0x52, 0x17, 0x5b, 0x50, 0x73, 0xf7,
+  0x6e, 0x14, 0x03, 0xdd, 0x96, 0x14, 0x30, 0xea, 0xa3, 0x5b, 0x7d, 0xaa,
+  0x95, 0xb7, 0xa3, 0x5b, 0xe9, 0x7f, 0x8d, 0x14, 0x26, 0x9a, 0xbe, 0x30,
+  0xb9, 0x06, 0x96, 0xdb, 0xb6, 0x93, 0xba, 0xe9, 0xda, 0x09, 0x7f, 0xf5,
+  0xed, 0xa8, 0xa7, 0x0e, 0x56, 0xf2, 0x7b, 0x60, 0x81, 0x0e, 0x96, 0xd0,
+  0xd5, 0xbe, 0x28, 0xde, 0xfb, 0xea, 0xe7, 0x39, 0xe2, 0x78, 0x7e, 0x50,
+  0xd9, 0xbf, 0x33, 0x49, 0xf6, 0x1c, 0x7b, 0xd6, 0x5c, 0xb9, 0x4a, 0x0a,
+  0x66, 0xb7, 0x9d, 0x80, 0x53, 0x6d, 0x00, 0x29, 0xb2, 0xb6, 0xa2, 0xb9,
+  0x04, 0x1f, 0xec, 0x7e, 0xf6, 0xed, 0x51, 0xc8, 0xe2, 0xa2, 0x8d, 0x2e,
+  0xc5, 0x18, 0x59, 0xc9, 0x5b, 0xa5, 0x2c, 0xfb, 0x65, 0x9a, 0x19, 0x71,
+  0x08, 0xe9, 0x6d, 0x90, 0x27, 0x92, 0xe2, 0xb5, 0x1f, 0xde, 0x60, 0x91,
+  0x1d, 0x3d, 0xf7, 0x02, 0xc5, 0x74, 0x24, 0x53, 0xec, 0x38, 0xed, 0xa5,
+  0xfa, 0x36, 0xc9, 0xba, 0x47, 0xc7, 0xde, 0x94, 0x32, 0xf1, 0x82, 0x77,
+  0x9b, 0x14, 0x36, 0x06, 0x00, 0x8e, 0x37, 0x63, 0x7a, 0x0d, 0xf9, 0xde,
+  0x67, 0x1d, 0x5f, 0x82, 0xb6, 0x9c, 0x98, 0x4e, 0x7c, 0xd4, 0x2d, 0x50,
+  0xa3, 0x88, 0x6a, 0xdb, 0x78, 0xea, 0x77, 0xbf, 0x97, 0xbe, 0x81, 0x10,
+  0x3b, 0x6c, 0xbf, 0xb1, 0xdb, 0x06, 0x78, 0x04, 0xb4, 0x12, 0x08, 0x40,
+  0x0d, 0xb4, 0xd9, 0x60, 0x62, 0x3a, 0xd2, 0xd5, 0x61, 0xd4, 0xa2, 0x86,
+  0x9e, 0xdc, 0xec, 0xa0, 0x06, 0x9d, 0xf3, 0xa9, 0x06, 0xa8, 0x04, 0xb5,
+  0x7c, 0x07, 0xd3, 0xa0, 0x53, 0x03, 0x1a, 0x46, 0xb6, 0x08, 0xd3, 0x87,
+  0x88, 0xdb, 0x82, 0xf9, 0x90, 0xac, 0xfc, 0xae, 0x19, 0x9c, 0x13, 0x57,
+  0xc5, 0xba, 0x3b, 0x08, 0x3d, 0x42, 0x7c, 0x01, 0x56, 0x6c, 0x42, 0x9b,
+  0xe7, 0x46, 0x87, 0xd8, 0x90, 0x30, 0xca, 0x02, 0xe6, 0xfa, 0xc1, 0x16,
+  0xc0, 0x06, 0x64, 0x4e, 0xcd, 0x72, 0x14, 0xbb, 0xca, 0xae, 0x4d, 0x92,
+  0xa1, 0xe8, 0x96, 0xc0, 0xa6, 0x74, 0xa6, 0x9c, 0xab, 0x4a, 0x6f, 0x33,
+  0x9d, 0x39, 0xef, 0xa0, 0xeb, 0x42, 0xf6, 0x45, 0x1c, 0x77, 0xab, 0x76,
+  0x1d, 0xef, 0xe4, 0x56, 0x2a, 0x16, 0x93, 0x12, 0x48, 0x65, 0x2d, 0x46,
+  0x36, 0x5f, 0x90, 0x43, 0xff, 0x87, 0x59, 0xab, 0x12, 0xe4, 0x2a, 0x4d,
+  0x2e, 0x55, 0x85, 0x21, 0xda, 0x16, 0xd8, 0x1f, 0xbc, 0x13, 0x9d, 0x92,
+  0xec, 0x1b, 0x99, 0x72, 0x9d, 0x9a, 0x35, 0x4b, 0x3a, 0x05, 0x36, 0x67,
+  0x36, 0x97, 0x4a, 0x46, 0xfd, 0x07, 0x3e, 0xe0, 0x16, 0x3e, 0xf1, 0x26,
+  0x01, 0x2e, 0xf3, 0xa1, 0xd5, 0xd2, 0xc2, 0xce, 0xa3, 0x06, 0xfa, 0xb7,
+  0x0e, 0x0b, 0xe0, 0x4f, 0x59, 0x93, 0x62, 0x17, 0x67, 0x73, 0x26, 0x62,
+  0x6a, 0x06, 0x8d, 0xbe, 0x0c, 0x3b, 0xb8, 0x2f, 0x87, 0x64, 0xa3, 0x91,
+  0xdc, 0xcd, 0x54, 0x28, 0x79, 0x0d, 0x83, 0xde, 0x62, 0x47, 0xa5, 0x38,
+  0x9b, 0x2a, 0x98, 0x32, 0x9c, 0x8d, 0x11, 0xab, 0x46, 0xb6, 0xcf, 0xb2,
+  0x72, 0x86, 0x6c, 0xa5, 0xfe, 0xd1, 0x12, 0xc2, 0xa3, 0x40, 0x0b, 0x6e,
+  0x99, 0x71, 0x03, 0x26, 0x86, 0xa2, 0x56, 0x77, 0xdf, 0x37, 0xec, 0x5d,
+  0x1d, 0x24, 0x51, 0x8d, 0x8b, 0xaf, 0xc1, 0x69, 0x07, 0xaa, 0x0c, 0x18,
+  0xc4, 0x6a, 0xad, 0xd5, 0xe7, 0xc3, 0x8c, 0x7c, 0xcd, 0x2d, 0x69, 0x86,
+  0x0f, 0x3e, 0x14, 0xa8, 0x4b, 0x6d, 0xa2, 0x77, 0xce, 0xd8, 0xeb, 0xd8,
+  0x0f, 0x16, 0xd9, 0x2c, 0x88, 0x51, 0xed, 0xc2, 0x8f, 0x36, 0xc3, 0x10,
+  0x75, 0x56, 0xec, 0xe7, 0x2f, 0x17, 0x7c, 0xaa, 0x4a, 0x02, 0x22, 0xd1,
+  0x0f, 0x62, 0x14, 0xc5, 0x2e, 0x37, 0x7e, 0xc9, 0xc4, 0xb8, 0x90, 0x2f,
+  0xd4, 0x05, 0xed, 0x9c, 0xc3, 0x76, 0xd5, 0x08, 0x4b, 0x1b, 0xaa, 0xe9,
+  0xe5, 0x8b, 0x54, 0xa4, 0x6e, 0x7e, 0xd7, 0x64, 0x0e, 0x94, 0xe2, 0xcb,
+  0xa5, 0x14, 0x35, 0xa0, 0x61, 0x4d, 0xaa, 0x96, 0x5b, 0x6a, 0xb9, 0xb7,
+  0xf6, 0x19, 0x30, 0xb2, 0xea, 0xad, 0x6c, 0x5b, 0xcb, 0x8c, 0xcf, 0x2b,
+  0x14, 0xea, 0xa8, 0x5c, 0x52, 0xce, 0x6e, 0x98, 0xae, 0xd0, 0xdb, 0x2d,
+  0x19, 0x25, 0x42, 0xc8, 0x6d, 0xcc, 0xfc, 0xf5, 0x96, 0xee, 0xd1, 0xe3,
+  0x68, 0x53, 0x38, 0xd9, 0x9c, 0xde, 0xff, 0xc4, 0xe6, 0xc3, 0x68, 0x59,
+  0xed, 0x88, 0x57, 0x3b, 0x95, 0x77, 0x3c, 0x06, 0x23, 0x54, 0x25, 0xdc,
+  0xf2, 0xe5, 0xe7, 0x8e, 0x1f, 0x94, 0x39, 0xf2, 0x53, 0x9b, 0xe8, 0x00,
+  0x81, 0xfa, 0xa0, 0x0f, 0xbe, 0x40, 0x1e, 0xfd, 0xb8, 0x8e, 0x16, 0xe3,
+  0x4d, 0x97, 0xae, 0x05, 0xee, 0x43, 0x2c, 0x7e, 0x5b, 0x03, 0xe5, 0x38,
+  0x7b, 0x54, 0x65, 0x1b, 0xf9, 0xe9, 0x13, 0x1e, 0x91, 0x47, 0x14, 0x79,
+  0x74, 0xa6, 0x4b, 0xd5, 0xc1, 0x56, 0xaa, 0x84, 0x54, 0x59, 0x11, 0x61,
+  0x45, 0x0c, 0x6f, 0xba, 0x02, 0x07, 0xe7, 0x80, 0x59, 0x9f, 0xda, 0xe1,
+  0x19, 0x34, 0x38, 0xde, 0x5f, 0x61, 0x97, 0x65, 0xc8, 0x62, 0xda, 0x3c,
+  0xb4, 0x8d, 0xec, 0x7e, 0x08, 0xa4, 0x70, 0x06, 0xbf, 0xf8, 0xfa, 0xfe,
+  0xe8, 0x76, 0x4b, 0x86, 0xc8, 0x4c, 0xcc, 0x83, 0x1b, 0xcd, 0x22, 0x73,
+  0x1d, 0xcb, 0x9f, 0x96, 0x51, 0xd2, 0x37, 0x08, 0x87, 0x99, 0xb9, 0xb3,
+  0xd1, 0xbf, 0x92, 0x02, 0x07, 0xe6, 0x7d, 0xa0, 0x03, 0x3f, 0xe3, 0xf8,
+  0xf8, 0xf9, 0xca, 0x95, 0x1d, 0xe6, 0x85, 0xe3, 0x9f, 0x0b, 0x85, 0x50,
+  0xc5, 0x6f, 0xd0, 0x00, 0x05, 0x20, 0x0e, 0x44, 0xfd, 0x40, 0x1f, 0xf7,
+  0xaf, 0xeb, 0x40, 0x8e, 0xb8, 0xc2, 0xec, 0x31, 0x57, 0x74, 0x29, 0xbb,
+  0xe0, 0x0c, 0x39, 0xdf, 0x8e, 0xe5, 0xde, 0x10, 0x22, 0xc0, 0x2e, 0x36,
+  0x92, 0x25, 0xd1, 0x3f, 0x05, 0x50, 0x92, 0x88, 0x48, 0xd6, 0x20, 0x5f,
+  0x06, 0x39, 0xf7, 0x28, 0x4e, 0x36, 0x5c, 0x24, 0xc9, 0x6b, 0x00, 0x00,
+  0x00, 0x01, 0x0c, 0x43, 0xd4, 0x08, 0x1f, 0xa2, 0x01, 0x61, 0x14, 0x5e,
+  0x67, 0xf0, 0x4e, 0xcf, 0xd6, 0xf2, 0xfe, 0x71, 0x0c, 0xe2, 0x54, 0xda,
+  0xb6, 0x8c, 0x0a, 0xad, 0xd1, 0x00, 0x63, 0x8f, 0x22, 0x88, 0x22, 0xbb,
+  0xbb, 0x4e, 0x04, 0x50, 0x0f, 0xb9, 0x5f, 0x25, 0x0f, 0xfd, 0xf9, 0xe4,
+  0x28, 0x25, 0xbe, 0xad, 0xa2, 0xdc, 0x00, 0xd0, 0x00, 0x45, 0x9c, 0x50,
+  0xc0, 0xe8, 0x6e, 0xbe, 0xad, 0x32, 0xfe, 0xe5, 0x26, 0xc2, 0x86, 0x54,
+  0x63, 0xc8, 0x82, 0x7f, 0xc8, 0x03, 0xd0, 0xfb, 0x6f, 0xec, 0x10, 0x80,
+  0x2a, 0xbf, 0xcc, 0x02, 0x27, 0x75, 0x2c, 0x0d, 0x3d, 0xbc, 0x2a, 0x93,
+  0x65, 0x28, 0x02, 0x23, 0xdb, 0x8b, 0x74, 0xc2, 0xe9, 0x09, 0xbf, 0xc9,
+  0x70, 0x10, 0x80, 0x1e, 0x47, 0xa4, 0x0d, 0xab, 0x52, 0x0e, 0x3a, 0x8d,
+  0xa1, 0x6c, 0x2e, 0x2c, 0x59, 0xb4, 0x36, 0xda, 0x53, 0x0c, 0xfc, 0x57,
+  0x00, 0x0c, 0x24, 0x39, 0x9c, 0xb7, 0x8d, 0xf4, 0x2d, 0xb7, 0x85, 0xda,
+  0xdc, 0x0d, 0xf2, 0xb9, 0x03, 0x12, 0x42, 0x44, 0x6f, 0x75, 0xb2, 0xf6,
+  0xfe, 0xcd, 0x0a, 0x0f, 0x35, 0xbc, 0xe6, 0x97, 0x8a, 0x42, 0xa6, 0x52,
+  0x5a, 0x37, 0xd3, 0x04, 0xbf, 0xf3, 0x6b, 0xac, 0x0d, 0xf3, 0xdd, 0xd9,
+  0x26, 0x1e, 0x36, 0x5a, 0x54, 0x3c, 0x6b, 0x4c, 0x2e, 0xa1, 0x29, 0x59,
+  0x46, 0xf7, 0x7d, 0xbe, 0x35, 0xcf, 0xfe, 0xbb, 0x45, 0xe9, 0xd2, 0xeb,
+  0x89, 0xfc, 0xef, 0x7c, 0xbe, 0x58, 0x6c, 0xa9, 0xe7, 0x13, 0x33, 0x32,
+  0x18, 0x7c, 0x0b, 0x6f, 0x9d, 0x4e, 0x32, 0xe7, 0x19, 0x96, 0x0f, 0xb9,
+  0x0e, 0xa6, 0x42, 0xce, 0x5a, 0x5d, 0x6a, 0x28, 0x88, 0xe7, 0x4f, 0x2b,
+  0x90, 0x73, 0xed, 0x98, 0xaf, 0x53, 0xcb, 0x44, 0x08, 0x6b, 0x30, 0x38,
+  0x5e, 0x6c, 0x88, 0x02, 0xb9, 0x57, 0xd6, 0x37, 0x9c, 0x98, 0x61, 0x49,
+  0x46, 0xa6, 0x52, 0x99, 0x99, 0x23, 0x7d, 0x90, 0x05, 0x84, 0x52, 0x38,
+  0xaf, 0xa8, 0x94, 0xf6, 0x2c, 0x11, 0x00, 0x17, 0x08, 0x98, 0xe3, 0x66,
+  0xf2, 0x62, 0xc5, 0xf2, 0x0c, 0xa1, 0x4d, 0xf2, 0x27, 0x49, 0x38, 0x73,
+  0x8b, 0x1e, 0x54, 0x87, 0x81, 0x4d, 0xd1, 0xca, 0x00, 0x64, 0xe7, 0x29,
+  0x0a, 0x94, 0xdc, 0xc5, 0x9e, 0x51, 0xf5, 0x42, 0x0d, 0x75, 0x84, 0x30,
+  0xc6, 0xf4, 0xf2, 0x2e, 0x54, 0xf4, 0x56, 0xe9, 0x90, 0xaa, 0x49, 0x6c,
+  0x9e, 0xe0, 0x2d, 0xb3, 0xd4, 0x14, 0xf8, 0x00, 0x31, 0x88, 0xdd, 0xf2,
+  0x3b, 0xaf, 0x3a, 0x59, 0x0d, 0xb2, 0x55, 0xfa, 0x1b, 0x62, 0xd0, 0xb2,
+  0x43, 0x22, 0x64, 0x64, 0x39, 0xbe, 0x54, 0x4e, 0xf3, 0x11, 0x43, 0x0f,
+  0x48, 0xbe, 0xad, 0xa3, 0xad, 0xd1, 0x53, 0xf2, 0xa0, 0x53, 0x71, 0xac,
+  0x3a, 0xa8, 0x4a, 0x94, 0xdd, 0x17, 0xec, 0x58, 0x6a, 0x06, 0x29, 0x4a,
+  0x39, 0xa1, 0x4e, 0x8c, 0xe3, 0x68, 0xa0, 0x16, 0xf1, 0xc6, 0xcd, 0x09,
+  0x2e, 0x4a, 0xbe, 0xad, 0xfa, 0x64, 0x01, 0xb8, 0x9a, 0x00, 0xeb, 0xee,
+  0x00, 0xe7, 0x7d, 0xfc, 0xa4, 0x28, 0xcc, 0x00, 0x3d, 0x17, 0xc3, 0x9d,
+  0x07, 0x95, 0x84, 0xed, 0xb8, 0xb4, 0x07, 0x8b, 0x6b, 0x7e, 0x71, 0xdf,
+  0xcb, 0xf2, 0x10, 0x8a, 0x6f, 0xd3, 0x20, 0x0a, 0x14, 0x10, 0x40, 0x4c,
+  0x8f, 0xdd, 0xf3, 0xa0, 0x11, 0x73, 0xb9, 0xb0, 0x05, 0x4a, 0xb4, 0x34,
+  0x62, 0xb7, 0x36, 0x6c, 0xe3, 0x7c, 0xb2, 0xe0, 0x6a, 0xee, 0xc0, 0x86,
+  0x98, 0x5e, 0xe4, 0x25, 0xb7, 0xf2, 0x89, 0x08, 0x3e, 0xf4, 0x55, 0x40,
+  0x47, 0xff, 0xd8, 0x27, 0x5d, 0xce, 0x48, 0x08, 0xff, 0xfb, 0xf8, 0x99,
+  0xa5, 0x04, 0x94, 0x5b, 0x74, 0x2e, 0x80, 0x1f, 0x00, 0x1b, 0x23, 0xe5,
+  0x02, 0x64, 0x76, 0x76, 0xa5, 0x94, 0x4c, 0xcd, 0x2e, 0x12, 0x9b, 0x37,
+  0x34, 0x0c, 0x11, 0x4e, 0x0c, 0xbd, 0x0a, 0x17, 0x2e, 0x20, 0xdf, 0xd6,
+  0xe6, 0x6d, 0x01, 0x1d, 0x48, 0xdd, 0x4b, 0x00, 0x0f, 0x05, 0x0a, 0xe1,
+  0x36, 0x06, 0x42, 0x2c, 0x7c, 0xc0, 0xc1, 0x9e, 0x72, 0x16, 0x18, 0xde,
+  0xb0, 0xc6, 0xf6, 0xcf, 0x6f, 0xce, 0x7b, 0x26, 0x4d, 0x4d, 0x7d, 0x18,
+  0x55, 0x33, 0x65, 0xbb, 0x14, 0x08, 0x7d, 0xb5, 0xb8, 0xcb, 0x5d, 0xc7,
+  0x1b, 0x60, 0xec, 0x99, 0x2c, 0x0e, 0x1e, 0x03, 0x36, 0xeb, 0x48, 0xff,
+  0x62, 0x05, 0xb8, 0x58, 0xd4, 0x15, 0x3c, 0xb6, 0xd3, 0xa0, 0xd9, 0xa9,
+  0xe2, 0xad, 0x97, 0x90, 0x42, 0xff, 0x5d, 0xbc, 0x20, 0x5e, 0x24, 0x2e,
+  0xfa, 0x12, 0x98, 0x87, 0xb5, 0x53, 0x9b, 0x41, 0x22, 0xf4, 0x5f, 0x7c,
+  0xef, 0x96, 0xd8, 0x32, 0x4e, 0x9c, 0x62, 0x8d, 0xfd, 0xac, 0x29, 0xbd,
+  0x29, 0x19, 0xd3, 0xeb, 0xfd, 0xee, 0xd1, 0x7b, 0x75, 0x64, 0x7c, 0x5c,
+  0xd9, 0x92, 0x4a, 0xba, 0x9e, 0x70, 0x9a, 0x90, 0x39, 0xb8, 0x2b, 0x09,
+  0xf9, 0x64, 0x09, 0xb1, 0x70, 0xe1, 0xa7, 0x44, 0x3c, 0x21, 0xae, 0x74,
+  0xd7, 0x08, 0xce, 0x67, 0x36, 0xd4, 0x3b, 0x69, 0x91, 0xd2, 0x58, 0x7a,
+  0xc2, 0x83, 0x94, 0xb6, 0x89, 0x1b, 0x3a, 0x54, 0x56, 0xf4, 0xdc, 0xf6,
+  0x15, 0xaf, 0xa2, 0xb2, 0x40, 0x09, 0x6c, 0x31, 0x16, 0xa1, 0xc3, 0xce,
+  0x39, 0xb0, 0xe5, 0x79, 0x3d, 0xf5, 0xf2, 0x2f, 0xe9, 0x23, 0xa2, 0xa5,
+  0x3c, 0x29, 0xbb, 0x3c, 0xdd, 0x14, 0x2f, 0x71, 0x0b, 0x3b, 0x3c, 0xae,
+  0x38, 0xfa, 0x12, 0x35, 0x02, 0x5b, 0x3a, 0xce, 0xd3, 0x8e, 0x8b, 0x02,
+  0x43, 0xb0, 0x3e, 0x0f, 0x2a, 0xfa, 0xb4, 0xc8, 0x53, 0x6d, 0xb5, 0x6b,
+  0x6d, 0xce, 0xae, 0x5d, 0x18, 0x7c, 0x2d, 0x42, 0x9a, 0xfd, 0xd8, 0xfb,
+  0x37, 0x28, 0x4d, 0xa5, 0x9c, 0x15, 0xea, 0xdc, 0x8e, 0xb2, 0xe7, 0x50,
+  0xe8, 0x3e, 0x86, 0x8c, 0x21, 0x04, 0xb5, 0xb7, 0x11, 0xf0, 0xb1, 0xc7,
+  0x0f, 0x30, 0xf2, 0xda, 0x6b, 0x68, 0xde, 0xcc, 0xf3, 0x72, 0xee, 0xbe,
+  0x8e, 0xc2, 0xce, 0x90, 0x90, 0xdc, 0xd1, 0x40, 0x61, 0xd6, 0xdb, 0xb4,
+  0xe0, 0xc1, 0xc8, 0xcc, 0x08, 0x60, 0x0b, 0x99, 0xa3, 0x4e, 0xab, 0xa3,
+  0x1b, 0x1b, 0xdf, 0xe7, 0x61, 0xc0, 0x3c, 0x33, 0x2c, 0x09, 0x0d, 0x62,
+  0x56, 0x2b, 0x76, 0x75, 0x72, 0xda, 0x99, 0x96, 0x8d, 0xb6, 0x16, 0xd8,
+  0xf2, 0x9b, 0xce, 0x92, 0x0f, 0x6d, 0x8e, 0x7d, 0xc7, 0x9b, 0x32, 0x0d,
+  0x2f, 0x10, 0xb8, 0xa5, 0x9c, 0xce, 0x26, 0x00, 0x1f, 0xfb, 0x48, 0x81,
+  0xa6, 0xdc, 0xb9, 0xb3, 0xd4, 0xe6, 0x89, 0x52, 0x94, 0xd9, 0x66, 0xcc,
+  0x79, 0x4d, 0xd3, 0x99, 0x67, 0x05, 0xa4, 0x0b, 0x53, 0xdb, 0xd4, 0x80,
+  0x37, 0x14, 0xef, 0xaf, 0x5b, 0xc3, 0xbd, 0xf9, 0xca, 0x96, 0xbb, 0x1f,
+  0xbc, 0x2d, 0x93, 0x5d, 0x77, 0x28, 0x6a, 0x96, 0xde, 0x9f, 0xe4, 0x47,
+  0xbf, 0xfc, 0x01, 0x8f, 0x5f, 0x0e, 0x76, 0xaa, 0x19, 0x86, 0xbd, 0xff,
+  0xb1, 0xbe, 0x90, 0xb6, 0xc1, 0x05, 0xf1, 0xbf, 0x1f, 0x1c, 0x00, 0x56,
+  0xf9, 0x2e, 0x69, 0x3a, 0xf3, 0xd1, 0x99, 0xa5, 0x87, 0xa8, 0x79, 0x92,
+  0x16, 0x10, 0xdc, 0xbd, 0x07, 0x00, 0xe4, 0x84, 0xde, 0x68, 0x89, 0xe5,
+  0x57, 0x42, 0x9b, 0xe9, 0x80, 0x14, 0xfc, 0x8a, 0x77, 0x28, 0x2a, 0x3a,
+  0x87, 0x4f, 0x37, 0x17, 0x71, 0x12, 0x1b, 0x0e, 0xf5, 0x6e, 0xc8, 0x01,
+  0x3f, 0xce, 0x7c, 0x90, 0x26, 0xfb, 0x75, 0xfb, 0xf2, 0x79, 0x92, 0x9b,
+  0x13, 0xf0, 0xb6, 0x0f, 0x5b, 0x5b, 0xd9, 0x80, 0x3c, 0xff, 0xe7, 0xc9,
+  0x07, 0x7a, 0x9d, 0xc9, 0x40, 0x27, 0x2e, 0x66, 0xdb, 0x51, 0x74, 0xe1,
+  0xd5, 0x50, 0xe8, 0xad, 0xee, 0xfe, 0x3f, 0xa2, 0x9e, 0x2c, 0x5e, 0x76,
+  0xf7, 0xc0, 0x1e, 0x73, 0x39, 0xc7, 0xc8, 0x90, 0x38, 0x3a, 0xad, 0x44,
+  0x38, 0x31, 0xbc, 0xde, 0xc4, 0x0a, 0xb8, 0x55, 0x2c, 0x34, 0xe8, 0x8d,
+  0xca, 0xe7, 0x70, 0x88, 0x58, 0x5b, 0x7f, 0x34, 0x00, 0x78, 0x23, 0x90,
+  0x03, 0x5e, 0xfd, 0xe7, 0xce, 0x5a, 0x4d, 0xe6, 0xbf, 0x76, 0xed, 0xa6,
+  0x17, 0x87, 0x7a, 0x1c, 0xdd, 0xd0, 0x04, 0xd8, 0x29, 0xfb, 0x5f, 0xc6,
+  0xec, 0x85, 0x2f, 0x96, 0xd5, 0xf2, 0x0b, 0xc0, 0xc6, 0xbb, 0xe8, 0x47,
+  0x70, 0x03, 0xa2, 0x27, 0xba, 0xc1, 0x38, 0xaa, 0x66, 0x13, 0x95, 0x64,
+  0xb1, 0x69, 0x41, 0x10, 0xb6, 0xf8, 0xb7, 0xb8, 0x8a, 0x46, 0xaf, 0x93,
+  0xe3, 0x61, 0xf3, 0x97, 0x73, 0x1e, 0x67, 0x9c, 0x3a, 0xc5, 0x68, 0x7b,
+  0xb8, 0xe9, 0x54, 0xa1, 0xb4, 0x04, 0x4d, 0xcd, 0x33, 0x31, 0x16, 0x46,
+  0xfe, 0xd4, 0x00, 0xe9, 0xdc, 0x7c, 0x08, 0x7e, 0xe4, 0xbb, 0x52, 0x07,
+  0xea, 0x54, 0x92, 0x0d, 0x6f, 0x0f, 0x7b, 0xc7, 0x6f, 0x4e, 0xeb, 0x50,
+  0x11, 0xff, 0xef, 0x74, 0xcc, 0x43, 0xce, 0xaa, 0xdc, 0x91, 0x41, 0xc2,
+  0xc8, 0xb3, 0x71, 0x00, 0x8c, 0x9d, 0xed, 0xc9, 0x10, 0xea, 0x6a, 0xe4,
+  0x5a, 0x18, 0xdc, 0x20, 0x0a, 0x3a, 0xf6, 0x7f, 0x0e, 0xa2, 0x5c, 0x3b,
+  0x76, 0xcc, 0xab, 0x2c, 0x4a, 0x50, 0x6f, 0x83, 0x79, 0xfc, 0x8a, 0x9e,
+  0x4e, 0x8e, 0x74, 0xa1, 0x35, 0x5b, 0x33, 0x11, 0x12, 0x37, 0xd7, 0x00,
+  0x40, 0xff, 0x79, 0xa2, 0x1d, 0x5d, 0x5d, 0x2a, 0xd9, 0x5e, 0xe3, 0x0d,
+  0xa1, 0x6d, 0xf6, 0x00, 0x05, 0xdf, 0x34, 0x01, 0xb8, 0x03, 0xce, 0x6f,
+  0x7d, 0x82, 0x47, 0xfe, 0x38, 0xda, 0x62, 0x1f, 0x0b, 0x81, 0xad, 0xf0,
+  0xbe, 0xbe, 0xff, 0x22, 0x44, 0xed, 0xdf, 0x83, 0x16, 0xd8, 0xe7, 0x66,
+  0xa1, 0x86, 0xdf, 0xca, 0x25, 0x28, 0xf8, 0xdf, 0x5c, 0x9f, 0x5e, 0xff,
+  0xe2, 0xb7, 0xae, 0xf9, 0xe6, 0x8d, 0x2a, 0xd5, 0x36, 0x40, 0xc6, 0xf6,
+  0x36, 0xbf, 0x97, 0xc3, 0x6e, 0x96, 0x4a, 0x6d, 0xa0, 0x7d, 0x8a, 0x4a,
+  0x60, 0x00, 0x00, 0x01, 0x0d, 0x43, 0xf7, 0xdd, 0x8a, 0x78, 0x80, 0x06,
+  0xc0, 0x0d, 0x05, 0x73, 0x52, 0x25, 0x20, 0x02, 0x10, 0x03, 0xf7, 0x2b,
+  0x8d, 0x50, 0xea, 0x6d, 0xa5, 0x95, 0x43, 0x65, 0x6f, 0x4c, 0x00, 0xf8,
+  0x5b, 0x80, 0x1b, 0x77, 0xcf, 0xcd, 0xdc, 0xa3, 0xe7, 0x9f, 0x0b, 0x24,
+  0x3a, 0xfe, 0xa5, 0x29, 0x43, 0x1a, 0x10, 0x34, 0x89, 0xcd, 0xde, 0x5f,
+  0xc5, 0xa7, 0x77, 0x37, 0xc9, 0x21, 0x8a, 0x61, 0xc1, 0x2d, 0xf3, 0xe0,
+  0x07, 0xc0, 0x0d, 0x78, 0xe7, 0xe4, 0x88, 0xff, 0x6f, 0x68, 0x85, 0xf9,
+  0x3e, 0x6d, 0x96, 0x6e, 0x2a, 0x40, 0xe9, 0x21, 0x77, 0xc1, 0xbc, 0x34,
+  0xfc, 0x56, 0xe7, 0x96, 0x64, 0xb2, 0xac, 0xa5, 0x8e, 0x52, 0x82, 0x02,
+  0x5b, 0xf8, 0x7d, 0xcb, 0xe7, 0x95, 0x60, 0x62, 0x4b, 0x2c, 0x21, 0x56,
+  0xd9, 0x06, 0xd6, 0xfa, 0xb0, 0x02, 0x1c, 0x80, 0x09, 0x1c, 0x28, 0x89,
+  0xf5, 0x10, 0xf8, 0x1d, 0x67, 0x7c, 0xf6, 0xee, 0xa4, 0x35, 0xda, 0x5e,
+  0x54, 0x1c, 0xa3, 0x61, 0x4d, 0x98, 0x10, 0x3f, 0x4b, 0xf9, 0xa0, 0x0f,
+  0xfe, 0x33, 0x3d, 0x88, 0xf9, 0x46, 0x49, 0xdb, 0xf2, 0x24, 0xe3, 0x4b,
+  0xb8, 0xaa, 0xd9, 0xc2, 0xe2, 0x94, 0xde, 0x7b, 0xe1, 0xcd, 0xf1, 0x80,
+  0x1c, 0x8a, 0xec, 0x01, 0x0f, 0xf0, 0x43, 0xb5, 0xd8, 0x1b, 0x39, 0x9d,
+  0x87, 0x28, 0x0a, 0xa8, 0xdf, 0x46, 0xfb, 0x7f, 0x7e, 0x77, 0xfe, 0x40,
+  0x31, 0xf4, 0x63, 0xae, 0x3b, 0xf3, 0x77, 0xc1, 0x0a, 0x40, 0xb6, 0xfa,
+  0x37, 0xf7, 0xe7, 0xbf, 0xa8, 0x03, 0x71, 0x62, 0x44, 0xe8, 0x62, 0x6b,
+  0xd4, 0x39, 0x3f, 0x08, 0x98, 0x32, 0x48, 0xdf, 0x3f, 0xfe, 0x0b, 0x00,
+  0x10, 0x67, 0x57, 0x66, 0x0c, 0xa5, 0xe1, 0x65, 0x9e, 0xd3, 0x23, 0xba,
+  0xe5, 0xf6, 0xda, 0x02, 0x29, 0x0b, 0x6b, 0xdb, 0x31, 0xf4, 0xbf, 0x06,
+  0xfe, 0x5f, 0xdf, 0xbe, 0xfd, 0xb2, 0x75, 0xd6, 0xd4, 0x2d, 0x65, 0x88,
+  0x89, 0xe8, 0xde, 0x08, 0x00, 0xf5, 0xe2, 0x3d, 0x9c, 0xfe, 0x79, 0xc9,
+  0x13, 0xf0, 0xee, 0xe0, 0xea, 0x03, 0x56, 0xfa, 0x3f, 0xd5, 0xc0, 0x82,
+  0x02, 0x7e, 0xdc, 0x9a, 0x5c, 0x39, 0x49, 0xf9, 0x21, 0xdb, 0x25, 0x2e,
+  0x0d, 0x6f, 0x8d, 0x75, 0x67, 0x44, 0x0e, 0x6a, 0x84, 0x3d, 0x72, 0x98,
+  0x38, 0xe1, 0xc3, 0x5b, 0x93, 0x78, 0x82, 0x66, 0xbb, 0x89, 0x83, 0xe2,
+  0x5c, 0x6c, 0x2c, 0x34, 0xa8, 0xda, 0x11, 0x45, 0xe0, 0x87, 0x53, 0x2b,
+  0x8e, 0x53, 0x35, 0x15, 0x2a, 0x1c, 0x1a, 0x90, 0xe6, 0xa3, 0xfb, 0xb6,
+  0xed, 0xb6, 0x00, 0x46, 0x5d, 0x28, 0x28, 0x31, 0xbd, 0x8e, 0x77, 0x78,
+  0xa2, 0xf5, 0xd8, 0x17, 0x69, 0xcd, 0xe0, 0x3e, 0xd2, 0xfd, 0x51, 0x20,
+  0x5e, 0xcd, 0xca, 0xa8, 0x71, 0x68, 0xde, 0x97, 0xee, 0xb6, 0x92, 0x14,
+  0x5b, 0x76, 0xce, 0x9d, 0xc0, 0x9d, 0x57, 0x00, 0xaa, 0xa0, 0xd8, 0x31,
+  0xbc, 0xe0, 0xa9, 0x38, 0xe1, 0xda, 0x50, 0x48, 0xc8, 0xad, 0xf4, 0x0e,
+  0x45, 0xe6, 0xfd, 0x26, 0xc7, 0xe1, 0x55, 0x1e, 0xb5, 0xd9, 0xa1, 0xd4,
+  0x3c, 0x7c, 0x94, 0xa3, 0xda, 0x00, 0x27, 0xf9, 0xf6, 0xfa, 0x8a, 0x23,
+  0x77, 0x5f, 0x14, 0x11, 0x00, 0x13, 0xae, 0xc8, 0x84, 0x7e, 0xf8, 0x8e,
+  0x81, 0x1b, 0xc6, 0xae, 0xc8, 0x34, 0xa2, 0x8b, 0x6a, 0x44, 0x18, 0xda,
+  0x13, 0x65, 0x6f, 0xe6, 0xe0, 0x38, 0xdb, 0x23, 0x6d, 0xd2, 0xe0, 0x16,
+  0xd9, 0x3d, 0xdd, 0x08, 0x12, 0x3b, 0x68, 0x69, 0xb6, 0x8f, 0x2d, 0xb7,
+  0xda, 0xaf, 0xb4, 0xc0, 0x82, 0xc6, 0x34, 0x51, 0xa4, 0xa6, 0x34, 0xaa,
+  0xde, 0xde, 0xcc, 0x32, 0xcb, 0x35, 0x06, 0xd8, 0x55, 0x42, 0xd4, 0x7b,
+  0x75, 0xbe, 0x94, 0x02, 0xdf, 0x99, 0x5e, 0xfc, 0x0c, 0x8e, 0xda, 0x52,
+  0xd0, 0xc5, 0xb1, 0xb9, 0xe4, 0x68, 0xff, 0x97, 0xdd, 0x2c, 0xe5, 0x5d,
+  0xdf, 0x27, 0x2c, 0xc2, 0xce, 0x3e, 0xb6, 0xbe, 0xb9, 0xbe, 0xde, 0xd8,
+  0xee, 0x02, 0x6c, 0xc9, 0x0a, 0x83, 0x21, 0x50, 0x73, 0x73, 0xd3, 0x64,
+  0x96, 0x46, 0x76, 0xa5, 0x6f, 0xde, 0xdb, 0xa4, 0x7f, 0x8f, 0x67, 0x6d,
+  0xa3, 0xd2, 0xb8, 0x47, 0x75, 0xca, 0x02, 0x27, 0x48, 0x88, 0xdc, 0xdc,
+  0xc9, 0x74, 0x5a, 0x84, 0x7e, 0x04, 0xf6, 0x28, 0x5d, 0xc1, 0xb0, 0xe9,
+  0x69, 0x96, 0x84, 0x94, 0xc9, 0xec, 0x08, 0x5f, 0xe3, 0xc7, 0x3d, 0x6e,
+  0xd3, 0xca, 0xd0, 0x33, 0x1f, 0x80, 0x03, 0x57, 0x4d, 0x8a, 0x13, 0x2b,
+  0x55, 0x2c, 0xe3, 0x9e, 0xa9, 0x0f, 0x8d, 0xf6, 0xd5, 0x5a, 0xb4, 0xb9,
+  0xc3, 0xa9, 0xc1, 0x0d, 0xea, 0x48, 0x6a, 0x92, 0x5b, 0xd5, 0x81, 0xf3,
+  0x49, 0x2d, 0xd1, 0x51, 0xe0, 0x07, 0x06, 0xe2, 0x01, 0x08, 0x40, 0x17,
+  0x28, 0xf3, 0xb6, 0xad, 0x24, 0xb2, 0xc3, 0x48, 0xfe, 0x7a, 0x58, 0x0a,
+  0xdd, 0xd7, 0x25, 0x78, 0xe2, 0xab, 0x68, 0x11, 0xcb, 0xc5, 0x73, 0x56,
+  0x3c, 0xc5, 0x49, 0x1d, 0xdf, 0x6f, 0xdb, 0x03, 0x52, 0xdd, 0x90, 0xa9,
+  0x47, 0x4b, 0x5a, 0xb7, 0x61, 0x02, 0xfd, 0x1d, 0xde, 0x84, 0x95, 0x9b,
+  0xd6, 0x5b, 0x4a, 0x42, 0xd1, 0x17, 0xc5, 0xae, 0x94, 0xda, 0xc6, 0xeb,
+  0x9c, 0xc1, 0x74, 0x54, 0xcc, 0x2c, 0x62, 0xef, 0x12, 0xc2, 0xcf, 0x19,
+  0x46, 0x9e, 0x1a, 0xcb, 0x0d, 0xe3, 0xe4, 0x46, 0x98, 0x78, 0xe1, 0x4e,
+  0xb3, 0x74, 0x69, 0x34, 0xaa, 0xa8, 0xc7, 0x9e, 0x70, 0x89, 0x9e, 0xd3,
+  0x9b, 0x46, 0xd5, 0x82, 0x7a, 0xb9, 0xe6, 0x30, 0xe0, 0xca, 0xd8, 0xdc,
+  0x67, 0x0e, 0xce, 0x27, 0x8e, 0x45, 0x7f, 0xa2, 0xd2, 0x9a, 0x0e, 0x6a,
+  0x3e, 0x37, 0xae, 0x13, 0xb6, 0xdf, 0x2c, 0xc8, 0x33, 0xf1, 0x9b, 0x4b,
+  0xa1, 0x6c, 0x65, 0x33, 0x87, 0xc4, 0x81, 0x17, 0xb7, 0xe9, 0xe7, 0x0d,
+  0x90, 0x61, 0x25, 0xab, 0x7d, 0xcd, 0x49, 0x29, 0x43, 0x25, 0x3b, 0x0b,
+  0x83, 0x8f, 0x24, 0x35, 0x7c, 0x4d, 0xd7, 0xee, 0x94, 0x36, 0xc9, 0xae,
+  0x86, 0x95, 0x4b, 0xa5, 0x9e, 0x30, 0x35, 0x6b, 0x45, 0x6b, 0x6e, 0xe7,
+  0x5d, 0xd8, 0x03, 0x9b, 0x4e, 0x5b, 0xb2, 0xd3, 0x90, 0x86, 0xd5, 0xed,
+  0x91, 0x40, 0xea, 0xa3, 0x9b, 0x35, 0x48, 0x92, 0xc0, 0x82, 0xda, 0xf9,
+  0xf9, 0xd3, 0xc0, 0x22, 0xf5, 0x3d, 0x86, 0xb6, 0xe5, 0xc5, 0xb8, 0x68,
+  0x52, 0x1a, 0x74, 0x39, 0x97, 0x9e, 0x88, 0x3e, 0xd9, 0xbc, 0xc5, 0x29,
+  0x2e, 0x49, 0x4c, 0xcb, 0x42, 0x62, 0x95, 0x68, 0x53, 0x73, 0xfa, 0x97,
+  0x8e, 0xe4, 0xdf, 0x49, 0x14, 0x34, 0x31, 0xba, 0x3f, 0x4e, 0xb0, 0x01,
+  0xc8, 0x9c, 0x27, 0xe9, 0x65, 0x07, 0xf4, 0x56, 0x13, 0xa8, 0x0a, 0xdf,
+  0x43, 0x4e, 0x0b, 0x68, 0x1a, 0x53, 0x73, 0xf0, 0x06, 0x35, 0x6f, 0xa3,
+  0x7f, 0x47, 0x00, 0x5a, 0x01, 0x67, 0xdc, 0x8a, 0xef, 0x8d, 0x10, 0xf3,
+  0xa4, 0xb8, 0x41, 0x73, 0xe7, 0x98, 0xd3, 0xa6, 0x15, 0x61, 0x43, 0xea,
+  0xb7, 0x98, 0x12, 0xe0, 0x01, 0x0f, 0xb0, 0x8e, 0x5f, 0xe1, 0x38, 0x93,
+  0x09, 0x46, 0x36, 0x0f, 0x6c, 0x98, 0x47, 0xd8, 0xfd, 0xc1, 0xf6, 0xbb,
+  0x0c, 0x33, 0x4a, 0x1e, 0x32, 0x8e, 0x39, 0xbb, 0x80, 0x0f, 0x28, 0xb0,
+  0x06, 0x20, 0x0f, 0xf8, 0xe2, 0x71, 0xb0, 0x75, 0xd2, 0x75, 0xd7, 0x24,
+  0x0f, 0xa5, 0xc2, 0xa1, 0x51, 0xb9, 0xf2, 0xf9, 0x49, 0x29, 0x29, 0xbc,
+  0x5c, 0x86, 0x61, 0x4d, 0xfb, 0x01, 0x5c, 0x00, 0x19, 0x77, 0xdf, 0x29,
+  0x81, 0xa6, 0xb9, 0xf2, 0x4c, 0x5f, 0x16, 0xf9, 0x5c, 0x81, 0xdd, 0x6d,
+  0xf1, 0x5c, 0xca, 0x43, 0xb2, 0x29, 0x29, 0xbe, 0x9e, 0x00, 0xd8, 0x58,
+  0x20, 0x80, 0xb7, 0x06, 0x91, 0xc9, 0xd0, 0x67, 0x13, 0x6f, 0x16, 0x3a,
+  0xc2, 0x6d, 0x01, 0xc8, 0xf4, 0x28, 0x6b, 0x7c, 0xaf, 0x8b, 0x75, 0xdf,
+  0x17, 0x9c, 0x09, 0xb9, 0xcf, 0x95, 0x40, 0x11, 0x5d, 0xb0, 0xa8, 0xd8,
+  0xec, 0x3f, 0x00, 0x06, 0x4a, 0xd9, 0x50, 0xd6, 0xfd, 0x57, 0xbc, 0xde,
+  0xb9, 0xc7, 0xae, 0x06, 0x6c, 0x55, 0xcb, 0x02, 0x2c, 0x2d, 0xbe, 0x82,
+  0x00, 0xec, 0x50, 0x01, 0xd3, 0xbb, 0x27, 0x9a, 0x3e, 0xf6, 0xf1, 0x3b,
+  0xa1, 0xf9, 0x4a, 0xc3, 0xa2, 0xc9, 0x32, 0x14, 0x3d, 0xbc, 0xe7, 0xc6,
+  0xf3, 0xfe, 0x82, 0x9d, 0xcb, 0xdc, 0x59, 0x30, 0xcd, 0xdb, 0xae, 0x1e,
+  0x9e, 0x45, 0xc0, 0xf8, 0x30, 0x9a, 0xdd, 0xbf, 0xf6, 0x75, 0xf5, 0xbc,
+  0x0a, 0xe3, 0x32, 0x1d, 0x26, 0xdb, 0x15, 0xc8, 0x7a, 0xac, 0x1b, 0x42,
+  0x9b, 0xcc, 0xb8, 0xa7, 0x27, 0x80, 0x1e, 0xd9, 0x86, 0xc6, 0xf8, 0x7f,
+  0x5f, 0x8e, 0x5f, 0xc0, 0xa1, 0x3b, 0x47, 0x57, 0x6b, 0xb2, 0xec, 0x83,
+  0x8f, 0x80, 0x72, 0x36, 0xe0, 0x05, 0xe0, 0x0f, 0x2e, 0x91, 0xfc, 0x9e,
+  0xeb, 0x95, 0x51, 0xfb, 0x62, 0xdc, 0xcb, 0x69, 0x90, 0xbd, 0x18, 0xad,
+  0x8b, 0x8d, 0x70, 0x02, 0x69, 0xc7, 0x02, 0xdd, 0x40, 0x7b, 0x16, 0x2a,
+  0xc4, 0x32, 0x1e, 0x50, 0xc0, 0xa8, 0xde, 0xa8, 0x00, 0xab, 0x6f, 0xf7,
+  0xb1, 0x7d, 0x8a, 0x96, 0x8f, 0x86, 0xf3, 0xce, 0xe9, 0x65, 0x5a, 0x85,
+  0xd5, 0x28, 0x96, 0xda, 0xda, 0x9b, 0x61, 0x4c, 0xee, 0x96, 0xdf, 0x9d,
+  0xe8, 0xd0, 0x02, 0x87, 0x6a, 0xf7, 0x46, 0xae, 0xe8, 0xbd, 0xde, 0x70,
+  0xb1, 0x9e, 0x5f, 0xa8, 0xbe, 0x2d, 0xe3, 0xdf, 0x79, 0xfe, 0xce, 0x11,
+  0xc1, 0x92, 0xd7, 0xa2, 0x78, 0xa9, 0xde, 0x2d, 0xf4, 0x37, 0x89, 0x80,
+  0x82, 0x02, 0xbb, 0xce, 0xc7, 0x58, 0x4c, 0xb2, 0x3d, 0x33, 0x24, 0xa1,
+  0x11, 0x0a, 0x81, 0x4c, 0xbf, 0xdd, 0x84, 0x4f, 0x7e, 0xf4, 0x5b, 0xe2,
+  0x2c, 0xb8, 0x66, 0x6d, 0x86, 0x60, 0xf0, 0x89, 0x1b, 0x1e, 0x83, 0xae,
+  0x69, 0x0a, 0xb3, 0x85, 0x40, 0x2d, 0xbe, 0x98, 0xbe, 0xef, 0xc7, 0x2f,
+  0x9f, 0x3d, 0xdd, 0xd3, 0xb8, 0xd9, 0x29, 0x86, 0x5b, 0xb4, 0x7e, 0x53,
+  0x92, 0x28, 0xe6, 0xf2, 0xdf, 0x4e, 0x34, 0x01, 0xac, 0xf8, 0x9f, 0x99,
+  0xfb, 0xdd, 0xd4, 0x95, 0x6e, 0xd2, 0xc9, 0xa7, 0xa0, 0xd6, 0xe7, 0x11,
+  0x26, 0xfd, 0xc8, 0xc2, 0x05, 0xfb, 0x60, 0x6e, 0x65, 0x7e, 0x5b, 0xbb,
+  0x20, 0x61, 0x69, 0x5b, 0x38, 0x03, 0x17, 0x71, 0xf4, 0xf7, 0xdc, 0x0f,
+  0x87, 0xad, 0xce, 0x7a, 0x90, 0xd4, 0x0d, 0xc9, 0x62, 0xf8, 0xb7, 0x4f,
+  0x12, 0xb9, 0xd9, 0xb2, 0x84, 0xa4, 0x58, 0x42, 0x69, 0x18, 0x05, 0x30,
+  0x00, 0x00, 0x01, 0x0e, 0x43, 0xfa, 0xd0, 0x87, 0x4c, 0x11, 0xbc, 0xe4,
+  0x90, 0xb2, 0xea, 0x14, 0x60, 0x5b, 0x78, 0x70, 0x02, 0x7e, 0x7a, 0x00,
+  0x75, 0xd1, 0x02, 0xef, 0x35, 0x60, 0x22, 0x00, 0x26, 0x5b, 0x8f, 0xbb,
+  0x80, 0x60, 0xc3, 0x14, 0xc3, 0xe1, 0x61, 0x81, 0x8d, 0xed, 0x7e, 0xa0,
+  0x16, 0x00, 0x2d, 0x23, 0x5d, 0xe9, 0x2d, 0x2a, 0xae, 0x75, 0xa0, 0x66,
+  0xcb, 0x2a, 0x16, 0x59, 0x29, 0xbb, 0x82, 0x78, 0xe7, 0x3d, 0xf8, 0x00,
+  0xb2, 0x55, 0xab, 0x86, 0x3e, 0x1f, 0x1f, 0x4a, 0x91, 0x14, 0x69, 0x6d,
+  0xf3, 0x59, 0x24, 0xd3, 0x2d, 0x21, 0x9c, 0xde, 0x45, 0x95, 0xf5, 0x27,
+  0x82, 0xc6, 0xf5, 0x72, 0xed, 0x00, 0x2f, 0x79, 0x16, 0x41, 0x7c, 0xdf,
+  0xdd, 0xef, 0x34, 0xcb, 0x84, 0x13, 0x09, 0xee, 0x8b, 0x92, 0xcb, 0x5d,
+  0xe4, 0xa8, 0x72, 0xb7, 0xbf, 0xb5, 0xdb, 0xc4, 0x55, 0x83, 0x2e, 0xab,
+  0xd6, 0x50, 0x11, 0x01, 0xed, 0xc5, 0xb6, 0x80, 0x5b, 0x65, 0xb4, 0xb4,
+  0x59, 0x9b, 0x91, 0x14, 0x9b, 0x4b, 0xb4, 0xf2, 0xdb, 0xad, 0x9b, 0xb5,
+  0xf2, 0x05, 0x98, 0x52, 0x4b, 0xfa, 0x18, 0x59, 0xde, 0xad, 0xb3, 0xa7,
+  0x9a, 0x18, 0xa4, 0x86, 0xf4, 0x23, 0x7d, 0x0c, 0x5c, 0x2d, 0x03, 0x29,
+  0x71, 0x65, 0x18, 0x43, 0x6f, 0x2c, 0x00, 0xb7, 0xe7, 0xcb, 0x24, 0xcc,
+  0x71, 0x63, 0x4a, 0x1a, 0xde, 0x96, 0x48, 0xbb, 0x2e, 0x51, 0xb5, 0x21,
+  0x85, 0xca, 0x49, 0x6c, 0x79, 0x2e, 0xba, 0x47, 0x5b, 0x07, 0x87, 0xd8,
+  0x50, 0x61, 0x43, 0xeb, 0x68, 0xfe, 0x77, 0x87, 0x67, 0x94, 0xf0, 0xa7,
+  0xd4, 0xac, 0xae, 0xdc, 0x85, 0x4f, 0x56, 0xfc, 0x08, 0x03, 0x59, 0x00,
+  0x1e, 0x6f, 0xff, 0x79, 0xe2, 0x04, 0x08, 0x22, 0x67, 0x2b, 0x40, 0x4b,
+  0x69, 0xbc, 0xac, 0x41, 0xd0, 0x3e, 0xb7, 0xe3, 0x8f, 0xaf, 0x0f, 0x22,
+  0x66, 0x9a, 0x65, 0x83, 0x53, 0x2a, 0x12, 0x4a, 0x6f, 0xe8, 0x24, 0xc7,
+  0x67, 0x7e, 0x56, 0xed, 0x43, 0xab, 0xdc, 0x1c, 0xa4, 0x30, 0xe8, 0xdf,
+  0x9c, 0xc0, 0x14, 0x13, 0xc0, 0x16, 0x0a, 0xb7, 0x9e, 0xf6, 0xd1, 0xaa,
+  0x23, 0x2d, 0xd3, 0x0e, 0xb4, 0x38, 0x64, 0x81, 0x2d, 0xc8, 0xe8, 0x01,
+  0x66, 0xc9, 0x7c, 0x57, 0xc4, 0xf6, 0xe6, 0x52, 0x75, 0x02, 0xdb, 0xfc,
+  0xdb, 0xf0, 0x23, 0x05, 0xab, 0xd0, 0x32, 0x1c, 0x69, 0xde, 0x0c, 0x04,
+  0xd0, 0x0b, 0x5f, 0x35, 0x60, 0x0a, 0x83, 0xa1, 0x94, 0x2c, 0xb3, 0xa3,
+  0x7b, 0x5f, 0xae, 0xe8, 0x94, 0xe3, 0x16, 0x0d, 0x2e, 0x42, 0xd2, 0x86,
+  0x41, 0x8d, 0xc7, 0x71, 0x3f, 0xe3, 0xbe, 0x0d, 0xa5, 0x8c, 0x2a, 0xc9,
+  0x43, 0x1b, 0x47, 0x2d, 0xe3, 0x2d, 0x94, 0x30, 0x2d, 0xb3, 0x95, 0x4f,
+  0x6f, 0x73, 0xf3, 0x5f, 0xf7, 0x22, 0x0a, 0xee, 0x65, 0x3b, 0x03, 0xf9,
+  0x17, 0x7a, 0xd4, 0xa3, 0x13, 0x39, 0xb1, 0x55, 0x47, 0x16, 0xdc, 0xc1,
+  0x55, 0xff, 0x41, 0x1d, 0x70, 0x4f, 0x09, 0xd8, 0x28, 0x53, 0x9c, 0x48,
+  0x89, 0x14, 0x32, 0x37, 0xbb, 0x11, 0x1c, 0x00, 0xe5, 0xff, 0xfe, 0x32,
+  0x4a, 0x52, 0x9b, 0xc7, 0xdb, 0xda, 0x89, 0x36, 0xe0, 0xd3, 0x62, 0x55,
+  0xb3, 0x46, 0xa0, 0xda, 0x31, 0xbe, 0x6e, 0x47, 0xf6, 0x76, 0xe6, 0x6e,
+  0x65, 0xc3, 0x91, 0x75, 0x0d, 0x44, 0x08, 0x6d, 0x31, 0x34, 0xc2, 0xe0,
+  0x04, 0x55, 0xad, 0x47, 0x90, 0x9b, 0xed, 0x09, 0x15, 0x08, 0xdc, 0xfc,
+  0xd9, 0x9c, 0xf9, 0x97, 0x2c, 0xe7, 0xbc, 0x97, 0x75, 0xd1, 0xc9, 0x61,
+  0x6a, 0x85, 0xd6, 0xf2, 0xd5, 0x04, 0x0b, 0xa6, 0x37, 0xa5, 0x76, 0x52,
+  0x2f, 0x6e, 0x16, 0xe9, 0xe9, 0x4b, 0x40, 0xb6, 0xcc, 0x2d, 0x7e, 0xc4,
+  0x61, 0x4f, 0x7d, 0xa0, 0x93, 0xff, 0x85, 0x81, 0xca, 0x16, 0xd9, 0x3a,
+  0x1b, 0xb9, 0x64, 0x0a, 0xab, 0x63, 0x67, 0x90, 0xe6, 0xfc, 0xc3, 0xa5,
+  0x17, 0x12, 0x10, 0xd0, 0x90, 0xde, 0x84, 0xd3, 0x79, 0x0e, 0xc0, 0xb9,
+  0x46, 0x8c, 0x64, 0x00, 0x7f, 0x27, 0x5f, 0x3a, 0x57, 0x86, 0x8f, 0x6a,
+  0x37, 0x2e, 0xf5, 0x29, 0x41, 0x11, 0x10, 0xe2, 0x9b, 0x59, 0x67, 0x92,
+  0x56, 0xb3, 0xa2, 0x5f, 0x56, 0xfd, 0x4c, 0xda, 0x47, 0xf3, 0x87, 0x82,
+  0x38, 0x01, 0xc5, 0xcb, 0x76, 0x80, 0x8a, 0xc3, 0x7c, 0x22, 0xb6, 0xaf,
+  0x70, 0x42, 0x00, 0x8d, 0x7b, 0xac, 0x0a, 0x00, 0xa8, 0xce, 0xaa, 0x84,
+  0xa9, 0x97, 0xd0, 0xb8, 0xd9, 0xf4, 0x10, 0xbf, 0xc4, 0x02, 0xaa, 0x58,
+  0x24, 0xff, 0xde, 0x79, 0x96, 0x12, 0x92, 0xd2, 0x53, 0x77, 0x72, 0xd7,
+  0x60, 0x9b, 0x3d, 0x3d, 0xb7, 0x5e, 0x9e, 0x0f, 0xb8, 0x00, 0x30, 0x56,
+  0xe8, 0x80, 0x85, 0xff, 0x53, 0x40, 0xe6, 0xef, 0x80, 0x85, 0xff, 0x53,
+  0x40, 0xe2, 0x43, 0x7e, 0x50, 0xa0, 0x07, 0xd7, 0x39, 0xa8, 0x13, 0xa2,
+  0x6e, 0x3a, 0xf8, 0x99, 0x97, 0x03, 0x06, 0xd6, 0xeb, 0x60, 0x7e, 0xe3,
+  0xad, 0xa1, 0x92, 0x81, 0x9b, 0x20, 0x5d, 0xc5, 0x02, 0x9b, 0x9e, 0x5f,
+  0x1b, 0xd4, 0xce, 0x22, 0x17, 0x65, 0x00, 0x3d, 0xef, 0xe6, 0x49, 0x60,
+  0x65, 0xb2, 0x2f, 0x8a, 0x63, 0x5f, 0x96, 0xd0, 0xfb, 0x43, 0x0b, 0xee,
+  0xa6, 0x6a, 0x9c, 0x58, 0xd0, 0xd3, 0x9b, 0x73, 0x9b, 0xb0, 0xf0, 0x39,
+  0xbc, 0xe2, 0x4c, 0xfb, 0x91, 0x84, 0x57, 0x48, 0x11, 0x6d, 0xba, 0x1b,
+  0x43, 0xc3, 0xda, 0x77, 0x60, 0x89, 0xed, 0x74, 0xf0, 0x1e, 0xf5, 0xce,
+  0x07, 0x00, 0x89, 0x06, 0xd3, 0xbc, 0x1b, 0xa2, 0x21, 0x3f, 0xe2, 0x7a,
+  0x2b, 0xc3, 0x21, 0x72, 0x9c, 0xd5, 0xbf, 0x00, 0x2a, 0x13, 0xc6, 0xad,
+  0x18, 0xaa, 0x61, 0x84, 0x34, 0x28, 0x94, 0xd0, 0xda, 0xd2, 0xdb, 0xc7,
+  0xcc, 0x59, 0x72, 0x18, 0x30, 0x68, 0xca, 0x12, 0x8d, 0x5b, 0x83, 0xe6,
+  0xe8, 0xc0, 0xca, 0x64, 0x08, 0x2d, 0x15, 0xb6, 0xee, 0xe3, 0xb8, 0x20,
+  0xcd, 0xa1, 0x98, 0xb5, 0x03, 0x69, 0x34, 0x35, 0xb1, 0x3f, 0x26, 0xe4,
+  0xa5, 0x85, 0x5b, 0x28, 0x0d, 0x58, 0x60, 0x73, 0x76, 0x6a, 0x9b, 0x69,
+  0x09, 0xb9, 0x12, 0x63, 0x9d, 0x10, 0x87, 0x4e, 0xf5, 0x6d, 0x99, 0x27,
+  0xb3, 0xf2, 0xa3, 0x73, 0xe2, 0xe4, 0xcd, 0x84, 0x35, 0x91, 0x91, 0xf1,
+  0x83, 0x9b, 0xba, 0x47, 0xce, 0x31, 0xfe, 0x74, 0x74, 0x4b, 0xb2, 0x25,
+  0x38, 0x71, 0xea, 0xdc, 0xc5, 0xb3, 0xdc, 0x0c, 0x41, 0xf4, 0x3a, 0x48,
+  0x54, 0x3e, 0x9e, 0x36, 0xd6, 0xe9, 0x5a, 0x6c, 0x75, 0x50, 0x95, 0x83,
+  0x7d, 0x5b, 0x6f, 0xde, 0x9b, 0x1c, 0x20, 0x56, 0x40, 0x1e, 0x3d, 0xf8,
+  0xff, 0xcb, 0xa1, 0xde, 0x2a, 0xd9, 0xe4, 0x36, 0x65, 0x2f, 0xc2, 0xb7,
+  0x87, 0x03, 0x8c, 0x00, 0x18, 0x37, 0x85, 0xe2, 0xbc, 0xfa, 0xe9, 0xcf,
+  0xe3, 0x81, 0x98, 0x6d, 0x43, 0x31, 0x10, 0x79, 0x0d, 0xbe, 0x89, 0xf7,
+  0xf9, 0x23, 0x7b, 0x91, 0xb1, 0xef, 0xe6, 0x3e, 0x17, 0x45, 0x73, 0x9b,
+  0x09, 0xb2, 0x51, 0xd4, 0x61, 0x2d, 0xbc, 0x3f, 0xc7, 0x52, 0x2e, 0xee,
+  0x8f, 0xba, 0x56, 0x64, 0x91, 0x0a, 0x38, 0x07, 0xb6, 0xd5, 0x6d, 0xcf,
+  0x33, 0xe7, 0xdb, 0xdb, 0x65, 0x43, 0xae, 0x65, 0x0e, 0xdb, 0x6c, 0xa9,
+  0x4e, 0xd3, 0x8a, 0x28, 0x63, 0x73, 0x5a, 0x4e, 0x29, 0x42, 0x56, 0x36,
+  0x4d, 0xfb, 0xa0, 0x06, 0x3e, 0xd0, 0x8d, 0xf5, 0x76, 0xa7, 0x32, 0x95,
+  0x09, 0xd5, 0xee, 0xdc, 0x57, 0x80, 0xac, 0x34, 0x63, 0x0f, 0xf8, 0x03,
+  0x51, 0x1f, 0x3d, 0x3b, 0x9e, 0x74, 0x53, 0xec, 0x0f, 0x9c, 0x08, 0xde,
+  0x03, 0xc9, 0xf6, 0x16, 0xb1, 0x54, 0xa4, 0x3c, 0x39, 0x8e, 0x7c, 0x8a,
+  0x00, 0x45, 0xef, 0x1e, 0x47, 0xe2, 0xf1, 0x88, 0xee, 0x2e, 0x51, 0x77,
+  0x9f, 0x2c, 0x7e, 0x97, 0xb5, 0x35, 0x24, 0xb4, 0x60, 0xc5, 0x6f, 0x25,
+  0x9c, 0x5f, 0x62, 0x2f, 0xdf, 0xab, 0xe7, 0x64, 0x01, 0x26, 0x3c, 0x8d,
+  0x97, 0x5e, 0xe9, 0x56, 0xd3, 0x4c, 0xe4, 0xac, 0xa8, 0x3a, 0xdc, 0x56,
+  0x29, 0x65, 0x94, 0x34, 0x6c, 0x3d, 0xaa, 0x94, 0xdf, 0xb3, 0x13, 0xf0,
+  0x23, 0x3e, 0xb7, 0x9e, 0x33, 0xb7, 0x6a, 0x21, 0xaf, 0x14, 0xf7, 0x6f,
+  0x96, 0x18, 0xa7, 0x4b, 0x12, 0x01, 0x03, 0xaa, 0x36, 0x7f, 0xe8, 0x91,
+  0x0e, 0x11, 0x5c, 0x25, 0xfc, 0xb8, 0xeb, 0xc3, 0xf8, 0xce, 0xde, 0xee,
+  0x0a, 0xfc, 0xc3, 0xe5, 0x19, 0xad, 0xf1, 0x8e, 0x30, 0x02, 0xde, 0x05,
+  0x23, 0x8c, 0x81, 0x9b, 0x20, 0xc2, 0xbf, 0x43, 0xfc, 0x1b, 0xe9, 0x7f,
+  0x04, 0x57, 0x80, 0x3d, 0xeb, 0x81, 0x73, 0x45, 0x67, 0xea, 0x3a, 0x75,
+  0xbd, 0xcd, 0xcc, 0x85, 0x50, 0x31, 0xe5, 0x4b, 0x95, 0x8e, 0xec, 0xc4,
+  0x92, 0x40, 0x9b, 0x16, 0xb6, 0x74, 0x07, 0xed, 0xf4, 0x72, 0x3c, 0x50,
+  0xa5, 0xdb, 0x69, 0x5f, 0x9d, 0x97, 0x23, 0xf5, 0xcb, 0x16, 0x7e, 0xcb,
+  0xa8, 0x71, 0xcc, 0xa0, 0x0b, 0x7e, 0x1f, 0x2f, 0x4f, 0x8f, 0x83, 0xf2,
+  0xe3, 0xdd, 0xae, 0xcd, 0x94, 0xaa, 0x36, 0x0c, 0xb0, 0x7a, 0x37, 0x50,
+  0x8b, 0x9d, 0x00, 0x31, 0xea, 0x91, 0xb4, 0x5c, 0x95, 0x30, 0x3b, 0x3e,
+  0x9f, 0x57, 0xbb, 0x98, 0x5a, 0x2f, 0x95, 0x87, 0xa8, 0x4a, 0x58, 0x8d,
+  0xe5, 0x00, 0x1a, 0x11, 0xbd, 0xb0, 0x57, 0x5c, 0x4c, 0xeb, 0x21, 0x77,
+  0xcb, 0x80, 0xc8, 0x34, 0xb4, 0x1b, 0x5b, 0x91, 0xf5, 0x65, 0x52, 0x15,
+  0x29, 0x9d, 0xa5, 0xd6, 0xfe, 0xac, 0x47, 0x12, 0x08, 0x5f, 0xdc, 0xf3,
+  0x7c, 0x8a, 0xa9, 0xbc, 0x75, 0xb6, 0xa5, 0x8b, 0x68, 0xd0, 0xd4, 0x6e,
+  0x37, 0xb7, 0x02, 0x38, 0xe8, 0xcd, 0x74, 0x44, 0x9e, 0x5b, 0x14, 0xf8,
+  0xad, 0xe8, 0xc0, 0x15, 0x09, 0xe4, 0x00, 0xac, 0x56, 0x11, 0xc8, 0x95,
+  0xe7, 0x4a, 0x01, 0x63, 0x89, 0xcf, 0x7e, 0xb8, 0x11, 0x00, 0x10, 0x6c,
+  0x3c, 0xcc, 0x2f, 0xd5, 0xbd, 0x00, 0x01, 0x8f, 0xb7, 0x5e, 0xe2, 0xdd,
+  0xd0, 0x93, 0x76, 0xc0, 0x09, 0x97, 0x9e, 0x39, 0xf2, 0x7a, 0x96, 0xe0,
+  0x20, 0x30, 0x31, 0xb9, 0xc5, 0x87, 0x49, 0x2c, 0x09, 0x09, 0x8d, 0x3c,
+  0x93, 0x12, 0x84, 0xb7, 0xf2, 0x0f, 0x79, 0x3e, 0xb7, 0xe3, 0x1d, 0x64,
+  0x0d, 0xd5, 0x32, 0xf8, 0x58, 0xde, 0x97, 0xb1, 0x64, 0x07, 0x5a, 0xe9,
+  0x98, 0x12, 0x61, 0xb6, 0xd3, 0xdb, 0xea, 0xa0, 0x05, 0xe2, 0x63, 0xb3,
+  0xbb, 0xe7, 0x12, 0x19, 0x9a, 0xec, 0xc7, 0xe8, 0x18, 0x94, 0xfb, 0xe4,
+  0xe9, 0x4e, 0xba, 0x91, 0x42, 0x1b, 0xe0, 0xc2, 0x83, 0xa6, 0x6a, 0xe0,
+  0xfc, 0x0e, 0xdf, 0xd5, 0x3d, 0xbb, 0x37, 0xf2, 0x5e, 0x2b, 0x1b, 0x92,
+  0x6b, 0x00, 0x00, 0x00, 0x01, 0x0f, 0x43, 0xfd, 0x0a, 0x00, 0xf4, 0x58,
+  0xaf, 0xbf, 0xbf, 0x02, 0x2d, 0x72, 0xa2, 0x9b, 0x98, 0xeb, 0x6b, 0xe4,
+  0xc3, 0x96, 0xc9, 0x0b, 0x46, 0xf4, 0x06, 0xf1, 0xd7, 0x0b, 0xa5, 0x14,
+  0x5c, 0xcb, 0xb2, 0x19, 0x4e, 0xa7, 0x97, 0x5b, 0x9b, 0xc3, 0x80, 0x0f,
+  0x9f, 0xab, 0x9a, 0xa3, 0x1d, 0xa9, 0x53, 0x2d, 0xc4, 0x52, 0xea, 0x14,
+  0xa3, 0x56, 0x37, 0x20, 0x52, 0xe7, 0x31, 0xcf, 0xd3, 0x51, 0x03, 0xf7,
+  0xbe, 0x13, 0x2e, 0xd0, 0xc2, 0xc7, 0x51, 0xed, 0xf2, 0x99, 0x52, 0xac,
+  0xf0, 0x2d, 0xb8, 0x60, 0xfb, 0x5b, 0xf5, 0x02, 0xaa, 0x6f, 0x36, 0x65,
+  0x88, 0x50, 0x74, 0x42, 0x86, 0x9c, 0x1a, 0x81, 0xad, 0xe4, 0x00, 0x1e,
+  0x4e, 0xfe, 0x3e, 0xf9, 0x32, 0x45, 0x29, 0x03, 0xae, 0xf9, 0x5d, 0x96,
+  0x18, 0x58, 0xf8, 0xbe, 0x0d, 0xe1, 0xc0, 0x17, 0x6f, 0x04, 0x6e, 0x78,
+  0x32, 0xe5, 0x5b, 0x53, 0x74, 0x53, 0xcb, 0xc9, 0xa1, 0xf4, 0x39, 0xf2,
+  0x17, 0x6c, 0x6d, 0x9f, 0x02, 0xbb, 0xcf, 0xa7, 0xd6, 0xc1, 0x7c, 0x82,
+  0x30, 0x02, 0x55, 0x0f, 0x0e, 0x85, 0x00, 0x90, 0xe5, 0xb6, 0x2f, 0x83,
+  0x67, 0x31, 0x66, 0x92, 0x55, 0xb9, 0xb0, 0x3a, 0x2b, 0x7f, 0x41, 0xff,
+  0x40, 0x03, 0xfe, 0x85, 0xf0, 0xf3, 0x28, 0x23, 0xff, 0xef, 0x0f, 0x0f,
+  0xd3, 0x62, 0x8f, 0xa1, 0xa5, 0xb0, 0x14, 0xb8, 0x2a, 0x71, 0xc8, 0x98,
+  0x01, 0x2e, 0x6c, 0xd5, 0x74, 0xe3, 0x30, 0xaf, 0x5b, 0x4e, 0x0d, 0x46,
+  0xe3, 0xf1, 0x7b, 0xff, 0xd2, 0x29, 0xb5, 0xd0, 0xb3, 0x37, 0xc9, 0xdb,
+  0xbc, 0xee, 0x39, 0xe5, 0xee, 0x01, 0x8b, 0x61, 0x34, 0x29, 0xbd, 0x0f,
+  0xdf, 0xbd, 0xd8, 0xb8, 0xea, 0x1d, 0x9f, 0x8c, 0xf3, 0xde, 0x7c, 0xa9,
+  0xa7, 0x87, 0x45, 0x2c, 0xc3, 0x94, 0x63, 0x6a, 0x64, 0xd5, 0xa8, 0xda,
+  0xa4, 0xdc, 0x02, 0xdb, 0xe3, 0xf5, 0xf0, 0xe0, 0x04, 0x80, 0x06, 0xaf,
+  0xaf, 0x50, 0x26, 0xf1, 0xbc, 0x4a, 0xe5, 0x85, 0x93, 0x6d, 0x54, 0x50,
+  0xb6, 0xfc, 0xff, 0xf5, 0xcc, 0xcb, 0x0c, 0x37, 0xc6, 0x4a, 0xdf, 0xa5,
+  0x48, 0xb9, 0xc5, 0x22, 0x7c, 0xf7, 0x95, 0x16, 0xc9, 0xb3, 0x31, 0x0d,
+  0xb4, 0xf3, 0xec, 0xb1, 0x56, 0x24, 0x29, 0x5b, 0xe4, 0x80, 0x0d, 0xfe,
+  0x01, 0x04, 0x06, 0x7f, 0xb3, 0x39, 0x15, 0xc8, 0xc0, 0xe2, 0x0b, 0x97,
+  0xcc, 0xb0, 0x20, 0x29, 0xb0, 0x32, 0x66, 0x3b, 0x25, 0x0a, 0x7b, 0x64,
+  0xf9, 0xe5, 0x24, 0x4f, 0x16, 0xfc, 0x30, 0xbd, 0xc0, 0x07, 0x9f, 0xfd,
+  0xe7, 0x3c, 0xd4, 0x6a, 0x49, 0x64, 0x32, 0x37, 0x91, 0x22, 0xf7, 0xc1,
+  0x17, 0x34, 0x40, 0x8e, 0xea, 0x17, 0x25, 0xe7, 0x16, 0xf3, 0xd6, 0x6c,
+  0x35, 0x3c, 0xae, 0x1e, 0xb0, 0xa3, 0x9b, 0xe9, 0xc0, 0x05, 0x70, 0x57,
+  0x0f, 0xdf, 0x8f, 0xe4, 0x01, 0xe6, 0x87, 0x1a, 0x5d, 0x94, 0xc9, 0xbe,
+  0x5b, 0x96, 0x5b, 0x2c, 0x6f, 0x94, 0x49, 0xf8, 0xf8, 0x9a, 0xa1, 0x73,
+  0x9c, 0x36, 0xda, 0x1a, 0x5c, 0x25, 0x37, 0x6e, 0x5a, 0x9f, 0x9a, 0x15,
+  0x56, 0x94, 0xcc, 0xfb, 0x1b, 0x0e, 0x96, 0x00, 0x5b, 0x4d, 0xc0, 0x15,
+  0xaa, 0x43, 0xc3, 0x21, 0xed, 0x88, 0xae, 0x05, 0x77, 0x00, 0x06, 0x7a,
+  0xaa, 0x48, 0x46, 0xfa, 0xaf, 0xbd, 0xd9, 0xfc, 0x12, 0x46, 0xd3, 0x34,
+  0x30, 0x0c, 0xf9, 0xfb, 0x66, 0xc0, 0xf3, 0xa6, 0x48, 0x6c, 0x94, 0xa3,
+  0xea, 0x37, 0xcd, 0x36, 0xf9, 0xbf, 0x05, 0xe5, 0x08, 0x84, 0x02, 0xb5,
+  0xb4, 0x96, 0xdc, 0xc8, 0xbe, 0x87, 0x10, 0xd9, 0xc3, 0x9b, 0xfa, 0x6f,
+  0xc0, 0xbf, 0x70, 0x02, 0x3f, 0x69, 0xbd, 0x08, 0xed, 0x41, 0x10, 0x01,
+  0x30, 0x51, 0xaa, 0x80, 0x91, 0xff, 0x92, 0xfe, 0xe0, 0xe5, 0xaa, 0xdb,
+  0x3f, 0xff, 0x34, 0x01, 0xf6, 0x91, 0x08, 0xc2, 0x62, 0x9f, 0x69, 0xbc,
+  0x71, 0xbf, 0x9d, 0x26, 0xd2, 0xad, 0x85, 0x41, 0xad, 0xe4, 0x3b, 0xf8,
+  0x04, 0x1f, 0xd9, 0x00, 0x12, 0x00, 0x5b, 0x68, 0x64, 0x36, 0x3c, 0xca,
+  0x38, 0x3f, 0xc8, 0xe4, 0xa5, 0xf8, 0x37, 0xe8, 0x2f, 0x91, 0x3b, 0xcf,
+  0xb8, 0xb8, 0x06, 0x60, 0xc7, 0x5e, 0xdd, 0xa8, 0x93, 0x53, 0x15, 0x23,
+  0xee, 0x20, 0xc2, 0x1b, 0x79, 0xef, 0x90, 0x52, 0x5d, 0xa0, 0x03, 0x46,
+  0xca, 0x95, 0x16, 0x7a, 0xb7, 0xf1, 0x30, 0x07, 0x74, 0x10, 0x40, 0x5c,
+  0x4f, 0xf7, 0xda, 0x20, 0xf5, 0xcf, 0x7e, 0x9c, 0x1f, 0x6c, 0x2a, 0x9b,
+  0x62, 0xac, 0x92, 0xa0, 0xc1, 0xed, 0xf2, 0x8e, 0x13, 0x8b, 0xb7, 0x6f,
+  0x81, 0x8b, 0x3c, 0x5b, 0xf4, 0xf9, 0x10, 0x48, 0x20, 0x80, 0xe7, 0xd3,
+  0x3e, 0x5d, 0x9c, 0xe9, 0x76, 0xde, 0x36, 0xbf, 0x4d, 0xab, 0x7c, 0xe9,
+  0x4b, 0x9a, 0x7a, 0xa5, 0x3d, 0x5b, 0xf3, 0x5f, 0xcc, 0x20, 0x76, 0xf7,
+  0x49, 0x7c, 0x26, 0x6d, 0x1f, 0x06, 0x6b, 0x75, 0x17, 0xde, 0x9b, 0xe8,
+  0x3e, 0x05, 0xb6, 0xaa, 0xa7, 0xb7, 0xc4, 0xe3, 0x83, 0x76, 0x65, 0x40,
+  0x08, 0xee, 0x2b, 0x7b, 0xf8, 0x08, 0x40, 0x15, 0xa2, 0xce, 0x90, 0xf0,
+  0x43, 0x00, 0x68, 0x14, 0x79, 0x3e, 0x58, 0x49, 0x6f, 0x17, 0x26, 0xf9,
+  0xe1, 0x6a, 0x3b, 0xf3, 0x6b, 0xac, 0xf0, 0xa0, 0x6d, 0xbd, 0xc6, 0x4b,
+  0xd0, 0x81, 0x32, 0x5a, 0x11, 0x1d, 0xc6, 0x85, 0x02, 0x27, 0xfd, 0x6a,
+  0xfa, 0x48, 0xde, 0xb5, 0x0f, 0x6f, 0x41, 0x49, 0xe0, 0x73, 0x74, 0x71,
+  0x9c, 0xce, 0xdd, 0xf8, 0xa1, 0x7e, 0xdb, 0xef, 0xc8, 0x4d, 0x59, 0xb3,
+  0x56, 0xc1, 0xc9, 0x2c, 0xad, 0x81, 0xe6, 0x68, 0xbf, 0x7f, 0x6d, 0x81,
+  0x59, 0xf3, 0x5d, 0xbc, 0x51, 0xc1, 0xc6, 0x58, 0x78, 0x49, 0x4c, 0xfd,
+  0x3a, 0xd1, 0x5c, 0x77, 0x65, 0x83, 0x03, 0xbf, 0x92, 0xcd, 0xb0, 0xf3,
+  0xf7, 0x39, 0x59, 0x00, 0x46, 0x5a, 0xb6, 0xbd, 0xc7, 0x89, 0xeb, 0xef,
+  0xca, 0xe5, 0x5a, 0x56, 0xe0, 0x87, 0x88, 0xc7, 0xe4, 0x3c, 0x02, 0x57,
+  0x6e, 0xfa, 0x16, 0xda, 0xb7, 0x54, 0x6f, 0x9b, 0x43, 0xde, 0x2a, 0xf8,
+  0xc3, 0x62, 0x14, 0x12, 0x91, 0xbd, 0x35, 0xda, 0x44, 0x30, 0xcd, 0xf4,
+  0xd7, 0xd2, 0xbd, 0x2a, 0x92, 0xdb, 0x83, 0xdc, 0xb9, 0x5d, 0x73, 0x9a,
+  0x3e, 0x58, 0xf7, 0xdd, 0x88, 0x4c, 0x38, 0xb1, 0x81, 0x55, 0xba, 0x76,
+  0x00, 0x1b, 0x07, 0x27, 0x8e, 0xf9, 0xd4, 0x1a, 0x73, 0x65, 0x5b, 0xa0,
+  0xf5, 0x6f, 0x90, 0x58, 0xa3, 0x0b, 0xf5, 0x83, 0x82, 0xd4, 0x84, 0xc7,
+  0x7f, 0x39, 0x0b, 0xf5, 0x80, 0x7c, 0x6b, 0xea, 0x67, 0x56, 0xcb, 0x68,
+  0x61, 0xb8, 0x97, 0x4a, 0x1c, 0xa3, 0xce, 0x68, 0xf7, 0x57, 0xd8, 0xf8,
+  0x81, 0xa9, 0x9a, 0x51, 0x0d, 0x19, 0x1c, 0xc1, 0xe8, 0xde, 0x19, 0x08,
+  0x19, 0x14, 0xb0, 0x98, 0x9b, 0xe8, 0x39, 0xb9, 0xcf, 0x2b, 0x70, 0x95,
+  0x28, 0xc0, 0xa0, 0xd6, 0xed, 0x2b, 0xde, 0xf9, 0x66, 0x21, 0xe0, 0x88,
+  0x00, 0x95, 0x54, 0x2a, 0x61, 0xed, 0xc0, 0x2b, 0x08, 0x13, 0x3d, 0x75,
+  0x2c, 0x24, 0xc6, 0x9a, 0xca, 0x14, 0x07, 0x37, 0xf6, 0x90, 0x02, 0x5f,
+  0x20, 0x02, 0xd0, 0x06, 0xd3, 0xd9, 0xdb, 0x68, 0x0f, 0x7b, 0x27, 0xf0,
+  0xfc, 0xe2, 0x4a, 0xb7, 0xf7, 0x76, 0x67, 0x85, 0xb1, 0xbd, 0x4f, 0x6f,
+  0xd0, 0x40, 0x03, 0x9e, 0x78, 0x9b, 0xba, 0xa3, 0x41, 0x0b, 0xfd, 0x67,
+  0x3a, 0x78, 0x4e, 0x6c, 0x5b, 0x7c, 0x63, 0x7d, 0x7b, 0xeb, 0x01, 0x07,
+  0xf9, 0x7f, 0xff, 0x57, 0xeb, 0xac, 0x02, 0x7c, 0xec, 0xde, 0x1f, 0x83,
+  0x0e, 0x5c, 0xd9, 0x24, 0x81, 0x8d, 0xf3, 0x90, 0x02, 0x3f, 0xf0, 0x81,
+  0x00, 0x0d, 0xb3, 0xe3, 0xec, 0xfe, 0x51, 0x4c, 0x7f, 0x3d, 0x75, 0x90,
+  0x9f, 0xce, 0xca, 0x86, 0x9b, 0x69, 0x85, 0xaa, 0x54, 0x34, 0x73, 0x46,
+  0xda, 0xba, 0x57, 0x81, 0x88, 0xde, 0x5e, 0xae, 0x2a, 0x92, 0x9b, 0xf8,
+  0x90, 0x02, 0x12, 0x33, 0xc0, 0x1d, 0x80, 0x36, 0x7c, 0x17, 0x2c, 0x1b,
+  0x25, 0xeb, 0x9b, 0x24, 0xfd, 0xc2, 0xb4, 0x6c, 0xc1, 0xcd, 0xc9, 0xfa,
+  0xf5, 0xbf, 0x04, 0x5e, 0x05, 0xf5, 0xcc, 0x3a, 0xa6, 0xe4, 0x78, 0x75,
+  0x18, 0x3e, 0x58, 0xdf, 0xba, 0x3e, 0x5f, 0x48, 0xbf, 0x7f, 0x71, 0x7d,
+  0xdd, 0x1b, 0x4b, 0xe7, 0x9b, 0xa6, 0x0c, 0xfd, 0x69, 0xd2, 0x05, 0x37,
+  0xe6, 0xbf, 0xee, 0x02, 0x08, 0x16, 0x0b, 0xff, 0x74, 0x81, 0x5b, 0xc0,
+  0xa3, 0x2f, 0x86, 0xdb, 0x6c, 0x21, 0xd6, 0xe7, 0xa8, 0xed, 0xb0, 0x96,
+  0x3d, 0xb0, 0xdf, 0xc5, 0xad, 0xfc, 0x61, 0xe0, 0x63, 0x32, 0x90, 0xed,
+  0x6d, 0x7e, 0xdb, 0xa0, 0x0c, 0x1d, 0xf7, 0x16, 0xb2, 0x06, 0x4f, 0xe8,
+  0x92, 0xb2, 0xd0, 0xc2, 0x07, 0x19, 0x8b, 0xeb, 0x5b, 0xec, 0x80, 0x0b,
+  0x5d, 0xef, 0xcf, 0xd8, 0x01, 0xcd, 0x17, 0x2a, 0x93, 0x60, 0x87, 0x11,
+  0xcc, 0xe9, 0xd6, 0xa7, 0xe2, 0xcd, 0x7f, 0x12, 0x52, 0x86, 0x8c, 0xd6,
+  0xf1, 0x20, 0x05, 0xa2, 0x27, 0xb8, 0x02, 0xa1, 0x64, 0x1d, 0xd3, 0x83,
+  0x93, 0xe0, 0x5e, 0xe5, 0xca, 0x34, 0x3b, 0x69, 0x25, 0x2b, 0x67, 0x3f,
+  0x25, 0x4f, 0x11, 0xed, 0x16, 0x0d, 0x24, 0x37, 0xf1, 0x28, 0x08, 0x5f,
+  0xef, 0x38, 0x8b, 0xe3, 0x2d, 0xa4, 0xa8, 0xdd, 0xdf, 0x28, 0x00, 0xee,
+  0x8a, 0xc0, 0x4c, 0x00, 0x3a, 0xa9, 0xea, 0xdc, 0xfe, 0xf1, 0xf4, 0x5e,
+  0x72, 0xe7, 0xca, 0x36, 0x57, 0x2e, 0x6c, 0xb0, 0x22, 0x95, 0x5b, 0xed,
+  0x40, 0x04, 0xa2, 0xa8, 0x01, 0x79, 0x1b, 0x31, 0xcf, 0x01, 0x13, 0xec,
+  0x48, 0xa3, 0x29, 0x6a, 0x32, 0xb6, 0x8e, 0xa4, 0x0d, 0x7d, 0x21, 0x58,
+  0xca, 0x94, 0x5b, 0x7b, 0xf9, 0x76, 0xfb, 0xc0, 0x06, 0x25, 0x06, 0x5b,
+  0x3e, 0x84, 0xe9, 0xc4, 0x18, 0x4d, 0x59, 0xab, 0x42, 0x92, 0x37, 0x80,
+  0x00, 0x77, 0xf0, 0x2f, 0x3d, 0xc5, 0xf5, 0xc3, 0xf8, 0xd8, 0xb2, 0xe4,
+  0x7b, 0xf2, 0x6a, 0x51, 0x95, 0x06, 0x5f, 0x16, 0xfa, 0xc7, 0xd3, 0xbd,
+  0xe0, 0x8b, 0xec, 0x27, 0xe6, 0x0e, 0x0e, 0xb9, 0xde, 0x57, 0x39, 0x69,
+  0x51, 0x2d, 0xa5, 0x14, 0xd8, 0xa5, 0xc0, 0x06, 0x40, 0x0f, 0x1f, 0xf1,
+  0x40, 0x2c, 0xc2, 0xd3, 0x2b, 0xb8, 0x7a, 0xe7, 0x9d, 0xbe, 0x7a, 0x36,
+  0x16, 0x43, 0xad, 0xe3, 0xf5, 0x7c, 0xf5, 0x66, 0xc0, 0xca, 0xb9, 0x02,
+  0xdb, 0x29, 0x4e, 0x46, 0xfe, 0x72, 0xe7, 0x4d, 0x00, 0xb3, 0x2c, 0xf0,
+  0xef, 0x61, 0xa0, 0x97, 0xff, 0xb6, 0x2a, 0x05, 0xb7, 0xea, 0x88, 0x21,
+  0xd8, 0x2b, 0xdb, 0x9e, 0x08, 0x0a, 0x02, 0x5d, 0xe6, 0xb8, 0xf9, 0x0a,
+  0xa5, 0x0c, 0x2c, 0x7b, 0x7e, 0x5a, 0x9a, 0x01, 0x5c, 0xe2, 0x60, 0x04,
+  0x22, 0xf7, 0x24, 0x21, 0xa4, 0x6f, 0xd3, 0xe0, 0x0f, 0x81, 0x0b, 0xfd,
+  0x33, 0x9b, 0x6b, 0xc6, 0xc4, 0x90, 0x99, 0x92, 0x87, 0x86, 0x5b, 0xb5,
+  0x59, 0x65, 0x20, 0x13, 0xac, 0xb0, 0x34, 0x3c, 0xf9, 0x5a, 0xf2, 0xcd,
+  0x4a, 0xad, 0xf4, 0x12, 0x7c, 0x11, 0x7b, 0xcb, 0x8e, 0xb2, 0x9a, 0xeb,
+  0x21, 0xa9, 0x12, 0x87, 0xe2, 0xee, 0xcb, 0x55, 0x15, 0x46, 0xb7, 0xe6,
+  0x71, 0x1e, 0xcf, 0xf8, 0x00, 0x71, 0xd7, 0xb6, 0x3d, 0x60, 0xd0, 0x42,
+  0x00, 0x69, 0x69, 0x48, 0x51, 0x61, 0xf6, 0xac, 0x85, 0x1e, 0x5b, 0x7d,
+  0xcf, 0xe4, 0x89, 0xc0, 0x03, 0x0e, 0xe3, 0x9f, 0xb2, 0x29, 0xab, 0xc0,
+  0x01, 0xec, 0x27, 0xe6, 0xeb, 0xcf, 0x44, 0xb0, 0xb8, 0x91, 0x1b, 0xd7,
+  0xfd, 0xfd, 0xde, 0x00, 0xdf, 0xe6, 0x13, 0xd7, 0xf5, 0x09, 0xde, 0x46,
+  0xd3, 0x2d, 0x2f, 0x7f, 0x6a, 0x64, 0x50, 0xe3, 0x8b, 0x6e, 0x9b, 0x2f,
+  0x2f, 0xc3, 0x28, 0x00, 0xd0, 0xf5, 0x6e, 0x8a, 0x54, 0x95, 0x58, 0x00,
+  0x00, 0x01, 0xb7
+};
+
+void
+mpeg2_get_video_info (VideoDecodeInfo * info)
+{
+  info->profile = GST_VAAPI_PROFILE_MPEG2_SIMPLE;
+  info->width = MPEG2_CLIP_WIDTH;
+  info->height = MPEG2_CLIP_HEIGHT;
+  info->data = mpeg2_clip;
+  info->data_size = MPEG2_CLIP_DATA_SIZE;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-mpeg2.h b/subprojects/gstreamer-vaapi/tests/internal/test-mpeg2.h
new file mode 100644 (file)
index 0000000..ba21d0f
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  test-mpeg2.h - MPEG-2 test data
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_MPEG2_H
+#define TEST_MPEG2_H
+
+#include <glib.h>
+#include "test-decode.h"
+
+void mpeg2_get_video_info(VideoDecodeInfo *info);
+
+#endif /* TEST_MPEG2_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-mpeg4.c b/subprojects/gstreamer-vaapi/tests/internal/test-mpeg4.c
new file mode 100644 (file)
index 0000000..270359b
--- /dev/null
@@ -0,0 +1,1674 @@
+/*
+ *  test-mpeg4.c - MPEG-4 test data
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "test-mpeg4.h"
+
+#define MPEG4_CLIP_WIDTH          320
+#define MPEG4_CLIP_HEIGHT         240
+#define MPEG4_CLIP_DATA_SIZE    19592
+
+/* Data dump of a 320x240 MPEG-4 video clip (mpeg4.m4v), it has a single frame */
+static const guchar mpeg4_clip[MPEG4_CLIP_DATA_SIZE] = {
+  0x00, 0x00, 0x01, 0xb0, 0x01, 0x00, 0x00, 0x01, 0xb5, 0x89, 0x13, 0x00,
+  0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x20, 0x00, 0xc4, 0x8d, 0x88, 0x00,
+  0xcd, 0x0a, 0x04, 0x1e, 0x14, 0x43, 0x00, 0x00, 0x01, 0xb2, 0x4c, 0x61,
+  0x76, 0x63, 0x35, 0x34, 0x2e, 0x36, 0x32, 0x2e, 0x31, 0x30, 0x30, 0x00,
+  0x00, 0x01, 0xb3, 0x00, 0x10, 0x07, 0x00, 0x00, 0x01, 0xb6, 0x10, 0x60,
+  0x85, 0x85, 0x41, 0x08, 0x78, 0xab, 0x44, 0x81, 0x29, 0x06, 0xd1, 0xd2,
+  0x4d, 0xe9, 0x2d, 0x55, 0xe0, 0x95, 0x36, 0x42, 0x10, 0x71, 0xfc, 0xa0,
+  0x4f, 0x8b, 0x9a, 0x0a, 0xd8, 0x84, 0xca, 0x81, 0x18, 0x48, 0x80, 0xf0,
+  0xd0, 0x0b, 0x97, 0x12, 0x83, 0x01, 0x47, 0x13, 0x97, 0x59, 0xfe, 0x22,
+  0x5b, 0x9d, 0x88, 0xfb, 0x38, 0x46, 0x2e, 0x29, 0x11, 0x39, 0xb3, 0x7a,
+  0x08, 0x02, 0x5f, 0x16, 0xf6, 0x52, 0x8d, 0x3e, 0x33, 0x2f, 0x12, 0x04,
+  0xb5, 0x5d, 0xa0, 0x88, 0xcd, 0xe2, 0xeb, 0x7a, 0xd9, 0xc0, 0x61, 0x30,
+  0xbd, 0x4e, 0xce, 0x8a, 0xb8, 0xe6, 0xbf, 0x14, 0x43, 0xed, 0x8d, 0xd8,
+  0x4d, 0x74, 0x47, 0x69, 0x5b, 0x23, 0x9c, 0xb5, 0xad, 0x82, 0x06, 0xfb,
+  0xfe, 0x9d, 0xec, 0x5d, 0x70, 0x49, 0x0b, 0xca, 0x95, 0x5f, 0xb3, 0xec,
+  0x0e, 0x6c, 0x0c, 0xdc, 0x68, 0x7b, 0xfc, 0x0f, 0xad, 0xbe, 0xcd, 0xd2,
+  0x58, 0xbf, 0x38, 0x4e, 0x30, 0x2e, 0x49, 0x7c, 0x95, 0x52, 0xb9, 0x3a,
+  0xc2, 0xfa, 0x69, 0x46, 0xf1, 0x14, 0x0e, 0x48, 0xd3, 0xa5, 0xa0, 0xc2,
+  0x6f, 0x29, 0x19, 0x61, 0x21, 0xaf, 0x0e, 0x32, 0x79, 0x06, 0x49, 0x06,
+  0x10, 0xf1, 0xb1, 0xef, 0x51, 0xf3, 0xa7, 0x14, 0x0f, 0xf2, 0x90, 0xaa,
+  0x3d, 0xde, 0xcb, 0x20, 0x71, 0xd1, 0x35, 0x30, 0x86, 0xc3, 0x21, 0x7f,
+  0xff, 0x70, 0xd2, 0xf4, 0x96, 0xac, 0xb1, 0x19, 0xff, 0x5f, 0xfe, 0xf3,
+  0x0a, 0xc3, 0x94, 0x0b, 0x10, 0xe6, 0xe7, 0x55, 0x54, 0x36, 0x6d, 0x2a,
+  0x35, 0x2d, 0x27, 0xa9, 0xd9, 0xb3, 0x7c, 0x37, 0x71, 0x85, 0x96, 0x2c,
+  0x2e, 0xdc, 0x6a, 0xd9, 0x9c, 0x51, 0xfe, 0x4a, 0x8a, 0xd2, 0x90, 0x13,
+  0x02, 0x19, 0x72, 0x86, 0x33, 0xf9, 0x11, 0x0c, 0x77, 0x2f, 0x57, 0x79,
+  0xc6, 0x9b, 0x2b, 0x8a, 0x79, 0x36, 0xf0, 0xa9, 0x15, 0xa4, 0xae, 0x11,
+  0x0e, 0x73, 0xe5, 0xca, 0x35, 0x74, 0x03, 0x2a, 0x41, 0x9b, 0xab, 0x53,
+  0xe5, 0x9e, 0x11, 0x8b, 0x69, 0x7b, 0x45, 0x9a, 0xa2, 0x94, 0xf2, 0x14,
+  0x50, 0x5b, 0x0a, 0x1b, 0x4a, 0x9e, 0xdd, 0x6b, 0x53, 0x52, 0xcf, 0x23,
+  0x57, 0x37, 0xca, 0x0d, 0x2c, 0x0b, 0x50, 0xc7, 0x60, 0xe3, 0xf6, 0x44,
+  0x1a, 0x1e, 0x0d, 0x4a, 0x79, 0xa9, 0x8c, 0x66, 0xed, 0x2a, 0x6f, 0x23,
+  0x73, 0x39, 0x6d, 0x5e, 0x77, 0xa1, 0xa6, 0x1f, 0xdb, 0xe8, 0x0c, 0x97,
+  0x8b, 0x38, 0xd6, 0xfd, 0x5e, 0x16, 0x7a, 0x67, 0x77, 0xb7, 0xab, 0x0a,
+  0x46, 0xfb, 0xf1, 0x05, 0x62, 0xcd, 0xc2, 0xec, 0x11, 0x14, 0xa8, 0xa2,
+  0x07, 0x39, 0xdb, 0x03, 0x96, 0x74, 0xa8, 0x18, 0x4e, 0x3f, 0x12, 0x53,
+  0xff, 0xff, 0x9e, 0xff, 0xc1, 0x59, 0x9a, 0x1e, 0x68, 0x89, 0xbf, 0x5d,
+  0x7e, 0x08, 0xba, 0xa4, 0x3a, 0xc0, 0x62, 0x0a, 0xd6, 0x94, 0xb5, 0x3d,
+  0x2d, 0x62, 0x4b, 0x3f, 0x57, 0xed, 0x05, 0x7f, 0xfe, 0x1e, 0x29, 0x0d,
+  0x00, 0xa7, 0x4c, 0xe6, 0x16, 0xd7, 0x96, 0x5a, 0x6f, 0xae, 0x35, 0xcc,
+  0xcf, 0x4b, 0xb9, 0x1a, 0x5b, 0xb5, 0x44, 0x0e, 0xcb, 0x20, 0x71, 0x9c,
+  0x50, 0xa4, 0x18, 0x84, 0xaa, 0x0b, 0xea, 0xb5, 0xa3, 0x3e, 0x14, 0x82,
+  0xdd, 0x14, 0x8a, 0x38, 0xb0, 0x7b, 0xf5, 0x11, 0x42, 0x91, 0xbd, 0xec,
+  0x96, 0x9e, 0x68, 0xba, 0xa6, 0xdb, 0xb4, 0xd0, 0xd8, 0xa6, 0x86, 0xea,
+  0x01, 0xf3, 0x7f, 0xfb, 0xd8, 0xf9, 0x68, 0xe5, 0x51, 0xd5, 0x3d, 0xe6,
+  0x62, 0xeb, 0x95, 0x71, 0xd5, 0x69, 0x6a, 0x8d, 0x8b, 0x29, 0x47, 0x10,
+  0xd8, 0x0c, 0x0b, 0xab, 0x68, 0x71, 0xf6, 0xa7, 0x17, 0x9d, 0xa8, 0xca,
+  0xed, 0xe2, 0xcb, 0xbd, 0x3a, 0xb5, 0x86, 0x94, 0x48, 0x50, 0x73, 0xcf,
+  0xb6, 0x70, 0x4b, 0xfe, 0xb4, 0xab, 0x6b, 0x19, 0x9a, 0xda, 0x89, 0x3d,
+  0x9b, 0xd9, 0x2d, 0xb7, 0x8b, 0xd0, 0xd0, 0xf9, 0xa6, 0x81, 0xba, 0x59,
+  0x39, 0x33, 0xb0, 0xa8, 0xb2, 0x95, 0xd9, 0x10, 0x2e, 0x0c, 0x13, 0x48,
+  0xee, 0x96, 0x0e, 0x2d, 0xcb, 0x71, 0x72, 0xb8, 0xba, 0xf5, 0x01, 0xea,
+  0xc6, 0x7a, 0xdc, 0xf7, 0x91, 0xe8, 0xc0, 0x4e, 0x92, 0x75, 0xc2, 0xf9,
+  0x42, 0xc6, 0xd8, 0xf7, 0xea, 0xc1, 0x13, 0x14, 0xdc, 0x94, 0xb6, 0x4d,
+  0x99, 0x9c, 0xbc, 0x2c, 0x5d, 0x71, 0x38, 0xc7, 0xe9, 0x44, 0x05, 0x0d,
+  0x30, 0x1d, 0xad, 0x3a, 0x13, 0x17, 0x65, 0x36, 0xf0, 0xaf, 0x67, 0xed,
+  0x83, 0x6e, 0x2c, 0x50, 0x7d, 0x3c, 0x1f, 0x2a, 0x03, 0x6d, 0x0e, 0x6e,
+  0xe2, 0xea, 0x79, 0x50, 0xea, 0x38, 0xe1, 0x6f, 0x7f, 0xde, 0x9c, 0x32,
+  0x99, 0xb0, 0x9d, 0xb1, 0x73, 0x03, 0xc2, 0xf0, 0xfe, 0x07, 0xaa, 0x64,
+  0xf6, 0x29, 0xd4, 0x59, 0x10, 0xd9, 0x20, 0x8b, 0xaa, 0x6b, 0xc2, 0xfb,
+  0x4d, 0x07, 0x85, 0x9d, 0xee, 0x76, 0xd3, 0x53, 0xb5, 0x15, 0x78, 0x97,
+  0xd7, 0xeb, 0x20, 0xe8, 0x2e, 0x53, 0xcb, 0xc8, 0x74, 0x62, 0xea, 0x9b,
+  0x4e, 0x53, 0xe5, 0x9b, 0xaa, 0x19, 0x2d, 0xcd, 0xf4, 0x2d, 0x6b, 0x6a,
+  0xe6, 0xf8, 0xa6, 0x5b, 0x41, 0x6e, 0x36, 0xd6, 0xcb, 0x3f, 0xdf, 0x87,
+  0x41, 0xd5, 0x43, 0xab, 0xd5, 0xb8, 0x1b, 0x29, 0x3c, 0x7d, 0x2f, 0xef,
+  0x59, 0xbe, 0xe7, 0x4b, 0x7f, 0xce, 0xac, 0x8a, 0xdd, 0x3c, 0x74, 0x42,
+  0x2f, 0x64, 0x47, 0xf3, 0x3a, 0xad, 0x55, 0x85, 0x89, 0x59, 0x6b, 0x25,
+  0x97, 0x30, 0xb3, 0xd5, 0x6a, 0x56, 0x0e, 0x05, 0x48, 0x24, 0x36, 0x79,
+  0x34, 0x43, 0x30, 0xcc, 0x56, 0x9d, 0x6d, 0xbb, 0x33, 0x17, 0xb2, 0x73,
+  0x90, 0x92, 0x43, 0xc2, 0xba, 0x47, 0x98, 0x9d, 0x67, 0x03, 0x47, 0xe2,
+  0xb5, 0xad, 0xb3, 0xe5, 0xdb, 0x62, 0x37, 0xea, 0x6e, 0x45, 0x84, 0xc3,
+  0x05, 0x2b, 0x09, 0xdd, 0x93, 0x38, 0xde, 0xf1, 0xb8, 0x81, 0x15, 0xe8,
+  0x9c, 0xa0, 0x22, 0xa3, 0xef, 0x50, 0xa8, 0x19, 0x10, 0xac, 0xad, 0x7d,
+  0xce, 0x8a, 0x8f, 0x9f, 0x4a, 0x89, 0xd1, 0xb3, 0x2d, 0xb7, 0xdb, 0xda,
+  0x48, 0x35, 0x32, 0xcb, 0x30, 0xf0, 0xec, 0x1a, 0x97, 0x8e, 0xd3, 0x09,
+  0x1b, 0xf1, 0x22, 0x75, 0x5e, 0x37, 0xe1, 0x10, 0x73, 0x4b, 0x0a, 0xe5,
+  0xb3, 0xc1, 0xc9, 0x10, 0x64, 0xc0, 0x64, 0xad, 0x52, 0xc6, 0x0b, 0xfb,
+  0xef, 0xff, 0xd8, 0x5b, 0xf8, 0x36, 0x9b, 0x62, 0xf3, 0xf0, 0x44, 0x01,
+  0x36, 0x1b, 0x05, 0xa4, 0x3e, 0xd8, 0x30, 0xc1, 0x4a, 0x0c, 0x39, 0x03,
+  0x7f, 0x56, 0x3c, 0x56, 0x55, 0xbd, 0x05, 0x62, 0xca, 0x51, 0xea, 0xf0,
+  0xa8, 0xe8, 0xcd, 0x26, 0x83, 0x37, 0x9b, 0x8a, 0xf1, 0xbb, 0xe4, 0x41,
+  0xdf, 0xfd, 0x32, 0xc4, 0x7c, 0xb2, 0x07, 0x20, 0xc2, 0x65, 0xc4, 0xb1,
+  0xdb, 0x71, 0xbc, 0x03, 0x4a, 0xb5, 0x29, 0x68, 0xdb, 0x73, 0xb7, 0x38,
+  0x8a, 0x71, 0x40, 0x9a, 0xfe, 0x90, 0x14, 0x25, 0xe1, 0xea, 0xec, 0x4e,
+  0xad, 0x85, 0xb1, 0xae, 0x0c, 0x94, 0xa9, 0x06, 0x1a, 0x94, 0xde, 0xb5,
+  0x78, 0x1e, 0xff, 0x41, 0x85, 0x4d, 0xbc, 0x36, 0x2d, 0x6c, 0x2f, 0x30,
+  0x0c, 0xc8, 0x8e, 0xc6, 0xcf, 0x0f, 0x44, 0x60, 0x30, 0x8a, 0xab, 0x4d,
+  0x6e, 0xce, 0x9b, 0xe6, 0x88, 0x84, 0x62, 0xf6, 0x41, 0x46, 0xd0, 0xe1,
+  0xb4, 0xfe, 0x67, 0x2f, 0x98, 0xca, 0xa7, 0x14, 0xcb, 0xaa, 0x78, 0x86,
+  0x08, 0x80, 0x24, 0x39, 0x27, 0x08, 0x41, 0x05, 0x89, 0x59, 0xfc, 0xff,
+  0xd6, 0xee, 0xee, 0x33, 0x7f, 0x78, 0x6e, 0x95, 0xa9, 0x3c, 0x33, 0xc5,
+  0x37, 0x7a, 0xbe, 0xd1, 0x9b, 0xc6, 0x54, 0x9e, 0x72, 0xd1, 0x51, 0x69,
+  0x0e, 0xbd, 0x28, 0x84, 0x10, 0xaf, 0x3b, 0x41, 0x8b, 0x07, 0x83, 0x28,
+  0x08, 0x82, 0xc4, 0xd5, 0x31, 0x37, 0xbb, 0x37, 0x96, 0x6f, 0x22, 0xdd,
+  0x5a, 0x23, 0x71, 0x92, 0xe4, 0xaa, 0x44, 0x81, 0x19, 0xaf, 0x49, 0x14,
+  0x0e, 0x87, 0x92, 0xd4, 0x36, 0xc5, 0x5e, 0x71, 0x75, 0x58, 0xa1, 0xac,
+  0x95, 0x65, 0xa7, 0x45, 0x3f, 0x11, 0x3a, 0xd6, 0xff, 0x31, 0xab, 0x9a,
+  0xbf, 0x46, 0x47, 0x15, 0x61, 0x4f, 0x2d, 0x40, 0x0b, 0xf9, 0xb7, 0x0a,
+  0x4f, 0x25, 0x6c, 0xe2, 0x94, 0x50, 0x17, 0xdb, 0x36, 0x74, 0x77, 0xa5,
+  0xab, 0x01, 0x00, 0xa1, 0x11, 0xe3, 0x2a, 0x58, 0xe7, 0x60, 0x79, 0x6b,
+  0x91, 0xa9, 0xb1, 0x47, 0xd9, 0xb0, 0xae, 0xf4, 0x65, 0xda, 0xb0, 0x30,
+  0xd0, 0xc1, 0x77, 0xe7, 0x76, 0x72, 0x42, 0xde, 0x02, 0x3c, 0xec, 0xaf,
+  0x63, 0x15, 0xd6, 0x7b, 0x76, 0x64, 0x0b, 0x55, 0xd5, 0xf7, 0x88, 0x05,
+  0xe4, 0xae, 0x7f, 0xc5, 0x2c, 0x5c, 0x24, 0x5c, 0x50, 0x6f, 0x5b, 0x9e,
+  0x37, 0x78, 0x13, 0x44, 0x6c, 0x56, 0xdf, 0xbd, 0xc5, 0x05, 0x85, 0x55,
+  0x62, 0x61, 0xef, 0xd5, 0x28, 0xbb, 0x37, 0x2e, 0x59, 0x69, 0x47, 0x0d,
+  0x9f, 0xa8, 0x24, 0xaa, 0xe4, 0x52, 0xa6, 0x5e, 0xc4, 0x04, 0x22, 0xd4,
+  0xac, 0xe7, 0xf2, 0xdb, 0x17, 0xfd, 0xf1, 0x66, 0xdc, 0xea, 0xd3, 0xb9,
+  0xc0, 0x71, 0x98, 0x46, 0x6a, 0x9e, 0x1f, 0x6f, 0xd1, 0xe6, 0xff, 0xca,
+  0x51, 0x07, 0x14, 0x84, 0x32, 0xa5, 0xfb, 0x75, 0x57, 0x35, 0x7d, 0x63,
+  0x64, 0xa8, 0x2f, 0x10, 0x57, 0x1c, 0x6e, 0x2b, 0xf7, 0xfc, 0x58, 0xa5,
+  0xb6, 0x24, 0x91, 0x9c, 0x35, 0x40, 0x88, 0x64, 0x0c, 0x35, 0x54, 0x7b,
+  0x26, 0x7f, 0x39, 0x24, 0x53, 0xe2, 0xb2, 0x83, 0x4f, 0x48, 0x71, 0x0f,
+  0xb7, 0x23, 0xef, 0xfb, 0xf6, 0x36, 0x97, 0x4a, 0xa7, 0xf1, 0x4d, 0x24,
+  0x8b, 0x2e, 0x0c, 0x12, 0xda, 0x56, 0xf5, 0x4e, 0xea, 0x9c, 0x8a, 0x8b,
+  0x20, 0xe3, 0x8b, 0xad, 0xc5, 0xb9, 0x04, 0x55, 0x38, 0x09, 0x63, 0x6f,
+  0xf7, 0xca, 0x73, 0x06, 0xc5, 0xa8, 0x91, 0xce, 0x71, 0x60, 0xcc, 0x18,
+  0x2a, 0x1f, 0x88, 0xcd, 0xff, 0xea, 0xa7, 0xa1, 0x5f, 0xfc, 0x06, 0x27,
+  0x44, 0x46, 0x2a, 0xf3, 0xe0, 0x49, 0x6c, 0x13, 0xcf, 0xe1, 0x11, 0x82,
+  0xd2, 0xe2, 0x30, 0x39, 0xb5, 0x0c, 0x9d, 0x52, 0xa6, 0x2f, 0x2c, 0xa8,
+  0xbb, 0xaa, 0x77, 0x1a, 0xc1, 0xb2, 0x8c, 0x06, 0x23, 0x45, 0xb9, 0xa8,
+  0x91, 0xcb, 0x2c, 0xf7, 0x8b, 0x24, 0x9d, 0x06, 0x37, 0xf0, 0xd3, 0x01,
+  0x82, 0x91, 0x59, 0x67, 0xa4, 0xcc, 0xfc, 0xcd, 0xb4, 0x45, 0x11, 0x25,
+  0x46, 0x88, 0x2d, 0x31, 0x7d, 0x0a, 0xa2, 0x35, 0xb9, 0x6a, 0xeb, 0x40,
+  0x26, 0x28, 0x34, 0xc7, 0xde, 0x49, 0x51, 0xc4, 0x5f, 0xee, 0x14, 0x53,
+  0x88, 0x6a, 0xd1, 0x4a, 0xf6, 0x02, 0xa1, 0x75, 0xcd, 0x1e, 0xea, 0x24,
+  0xf1, 0x42, 0xc4, 0xab, 0x1c, 0x36, 0xce, 0x6f, 0x5a, 0xa5, 0xab, 0xfb,
+  0xb6, 0x48, 0x55, 0x6a, 0xcb, 0x2c, 0x22, 0xa1, 0x06, 0x1a, 0xf0, 0xbf,
+  0x2e, 0x20, 0x40, 0x72, 0x7d, 0xea, 0xde, 0x8c, 0x46, 0x88, 0xb1, 0x6e,
+  0xe1, 0x5f, 0xb9, 0x56, 0xea, 0x0d, 0x29, 0x80, 0xb5, 0x22, 0x91, 0x6c,
+  0xbf, 0x36, 0xb0, 0x9b, 0x90, 0xe9, 0x40, 0xa3, 0xea, 0xb3, 0xed, 0x4f,
+  0x54, 0x73, 0x85, 0x22, 0x61, 0xc0, 0xe2, 0xa6, 0x6e, 0x95, 0x41, 0xc8,
+  0x89, 0xf0, 0xcc, 0x11, 0xf0, 0xfa, 0x25, 0x87, 0x61, 0xdb, 0xb7, 0xd1,
+  0xb5, 0x7b, 0x65, 0xb0, 0x3d, 0xcd, 0xd5, 0x84, 0x01, 0x8f, 0xd4, 0x8a,
+  0x84, 0xfb, 0x72, 0x6f, 0x96, 0xee, 0x8b, 0xc8, 0xa3, 0x31, 0x48, 0x22,
+  0x28, 0xe4, 0x93, 0xb7, 0x70, 0xdd, 0x27, 0x9e, 0xf5, 0x3f, 0xe6, 0x20,
+  0xdb, 0xc1, 0x98, 0x26, 0x8d, 0x13, 0x98, 0xab, 0x4a, 0xeb, 0xae, 0xf2,
+  0xea, 0x15, 0x89, 0x05, 0x46, 0x93, 0xb6, 0x58, 0x93, 0xf5, 0x0d, 0x8a,
+  0x21, 0x4b, 0xea, 0xea, 0x81, 0xba, 0x33, 0x83, 0x11, 0xea, 0x79, 0xa5,
+  0x51, 0x14, 0x81, 0x5b, 0x0b, 0xa6, 0x6b, 0x2a, 0xc3, 0x51, 0x7f, 0xb6,
+  0xad, 0x60, 0x88, 0xa4, 0x60, 0xe7, 0x08, 0x94, 0x2d, 0x51, 0xee, 0xce,
+  0xe6, 0xe6, 0x95, 0x14, 0xf7, 0xbd, 0x0a, 0x55, 0xca, 0x9a, 0x98, 0xdc,
+  0xfc, 0x0b, 0x6f, 0x12, 0xa8, 0xb5, 0xb9, 0xc9, 0xff, 0x7e, 0xb5, 0xc4,
+  0x71, 0x42, 0x0a, 0x1a, 0x99, 0xa5, 0x5f, 0x9c, 0xd5, 0x28, 0xef, 0x41,
+  0x1e, 0xd2, 0x33, 0x58, 0x3c, 0xc0, 0x36, 0xcb, 0x2b, 0xda, 0xa3, 0x16,
+  0x43, 0x62, 0x3b, 0xf9, 0x01, 0x82, 0xb2, 0xd4, 0x58, 0x7e, 0xa6, 0x47,
+  0xe5, 0xf1, 0x56, 0x23, 0x85, 0x70, 0x6d, 0x88, 0x23, 0xcf, 0x6a, 0x79,
+  0x14, 0xff, 0x6c, 0x92, 0x77, 0x76, 0xf5, 0x6e, 0x13, 0x8d, 0xeb, 0x19,
+  0xa1, 0xec, 0xb6, 0xce, 0x1b, 0x38, 0xbb, 0x6a, 0x62, 0x9b, 0xe9, 0x36,
+  0x56, 0xb7, 0xca, 0x34, 0xdd, 0x42, 0x1a, 0x23, 0x06, 0x1a, 0xba, 0x82,
+  0x68, 0xd8, 0xf5, 0x28, 0x20, 0xee, 0x33, 0x14, 0x44, 0x8d, 0xa6, 0x6f,
+  0xfe, 0x91, 0x5e, 0xa7, 0x8c, 0x2d, 0x78, 0xb4, 0x8a, 0x3f, 0xad, 0xe9,
+  0xd1, 0x1e, 0xfc, 0x2b, 0x0c, 0xad, 0x0e, 0xf0, 0x4a, 0x2f, 0x10, 0x04,
+  0x90, 0x40, 0xc6, 0xb0, 0xb6, 0xdf, 0x25, 0xcc, 0xac, 0xdc, 0xb6, 0xf2,
+  0x7f, 0xb4, 0x6f, 0x81, 0xb6, 0x16, 0x16, 0x77, 0x01, 0x8e, 0x08, 0xc2,
+  0x0a, 0xb1, 0xfd, 0x49, 0xbe, 0x12, 0xbf, 0x14, 0xfe, 0x5d, 0x9f, 0xde,
+  0xa9, 0x92, 0xca, 0x1e, 0x40, 0xe3, 0x43, 0x50, 0x7c, 0xef, 0xfe, 0xe2,
+  0x3c, 0x58, 0x12, 0xb3, 0x60, 0xb6, 0x6d, 0x54, 0xe2, 0x4a, 0xaf, 0xb6,
+  0xca, 0x46, 0xbf, 0x35, 0xb5, 0x4b, 0xb3, 0xe4, 0x39, 0x6a, 0x20, 0x60,
+  0xa8, 0x36, 0x02, 0x0a, 0x68, 0xa8, 0x7b, 0xfd, 0xc0, 0xe9, 0x9e, 0xfe,
+  0x06, 0xbd, 0x0f, 0x60, 0x30, 0xd4, 0x19, 0x2d, 0x25, 0x4e, 0x3e, 0x2f,
+  0x10, 0x6d, 0xd1, 0x07, 0xdf, 0xd1, 0x06, 0x7f, 0xb6, 0xdb, 0xde, 0x7e,
+  0x7f, 0xa4, 0x69, 0x08, 0xe3, 0xff, 0x0f, 0xf7, 0xd5, 0xa9, 0x73, 0x32,
+  0x55, 0xa8, 0x73, 0xfa, 0xa6, 0xf0, 0x36, 0x0b, 0x4e, 0xdb, 0xd8, 0x78,
+  0xeb, 0xa7, 0xe8, 0x32, 0x0c, 0x5a, 0xac, 0x11, 0x3c, 0x9a, 0x37, 0xfc,
+  0x9e, 0xb5, 0x16, 0xd9, 0xdc, 0xa8, 0x2f, 0x03, 0x80, 0x9c, 0xc5, 0x65,
+  0xbd, 0x1b, 0xff, 0xf4, 0x09, 0xda, 0x70, 0xe8, 0xa0, 0x20, 0x01, 0xef,
+  0x89, 0x35, 0x4d, 0x2a, 0x55, 0x29, 0x5e, 0x9b, 0xa6, 0x9c, 0x36, 0xed,
+  0x89, 0x82, 0x00, 0x8e, 0x93, 0xd2, 0x30, 0x3b, 0xf7, 0x5a, 0xf7, 0x7f,
+  0x8d, 0xc2, 0xdb, 0xaa, 0x6d, 0x5e, 0x7d, 0x46, 0xa9, 0xdc, 0x50, 0x22,
+  0x02, 0xd8, 0x15, 0x82, 0x36, 0x09, 0x1f, 0x60, 0xb4, 0x79, 0x18, 0x10,
+  0x3e, 0x0c, 0x1c, 0x49, 0x95, 0x4a, 0x1b, 0x4a, 0x82, 0xd1, 0x3b, 0x22,
+  0x10, 0x34, 0x4d, 0x0b, 0x13, 0xff, 0x1a, 0xd5, 0x00, 0xc6, 0xfb, 0xf0,
+  0x60, 0x4d, 0x0c, 0x42, 0x11, 0x78, 0x21, 0x01, 0xef, 0xab, 0xfb, 0x03,
+  0xd6, 0x5b, 0x10, 0x71, 0x42, 0x8b, 0xef, 0xf1, 0x6a, 0xa6, 0x72, 0x8e,
+  0x3d, 0x81, 0xb0, 0x31, 0x1c, 0x3c, 0x52, 0xe6, 0x1f, 0x00, 0x00, 0x8a,
+  0x08, 0x6c, 0x46, 0x25, 0x2c, 0x3c, 0x1e, 0x03, 0xc3, 0xc0, 0x1e, 0x9a,
+  0x8c, 0x1a, 0x70, 0x55, 0xba, 0xb6, 0x14, 0x3a, 0x44, 0xa9, 0x28, 0xe8,
+  0x4a, 0x9d, 0xef, 0xf5, 0x22, 0xa5, 0x89, 0x22, 0xa8, 0x46, 0xaf, 0xdb,
+  0xf1, 0x6c, 0x62, 0x76, 0xee, 0x2a, 0xc5, 0x2b, 0x15, 0x22, 0x84, 0x22,
+  0xee, 0x14, 0x88, 0x9d, 0x74, 0xb9, 0xbe, 0x40, 0x5d, 0x55, 0x5e, 0xc0,
+  0x5c, 0x5d, 0xff, 0x16, 0x42, 0xfd, 0xd2, 0xc9, 0xc8, 0xbe, 0xd1, 0x91,
+  0xd9, 0xdd, 0x36, 0x05, 0xb7, 0x03, 0x6b, 0xc1, 0x93, 0x94, 0x2e, 0x55,
+  0x31, 0x55, 0xbc, 0x5f, 0xff, 0xac, 0x92, 0xf2, 0xc9, 0x0f, 0x47, 0xa2,
+  0x33, 0xe4, 0x9c, 0xb5, 0x32, 0xb9, 0x9b, 0xe4, 0x62, 0x83, 0xa3, 0xfc,
+  0xcf, 0x6c, 0xe8, 0xd9, 0x9e, 0xf0, 0x52, 0xf4, 0x44, 0x0d, 0x60, 0x4e,
+  0x78, 0x0f, 0xff, 0xa9, 0xe6, 0x45, 0xd4, 0x39, 0x9f, 0x96, 0x32, 0x6d,
+  0x22, 0x3e, 0x13, 0x25, 0x89, 0xbf, 0x61, 0x77, 0xad, 0xf6, 0x4f, 0xe6,
+  0xc0, 0xf5, 0x17, 0x57, 0xfc, 0xbd, 0x0e, 0x77, 0x0f, 0x8b, 0xd8, 0xfe,
+  0x36, 0xab, 0x21, 0x65, 0xf3, 0x2a, 0x14, 0x75, 0x1c, 0x34, 0x5b, 0xc1,
+  0x14, 0xc3, 0x56, 0xaa, 0x2b, 0xbe, 0x53, 0xb7, 0xad, 0x0c, 0x97, 0x27,
+  0x66, 0x3c, 0x5c, 0xea, 0xad, 0x55, 0xdc, 0xc6, 0xc0, 0xa2, 0x95, 0x05,
+  0xbc, 0x58, 0xd4, 0x06, 0x09, 0x06, 0xc9, 0xdb, 0xf6, 0x35, 0x65, 0x69,
+  0x4b, 0x3f, 0xd5, 0xb5, 0x1f, 0x2a, 0x1e, 0x95, 0x00, 0x9d, 0x7a, 0x85,
+  0x7a, 0xb1, 0x5a, 0x1e, 0x49, 0xc7, 0x20, 0x3f, 0xf7, 0x1b, 0xbb, 0xc4,
+  0x7d, 0x18, 0x90, 0x97, 0xc8, 0x79, 0xb1, 0x96, 0x96, 0x2d, 0x35, 0x6d,
+  0x9c, 0x24, 0xed, 0x36, 0xec, 0x39, 0x92, 0xa9, 0x6b, 0x6c, 0xa6, 0xe2,
+  0xd6, 0x3c, 0x8a, 0xa0, 0xfb, 0x12, 0xa9, 0x56, 0xd4, 0xff, 0xaa, 0xc4,
+  0xbe, 0x05, 0x4c, 0x0d, 0xc1, 0x2d, 0x97, 0xa4, 0xf3, 0x4c, 0xa8, 0xd8,
+  0x5a, 0xd1, 0x57, 0x34, 0x36, 0xb3, 0xb2, 0x83, 0x0d, 0x32, 0xdf, 0x13,
+  0x21, 0xf6, 0xc5, 0xaa, 0x80, 0xfd, 0x1b, 0x25, 0xc2, 0xd4, 0x45, 0x70,
+  0x6f, 0x2c, 0x45, 0x5e, 0x2b, 0x53, 0x8c, 0xe7, 0x73, 0x9f, 0x8a, 0x25,
+  0x1c, 0xa2, 0x92, 0xd8, 0x8c, 0x35, 0xc0, 0x5a, 0x2e, 0xd8, 0x91, 0xd0,
+  0xf4, 0x7d, 0xdb, 0xeb, 0xc2, 0xc4, 0x1e, 0xb5, 0x0f, 0xba, 0x0c, 0x83,
+  0x70, 0x12, 0x07, 0x62, 0x10, 0xf4, 0x18, 0xb1, 0x96, 0x7c, 0xaf, 0xd4,
+  0xb3, 0xe1, 0xdf, 0xb5, 0x1f, 0xa9, 0xb9, 0x01, 0x2e, 0xd8, 0x69, 0xc6,
+  0xb7, 0x93, 0x48, 0xad, 0x36, 0xb3, 0x93, 0xa1, 0xdf, 0xd0, 0xa0, 0x40,
+  0x46, 0xa2, 0x4e, 0xff, 0xf7, 0xfc, 0xb3, 0x25, 0x29, 0x94, 0x4e, 0x17,
+  0xf2, 0x2f, 0x8c, 0xb5, 0xc2, 0xcf, 0xe0, 0x7b, 0x71, 0x7c, 0x6e, 0x58,
+  0xb7, 0x01, 0x82, 0x42, 0xca, 0xb9, 0x25, 0xc9, 0x92, 0x4c, 0x44, 0x68,
+  0xf1, 0x83, 0x4d, 0x92, 0x45, 0x28, 0xd5, 0x06, 0xaf, 0x54, 0x03, 0x90,
+  0x90, 0xfd, 0x20, 0x18, 0x32, 0x3b, 0x83, 0xa8, 0x36, 0xad, 0xef, 0xf9,
+  0xe6, 0x3d, 0x03, 0x9b, 0x3a, 0x08, 0xc6, 0x24, 0x9d, 0xb1, 0xc4, 0xb4,
+  0x42, 0xdc, 0x37, 0xf8, 0xd4, 0xbd, 0x20, 0x1d, 0xfd, 0x3e, 0x6b, 0x36,
+  0xd5, 0xe0, 0x50, 0x75, 0x9f, 0xa7, 0xdb, 0xe0, 0x45, 0x58, 0x3c, 0xbf,
+  0x45, 0xc9, 0x0f, 0x0f, 0x70, 0x7a, 0x5a, 0x24, 0xb3, 0x27, 0x4b, 0x27,
+  0xb1, 0x74, 0x1c, 0xf1, 0x55, 0x5c, 0x68, 0x4f, 0x9a, 0x2d, 0xe8, 0x2d,
+  0x8b, 0xdc, 0x53, 0x8f, 0x6d, 0x01, 0xce, 0x61, 0x6b, 0x3d, 0xe0, 0x2b,
+  0x20, 0xc7, 0x84, 0xc3, 0xa2, 0xe1, 0xfe, 0x45, 0x62, 0x0a, 0x94, 0x7f,
+  0xa3, 0x0a, 0x7c, 0xa0, 0x32, 0x9f, 0x52, 0xd6, 0x00, 0xa5, 0xca, 0xba,
+  0x0a, 0xbc, 0x40, 0x1c, 0x02, 0xde, 0xa0, 0x8c, 0x39, 0x0f, 0x55, 0x7f,
+  0x9f, 0xf8, 0x14, 0xfd, 0x2a, 0x99, 0x45, 0x65, 0xcf, 0x4c, 0xe8, 0xe6,
+  0x02, 0x49, 0x89, 0x3d, 0x70, 0x3b, 0x8a, 0x1e, 0xd9, 0x5d, 0x1e, 0x88,
+  0x3f, 0x2c, 0x95, 0x1a, 0x23, 0x5d, 0x26, 0x5d, 0xbc, 0xd2, 0xdb, 0x10,
+  0xb8, 0xff, 0x87, 0x57, 0xb6, 0x02, 0x2f, 0xae, 0x7b, 0x61, 0x6e, 0xf8,
+  0xae, 0x4d, 0x35, 0x00, 0x4a, 0xa5, 0xe2, 0x5b, 0x5e, 0x66, 0xe5, 0x6c,
+  0xb7, 0xf9, 0x6b, 0x55, 0x41, 0x5c, 0x9b, 0x39, 0xd9, 0xd1, 0xb3, 0x5a,
+  0xbc, 0x2d, 0xc2, 0x53, 0x07, 0xb7, 0x32, 0x11, 0x0b, 0x99, 0x6c, 0xab,
+  0x43, 0xcf, 0x96, 0x46, 0x5b, 0xe1, 0x62, 0x35, 0x12, 0xf7, 0x78, 0x80,
+  0x1c, 0x60, 0xd0, 0xfe, 0x87, 0xb2, 0x41, 0xb2, 0x0e, 0x2f, 0x14, 0xa1,
+  0x87, 0xc9, 0x8f, 0x0b, 0xf4, 0x6f, 0x9a, 0xa2, 0x28, 0x37, 0xd9, 0x29,
+  0xb3, 0xde, 0xa9, 0x56, 0x57, 0xfc, 0x6b, 0x29, 0x6f, 0xdb, 0x0f, 0x17,
+  0xea, 0x09, 0x40, 0x9e, 0x70, 0xcd, 0x68, 0xcb, 0x1f, 0x4e, 0xe6, 0x49,
+  0x11, 0x23, 0x46, 0x27, 0x37, 0x59, 0x65, 0x7f, 0x55, 0xeb, 0x5d, 0x6b,
+  0xa8, 0xed, 0xc9, 0xd2, 0xce, 0xa8, 0x11, 0x14, 0x3d, 0x38, 0x4f, 0xda,
+  0x4a, 0xa7, 0x5b, 0xaa, 0xb7, 0xad, 0x6f, 0xf6, 0x6a, 0x05, 0xe7, 0xec,
+  0xb0, 0x2a, 0x2a, 0x14, 0x05, 0xa5, 0xa7, 0x87, 0xdb, 0xf0, 0xf5, 0xaf,
+  0xc9, 0x9c, 0x1b, 0x72, 0x59, 0x14, 0x20, 0xe0, 0xc6, 0x83, 0x0d, 0x7b,
+  0x71, 0xbc, 0x2b, 0x90, 0xa9, 0x71, 0x4a, 0x32, 0x21, 0x25, 0x1b, 0x20,
+  0x86, 0xcf, 0x25, 0xd5, 0x9d, 0xf7, 0x86, 0x6b, 0x63, 0x34, 0xa9, 0xfd,
+  0xe5, 0x03, 0x9d, 0x9c, 0xbb, 0x7b, 0x5b, 0xd9, 0xe9, 0x21, 0x22, 0x91,
+  0xba, 0x30, 0xb0, 0x60, 0xac, 0x4b, 0x11, 0xb9, 0x4b, 0x52, 0xb1, 0x39,
+  0xde, 0xf3, 0xf3, 0x6f, 0x49, 0x23, 0x87, 0xe0, 0xcd, 0x89, 0x1a, 0x5e,
+  0x24, 0xb4, 0xc5, 0x66, 0x4a, 0x9e, 0x6e, 0xa4, 0x2d, 0xd5, 0x11, 0x6e,
+  0x16, 0xb5, 0x00, 0x9f, 0x35, 0x40, 0x15, 0x07, 0xc8, 0x80, 0x1c, 0x30,
+  0xc0, 0x38, 0xc6, 0x25, 0xf3, 0x4c, 0xb3, 0xb3, 0x9b, 0xc6, 0x79, 0xce,
+  0xa2, 0xec, 0x2c, 0xfc, 0x19, 0x18, 0x83, 0x9b, 0x00, 0xa2, 0x97, 0x45,
+  0x3a, 0x81, 0xcd, 0x86, 0xa0, 0x3a, 0x10, 0xbc, 0xda, 0xb6, 0xd5, 0xa6,
+  0x6f, 0xb6, 0xf3, 0x4b, 0x39, 0xc5, 0x36, 0xa1, 0x80, 0x24, 0x33, 0x5c,
+  0xb9, 0x6e, 0x6c, 0xe5, 0x88, 0xc9, 0xc5, 0xad, 0x81, 0xc2, 0xf2, 0xd1,
+  0x05, 0xa6, 0x53, 0xc6, 0xb9, 0x8d, 0x15, 0xaf, 0x67, 0xa2, 0x29, 0x2a,
+  0x90, 0xe1, 0xc1, 0x1f, 0xc1, 0x00, 0x7d, 0xa5, 0x5f, 0x62, 0xb3, 0x68,
+  0x15, 0xfe, 0xd1, 0xcd, 0x19, 0xa0, 0x21, 0x80, 0x89, 0xaa, 0xd7, 0x9e,
+  0x1c, 0x3d, 0xf5, 0x57, 0x50, 0x05, 0x8d, 0x96, 0x54, 0x3e, 0x4e, 0xae,
+  0x29, 0x6b, 0xca, 0x60, 0x6b, 0x30, 0x1c, 0xa4, 0x8c, 0x83, 0x0c, 0x82,
+  0x0b, 0x1b, 0x0b, 0x95, 0x08, 0x39, 0x77, 0x2b, 0x58, 0xc6, 0x42, 0xa5,
+  0xd0, 0xc9, 0x0a, 0xa6, 0x83, 0x06, 0xe0, 0xf9, 0x5f, 0xfd, 0xd6, 0xe0,
+  0x84, 0x93, 0x33, 0xa1, 0xfc, 0x2c, 0x0e, 0xbd, 0x85, 0x9a, 0xa6, 0xf5,
+  0x6e, 0x51, 0x88, 0x31, 0x01, 0x46, 0x12, 0xab, 0x92, 0x03, 0x16, 0x08,
+  0x4c, 0xed, 0x0e, 0x53, 0xec, 0x60, 0x18, 0x13, 0x6d, 0x1f, 0x66, 0x23,
+  0xf9, 0xda, 0x38, 0x15, 0xb6, 0x16, 0x84, 0x60, 0x6c, 0xf4, 0x98, 0xd9,
+  0x7e, 0x29, 0x66, 0xf3, 0x7f, 0xbf, 0xaa, 0x43, 0xd4, 0x21, 0xaa, 0x10,
+  0x13, 0x20, 0x7c, 0x74, 0x07, 0x87, 0x59, 0xa3, 0xf2, 0xf6, 0xb5, 0x3d,
+  0x5b, 0xde, 0xf2, 0x9b, 0x33, 0xbc, 0xbc, 0xf4, 0xe0, 0xd9, 0x15, 0x06,
+  0x27, 0x0a, 0xa3, 0xe2, 0xe6, 0x5b, 0xf6, 0x6a, 0xb9, 0x23, 0x6a, 0x21,
+  0x6e, 0x65, 0xb7, 0xd2, 0xa1, 0x0d, 0x42, 0xc5, 0xc4, 0x70, 0x38, 0x3c,
+  0x05, 0x68, 0xf4, 0x7b, 0xf9, 0xbe, 0x69, 0xa5, 0x83, 0xf5, 0xd8, 0x6a,
+  0x49, 0xc0, 0xf3, 0xca, 0x46, 0xfb, 0xa0, 0xa8, 0xff, 0xc6, 0xc2, 0xc7,
+  0xf9, 0x60, 0x58, 0xbb, 0xce, 0x11, 0x3f, 0x00, 0x00, 0x8f, 0x08, 0x2c,
+  0x44, 0x23, 0x2c, 0x98, 0x78, 0x6c, 0x19, 0x42, 0x65, 0x15, 0x07, 0x47,
+  0x10, 0xe1, 0x26, 0x35, 0x5b, 0x2a, 0x65, 0xd0, 0x33, 0x94, 0xd1, 0x02,
+  0x63, 0xad, 0xf0, 0x31, 0x60, 0xf1, 0x06, 0x82, 0xa8, 0xb8, 0x95, 0x71,
+  0xc7, 0x97, 0x06, 0x13, 0xcf, 0x99, 0x98, 0x1e, 0xa8, 0xa6, 0xbb, 0x17,
+  0x46, 0x86, 0xb8, 0x5c, 0x52, 0x22, 0x72, 0x65, 0x7a, 0x38, 0xee, 0xea,
+  0xfa, 0x19, 0x39, 0x60, 0x45, 0x5f, 0x91, 0x1f, 0x51, 0x2c, 0xbd, 0x06,
+  0x13, 0xad, 0xad, 0x08, 0x3d, 0xd1, 0x06, 0x6c, 0xed, 0xea, 0x85, 0xce,
+  0x29, 0x4b, 0x99, 0xe4, 0x2c, 0x92, 0x31, 0xb0, 0x3b, 0xdd, 0x2b, 0xab,
+  0x03, 0x02, 0xeb, 0x2b, 0x40, 0xe9, 0x64, 0x5a, 0x4a, 0xd5, 0x47, 0xb9,
+  0x28, 0x6b, 0xde, 0x53, 0x47, 0xe3, 0xe9, 0x58, 0x6a, 0x4d, 0xdf, 0xce,
+  0x5e, 0xf0, 0x96, 0xc4, 0x71, 0xc3, 0x78, 0xc2, 0xc5, 0x9d, 0x53, 0x28,
+  0x2f, 0x4d, 0x09, 0x7f, 0xeb, 0x6c, 0x78, 0x6d, 0xef, 0x7a, 0x64, 0x42,
+  0xbb, 0x8a, 0x64, 0xcf, 0x68, 0x87, 0x2f, 0x59, 0x51, 0x63, 0x5e, 0xb3,
+  0xd8, 0x86, 0xdd, 0xb2, 0xf2, 0x86, 0xc4, 0x5d, 0x37, 0x87, 0x3c, 0x67,
+  0xf9, 0x0b, 0x6f, 0x69, 0x2f, 0x2d, 0xe8, 0x30, 0xd6, 0x5a, 0x93, 0xed,
+  0x64, 0xf5, 0x95, 0x42, 0x72, 0xb8, 0x84, 0x3a, 0x47, 0xc1, 0x38, 0x9d,
+  0xae, 0xe2, 0x30, 0x4c, 0x38, 0xfe, 0x99, 0x25, 0xbd, 0x37, 0xe6, 0x86,
+  0xa6, 0x8b, 0x7a, 0xb9, 0xb0, 0xaf, 0xb3, 0xcd, 0x63, 0x94, 0x89, 0x7e,
+  0xfb, 0xc0, 0x91, 0xd2, 0x29, 0x5a, 0x46, 0x15, 0xb1, 0x1b, 0xec, 0xb1,
+  0x00, 0x56, 0x9c, 0x57, 0x9d, 0x86, 0xea, 0x08, 0xbb, 0xcb, 0xd9, 0x43,
+  0x20, 0xab, 0xa5, 0x86, 0x06, 0xe5, 0xcb, 0x72, 0x8d, 0xe6, 0xf0, 0xd1,
+  0xf4, 0xff, 0xfb, 0xad, 0x30, 0x6f, 0xd2, 0xb5, 0x4a, 0x25, 0xec, 0x0c,
+  0xc1, 0x82, 0xa2, 0xa2, 0x3c, 0x50, 0x9c, 0x35, 0x82, 0xf7, 0x2c, 0xd6,
+  0x75, 0x86, 0xf9, 0x2e, 0xe9, 0x6c, 0x2a, 0x88, 0xf9, 0x65, 0xeb, 0xf8,
+  0xf2, 0xc8, 0x08, 0xdb, 0xe0, 0x44, 0x4a, 0xc3, 0x3f, 0x99, 0x2d, 0xf0,
+  0x81, 0xd4, 0x52, 0xfe, 0xf2, 0xc0, 0xaa, 0x12, 0x97, 0x2a, 0x2f, 0xf8,
+  0xe3, 0x8a, 0x20, 0xe2, 0xe7, 0x99, 0xc5, 0xb9, 0xce, 0x76, 0x5a, 0x22,
+  0xe2, 0x90, 0x4a, 0x86, 0x3d, 0xe1, 0xd3, 0x0a, 0x12, 0xe1, 0x6b, 0x69,
+  0x6c, 0x2c, 0xcc, 0xc1, 0xcc, 0xf2, 0xfc, 0x85, 0xaa, 0x0a, 0x86, 0xd5,
+  0x48, 0x30, 0x9d, 0x1e, 0xa8, 0x1c, 0x4c, 0x5a, 0xc9, 0x75, 0x17, 0x39,
+  0x2a, 0x29, 0x01, 0x69, 0x8c, 0xe9, 0x56, 0x91, 0xb6, 0x3d, 0xf0, 0xfc,
+  0xbc, 0x20, 0x37, 0x58, 0x52, 0xa7, 0xdd, 0x5f, 0xda, 0x1d, 0x6c, 0x37,
+  0x03, 0x83, 0x22, 0x01, 0xd0, 0x86, 0xa9, 0x2d, 0x51, 0x29, 0x66, 0x83,
+  0x1a, 0xd0, 0xca, 0x50, 0x4b, 0x2a, 0x10, 0x47, 0x5a, 0xd8, 0x32, 0xf8,
+  0x57, 0x79, 0x0b, 0x4d, 0x8a, 0x43, 0xba, 0xf9, 0x4d, 0x3c, 0xbe, 0x29,
+  0x05, 0xb1, 0x53, 0x3c, 0xc8, 0xa5, 0xb2, 0x2c, 0xad, 0x7c, 0x33, 0x17,
+  0x9d, 0x38, 0x9d, 0x9f, 0x79, 0x2b, 0x0a, 0x7c, 0x39, 0xab, 0x21, 0x92,
+  0xc9, 0x3c, 0x8c, 0xac, 0x52, 0x13, 0x41, 0x48, 0xcf, 0xd5, 0x89, 0x49,
+  0xeb, 0x34, 0xb7, 0x55, 0x33, 0xc9, 0xfd, 0x5f, 0x54, 0x59, 0x81, 0xe0,
+  0x38, 0xc5, 0x7f, 0x28, 0x22, 0xd6, 0x74, 0xad, 0x6e, 0x44, 0x0b, 0x42,
+  0x2f, 0x21, 0x1b, 0x7a, 0x73, 0x45, 0xad, 0xa8, 0x5f, 0xf8, 0xad, 0x95,
+  0x17, 0xbc, 0xbe, 0xe5, 0xc1, 0x97, 0x01, 0x86, 0x81, 0xc8, 0x7a, 0x0f,
+  0x05, 0x01, 0x98, 0x06, 0x2b, 0xf9, 0x7e, 0xb0, 0x3f, 0x57, 0x59, 0x53,
+  0x83, 0x8f, 0x16, 0x65, 0xfc, 0xf8, 0x31, 0x54, 0xb7, 0x01, 0x83, 0x8d,
+  0x80, 0xc1, 0x52, 0xca, 0xd4, 0xee, 0xac, 0x8b, 0x90, 0xb4, 0xdf, 0x0d,
+  0x47, 0x88, 0x47, 0xe9, 0x02, 0x11, 0x7a, 0x61, 0xc2, 0xb6, 0x26, 0xf8,
+  0xab, 0x7f, 0x36, 0xf1, 0x78, 0xbc, 0xb4, 0x09, 0x82, 0x52, 0xe6, 0x6f,
+  0x16, 0xa0, 0x92, 0x54, 0x84, 0x6d, 0xd2, 0xaa, 0xca, 0x74, 0x8d, 0x27,
+  0x6f, 0xdb, 0x3f, 0xff, 0x79, 0xbb, 0xb8, 0x1d, 0x77, 0xfe, 0xe8, 0x79,
+  0x43, 0x83, 0xab, 0x88, 0x60, 0x1a, 0x10, 0xc4, 0xa4, 0x89, 0x01, 0x13,
+  0x1a, 0xd9, 0xbf, 0x04, 0x46, 0xfb, 0x9f, 0xac, 0xce, 0xfe, 0xf2, 0x50,
+  0x24, 0x55, 0xe3, 0x2b, 0x8f, 0x1b, 0xf4, 0x55, 0xaa, 0xb4, 0xaf, 0xd9,
+  0xa0, 0xac, 0x43, 0x4b, 0x2a, 0x25, 0xc3, 0x6e, 0x28, 0x05, 0x70, 0x58,
+  0x30, 0x11, 0xf7, 0x22, 0x7b, 0x20, 0x32, 0x1f, 0x45, 0x11, 0x41, 0x50,
+  0x78, 0xb7, 0x3a, 0x1c, 0x83, 0x04, 0x62, 0x97, 0x0b, 0x78, 0xd5, 0x2a,
+  0xa6, 0x0a, 0x3c, 0xd8, 0xb8, 0x47, 0x06, 0xd5, 0x41, 0x09, 0x21, 0x73,
+  0x52, 0xf3, 0xec, 0xa8, 0xcc, 0x9c, 0x1b, 0x67, 0x03, 0xd6, 0xe8, 0x6e,
+  0xa6, 0x39, 0x41, 0x2b, 0xdf, 0x12, 0xee, 0x33, 0x17, 0x4d, 0xff, 0xd6,
+  0xd4, 0xc5, 0xfd, 0xff, 0xd0, 0xef, 0xfd, 0x11, 0x77, 0x4e, 0x06, 0x51,
+  0xe8, 0x1c, 0xf3, 0x2c, 0xe2, 0xb5, 0x7e, 0xad, 0xa9, 0xf2, 0xf9, 0x2f,
+  0x26, 0x67, 0x56, 0xed, 0x0e, 0x54, 0x38, 0x4c, 0x10, 0x82, 0x00, 0x94,
+  0xd6, 0x65, 0x54, 0xac, 0x77, 0xea, 0xb7, 0x1a, 0x05, 0x5b, 0x73, 0xde,
+  0xd1, 0xbd, 0xe3, 0x19, 0xb8, 0xc6, 0xe2, 0x3c, 0x2b, 0xf0, 0xb4, 0x61,
+  0x9f, 0x7d, 0x50, 0xde, 0x7b, 0x42, 0xd7, 0xb0, 0xf2, 0x61, 0x6d, 0x47,
+  0x95, 0x4e, 0x35, 0x92, 0x2c, 0xbe, 0xc5, 0xad, 0xa6, 0x9e, 0xa2, 0x97,
+  0x9e, 0x61, 0x56, 0xf8, 0xac, 0x41, 0xd6, 0x40, 0xa1, 0x5a, 0x0a, 0x40,
+  0x80, 0x96, 0x98, 0x7e, 0x90, 0x79, 0xe1, 0xff, 0xb2, 0x83, 0x23, 0x8b,
+  0x71, 0x4e, 0xcc, 0xb2, 0xae, 0x08, 0xe0, 0x20, 0xe1, 0x35, 0x6e, 0xd4,
+  0x2b, 0x67, 0x8c, 0x31, 0x72, 0x5f, 0xd9, 0x3f, 0x7f, 0x6c, 0x05, 0x60,
+  0x15, 0xe7, 0x01, 0x90, 0x81, 0x00, 0x61, 0x88, 0x25, 0x0d, 0x81, 0xb9,
+  0x04, 0x65, 0x6a, 0xd3, 0x62, 0x78, 0xad, 0x81, 0xc8, 0xe7, 0x32, 0x81,
+  0x76, 0xa7, 0xd1, 0xca, 0x1c, 0xe2, 0x91, 0x14, 0xb4, 0x18, 0x12, 0xc7,
+  0x25, 0xe1, 0x04, 0x1b, 0x83, 0xed, 0x1d, 0x8f, 0x59, 0xd6, 0xbd, 0xb9,
+  0x60, 0xf9, 0x0a, 0xb4, 0xf4, 0xd2, 0x68, 0x87, 0x30, 0x39, 0x06, 0x22,
+  0x06, 0x48, 0xfc, 0x1a, 0x8e, 0xd3, 0x8f, 0xc1, 0x4f, 0x35, 0x46, 0xf9,
+  0x6f, 0x51, 0xbe, 0xa8, 0x88, 0x8b, 0x6e, 0x8d, 0xc1, 0x86, 0x94, 0x72,
+  0x02, 0x9a, 0xe8, 0x58, 0xd9, 0x5c, 0xf9, 0xe4, 0x47, 0x27, 0x1d, 0x06,
+  0x4e, 0x01, 0xbc, 0xe0, 0x29, 0xf8, 0x4b, 0x18, 0x6a, 0x51, 0x98, 0x08,
+  0x95, 0x40, 0xc9, 0x40, 0xeb, 0x1b, 0x77, 0x53, 0x87, 0xf2, 0xa3, 0xf3,
+  0x39, 0x2e, 0x0c, 0xb8, 0x36, 0x7a, 0xd4, 0xf9, 0x50, 0x05, 0x9d, 0x65,
+  0xcd, 0x86, 0xb0, 0x64, 0xe3, 0xb4, 0xc9, 0xb4, 0x46, 0x10, 0x58, 0x10,
+  0x78, 0x9c, 0x72, 0x59, 0xdb, 0x36, 0x7a, 0x4b, 0x2d, 0xf5, 0x82, 0x2a,
+  0x9b, 0x01, 0x24, 0xa3, 0x69, 0x8b, 0x87, 0xa9, 0x15, 0x04, 0x34, 0x8d,
+  0xed, 0x9e, 0xb1, 0xb8, 0x86, 0xd9, 0x65, 0xef, 0x83, 0x6d, 0xc3, 0xe6,
+  0xc2, 0x18, 0x8f, 0xf0, 0x82, 0x94, 0x3f, 0xd0, 0xf3, 0x8d, 0x66, 0x4c,
+  0xea, 0xd3, 0x92, 0x77, 0x80, 0x4f, 0xa6, 0x42, 0x98, 0x30, 0x90, 0x3b,
+  0xc6, 0xbc, 0x0c, 0x58, 0xae, 0x95, 0x2b, 0xba, 0xdb, 0x55, 0x16, 0x42,
+  0xc8, 0xba, 0xe3, 0x10, 0x61, 0xa7, 0x8c, 0xaf, 0x49, 0xbc, 0x16, 0xb7,
+  0x81, 0x57, 0x0b, 0x2d, 0xb1, 0x4c, 0x91, 0x10, 0x8a, 0xb3, 0x83, 0x30,
+  0xf4, 0x20, 0xb2, 0xcf, 0xf3, 0xc9, 0x18, 0xd4, 0x89, 0x27, 0x03, 0xfd,
+  0x56, 0x55, 0xb7, 0x6a, 0x3f, 0x12, 0x28, 0x07, 0x07, 0xa1, 0x60, 0x88,
+  0xbc, 0x7a, 0xab, 0xdc, 0x6c, 0xb9, 0x26, 0x2b, 0x34, 0xdf, 0xf9, 0x9e,
+  0x44, 0x1d, 0x95, 0x95, 0xe8, 0x2a, 0x03, 0xa2, 0xd0, 0x62, 0x73, 0x62,
+  0x1a, 0xa1, 0xe8, 0x43, 0x6c, 0xb5, 0x8c, 0xef, 0x76, 0xd1, 0xc7, 0x96,
+  0xed, 0xa8, 0xed, 0x50, 0x54, 0xa4, 0xc8, 0xb3, 0x2d, 0xef, 0x22, 0x8a,
+  0x75, 0x3f, 0xfe, 0x9e, 0x6f, 0x60, 0x80, 0xc2, 0x56, 0x9b, 0xda, 0xa7,
+  0x54, 0x42, 0xbd, 0xee, 0xf1, 0x9b, 0x17, 0xbe, 0xaa, 0x14, 0x28, 0xc5,
+  0xf0, 0x58, 0x26, 0x4d, 0x37, 0x74, 0x0c, 0x4d, 0xfe, 0xff, 0x94, 0x6f,
+  0xdb, 0x79, 0x16, 0x91, 0x49, 0x56, 0x00, 0x82, 0x63, 0xa0, 0x38, 0x24,
+  0xe7, 0xb0, 0x72, 0xa3, 0x35, 0x85, 0xd4, 0x56, 0xe6, 0xa9, 0xc8, 0xb4,
+  0x9c, 0xc2, 0x97, 0x0b, 0x41, 0x08, 0x78, 0xda, 0xa8, 0xad, 0x2a, 0x55,
+  0x19, 0x54, 0x48, 0xc7, 0xb1, 0x16, 0x67, 0x3b, 0xf0, 0x26, 0xa5, 0xd3,
+  0xdf, 0x2c, 0x62, 0xef, 0xfd, 0xfe, 0xe8, 0x31, 0x14, 0xca, 0xb1, 0x13,
+  0x61, 0x74, 0x74, 0x95, 0x9f, 0x35, 0xf0, 0xfd, 0x37, 0xd2, 0x31, 0xec,
+  0x0e, 0xd9, 0xbe, 0x85, 0xb2, 0x4e, 0xff, 0xeb, 0x16, 0x95, 0x61, 0xe0,
+  0x60, 0x83, 0x32, 0x0d, 0xf4, 0xe2, 0x3a, 0xb9, 0xe4, 0x95, 0xb6, 0x07,
+  0x4d, 0x68, 0x18, 0x40, 0x1f, 0xd8, 0x0c, 0x87, 0xe0, 0xe0, 0x29, 0x80,
+  0xe3, 0x21, 0x9c, 0x14, 0xa2, 0x3b, 0x2c, 0xfa, 0x2a, 0x54, 0x1e, 0x35,
+  0x7b, 0x55, 0xd5, 0xef, 0xef, 0xa2, 0x29, 0xcc, 0x04, 0x70, 0x61, 0x30,
+  0xc1, 0x76, 0xd4, 0x67, 0xb3, 0x29, 0x66, 0xc0, 0x33, 0xd5, 0xf9, 0x51,
+  0xda, 0x0b, 0x41, 0xbf, 0xfa, 0xa8, 0x9b, 0x51, 0x99, 0x30, 0xc9, 0x6a,
+  0x0f, 0x87, 0x1e, 0x1d, 0x0e, 0xac, 0x5f, 0xe0, 0xaa, 0x4d, 0xde, 0xaf,
+  0x3a, 0x38, 0xf1, 0x02, 0x82, 0x08, 0x71, 0x9d, 0xde, 0x2f, 0xbc, 0xe4,
+  0x14, 0x2e, 0x3c, 0x52, 0x0a, 0xa2, 0xe5, 0x1d, 0xb4, 0x14, 0xca, 0x86,
+  0x03, 0x87, 0x18, 0x10, 0x0b, 0xf7, 0x96, 0x67, 0x09, 0x77, 0xf2, 0x2c,
+  0x6f, 0x86, 0x1b, 0xe1, 0x54, 0x3a, 0x9e, 0x8c, 0xce, 0x29, 0x45, 0xf4,
+  0x4a, 0x3c, 0x50, 0x84, 0x44, 0x04, 0x70, 0x7c, 0x98, 0x01, 0xd4, 0xac,
+  0xb7, 0x6f, 0x95, 0x62, 0xbb, 0x2d, 0xc5, 0x3b, 0xde, 0xa8, 0x99, 0x10,
+  0x41, 0xc1, 0x69, 0x58, 0x6c, 0x58, 0x2c, 0x59, 0xb9, 0xf9, 0xb2, 0x02,
+  0xb2, 0xea, 0x95, 0xf9, 0x6a, 0xeb, 0xaf, 0x3a, 0xa1, 0x40, 0x5a, 0xb3,
+  0x77, 0xa2, 0x1b, 0x05, 0xf1, 0x5a, 0x72, 0xea, 0x93, 0x2f, 0xab, 0x4c,
+  0x37, 0xd6, 0x9b, 0xcf, 0xcb, 0xd8, 0xcc, 0xc2, 0xdc, 0x6f, 0x34, 0x15,
+  0xc5, 0xa5, 0x86, 0x09, 0xf0, 0xa8, 0xc2, 0xd3, 0x52, 0xa6, 0x50, 0xe4,
+  0x31, 0x06, 0x0a, 0x4d, 0x17, 0xf9, 0xb2, 0xdc, 0xea, 0xf6, 0xdd, 0x51,
+  0xd4, 0x5c, 0xa7, 0x05, 0xf3, 0xf9, 0xe6, 0xae, 0x94, 0x92, 0x89, 0x85,
+  0x09, 0x38, 0x9d, 0xab, 0x3f, 0xcd, 0x5e, 0xac, 0x87, 0xb6, 0xf5, 0x67,
+  0xc2, 0xdc, 0x99, 0x61, 0x23, 0xcc, 0xb1, 0xcf, 0x25, 0xb8, 0xdb, 0x3c,
+  0x2d, 0xdf, 0xe6, 0x16, 0x4e, 0x5b, 0x6f, 0xa7, 0x14, 0xfc, 0x44, 0xe1,
+  0x68, 0x31, 0x3c, 0xb0, 0xb8, 0x2f, 0xd3, 0xa5, 0xc5, 0x9c, 0xad, 0x77,
+  0xb7, 0x83, 0x2e, 0x11, 0xbf, 0x2d, 0x17, 0x46, 0x8f, 0xa5, 0x0e, 0xa6,
+  0xcf, 0xb5, 0x9a, 0x2f, 0x57, 0xca, 0x58, 0x86, 0x0b, 0x90, 0x3b, 0xb0,
+  0x93, 0x19, 0x2b, 0xfd, 0xa1, 0xb9, 0xaa, 0x48, 0x0b, 0x61, 0xa7, 0xf5,
+  0x4a, 0x7d, 0x6d, 0x07, 0x68, 0xc3, 0xa7, 0x05, 0xca, 0xa7, 0x0a, 0xd0,
+  0x03, 0xba, 0xeb, 0x6d, 0x60, 0x44, 0x07, 0x82, 0xff, 0x8d, 0xaf, 0xe0,
+  0x30, 0x16, 0xf7, 0xbb, 0x98, 0x1c, 0x6f, 0xaf, 0x00, 0x9a, 0x93, 0xa9,
+  0xa3, 0x7d, 0x0e, 0xbc, 0xc8, 0x2b, 0x75, 0x95, 0xad, 0xfd, 0x29, 0xe5,
+  0xa7, 0xfb, 0x8b, 0x85, 0x8a, 0x07, 0x65, 0xcd, 0x6a, 0xa5, 0x6a, 0xef,
+  0x6f, 0xd4, 0x4f, 0x40, 0xe3, 0x9c, 0xef, 0x78, 0x1c, 0x9c, 0x3a, 0x01,
+  0xd9, 0xdf, 0x0f, 0xe7, 0xb4, 0xb1, 0x92, 0xcf, 0x16, 0x74, 0x67, 0xd0,
+  0x61, 0xaa, 0x63, 0xfd, 0xe8, 0xf9, 0x5b, 0x5e, 0x1b, 0xf7, 0xbf, 0x24,
+  0xce, 0x68, 0x44, 0x90, 0x07, 0x42, 0xc5, 0x41, 0xfd, 0x2a, 0xd6, 0xd5,
+  0x8e, 0x0d, 0xac, 0x58, 0xb0, 0x66, 0xf7, 0x3a, 0x83, 0x10, 0x97, 0x99,
+  0xad, 0xb4, 0xa9, 0x36, 0x96, 0x34, 0xd4, 0x03, 0x7a, 0x56, 0x8b, 0x27,
+  0xea, 0xdc, 0x85, 0x44, 0x97, 0x0a, 0xc0, 0xae, 0xe0, 0x0a, 0xa6, 0xbe,
+  0x5a, 0xde, 0xe2, 0x8b, 0x9c, 0xdc, 0x1b, 0xad, 0x6d, 0xb1, 0x7a, 0x0c,
+  0x35, 0x32, 0x07, 0x53, 0x7c, 0x70, 0x5b, 0x8a, 0x6f, 0x95, 0x5b, 0xb7,
+  0x00, 0x86, 0xf6, 0x4f, 0x37, 0x0d, 0x29, 0x3a, 0xaa, 0x46, 0x7f, 0xa3,
+  0xd9, 0xbf, 0xfa, 0x9c, 0x60, 0x7c, 0xab, 0xbd, 0x1b, 0xdb, 0x60, 0x2c,
+  0x41, 0x82, 0xa6, 0x96, 0x77, 0xd1, 0xed, 0x88, 0x99, 0xf5, 0xfc, 0x88,
+  0x64, 0xdd, 0xec, 0x0d, 0xa3, 0xc5, 0x21, 0x0c, 0x75, 0x5a, 0xa2, 0x0f,
+  0xb2, 0x96, 0x7e, 0xef, 0x20, 0x70, 0x48, 0x7c, 0x52, 0xb5, 0x97, 0x11,
+  0xcb, 0x41, 0x38, 0x2e, 0xb3, 0xf8, 0x55, 0x2e, 0x62, 0x8d, 0xe8, 0xa1,
+  0xf1, 0xe7, 0xb5, 0xa5, 0x8f, 0x6d, 0x50, 0x6c, 0x51, 0x44, 0x21, 0xfe,
+  0x45, 0xbe, 0x1f, 0x95, 0x94, 0x96, 0x4a, 0xe3, 0xa3, 0xf4, 0xfd, 0xfb,
+  0x6c, 0x76, 0xb5, 0xb7, 0x9d, 0xda, 0xbc, 0xdc, 0x43, 0x39, 0xa5, 0xaa,
+  0x11, 0xcd, 0x2a, 0x2c, 0x04, 0x8a, 0x1e, 0x35, 0x89, 0x3e, 0x5e, 0xd6,
+  0x49, 0x31, 0x3e, 0xcf, 0xc4, 0x12, 0x3f, 0x08, 0xe3, 0xaf, 0xea, 0x7e,
+  0xf0, 0x13, 0x89, 0x54, 0xa0, 0xb6, 0xca, 0x0c, 0x4c, 0x57, 0xb5, 0x4f,
+  0xe8, 0x2d, 0xdb, 0x2a, 0xab, 0xfe, 0x69, 0x8b, 0xe5, 0xd9, 0xca, 0x37,
+  0xbf, 0xbd, 0xde, 0x2c, 0xbc, 0xa1, 0xc2, 0x20, 0x10, 0x32, 0x03, 0xb9,
+  0x8a, 0xb8, 0xaf, 0xea, 0xfc, 0x1f, 0x67, 0xe7, 0xba, 0xa3, 0xf1, 0x45,
+  0xbc, 0x2c, 0x58, 0x34, 0xa0, 0x94, 0x7d, 0xa6, 0x1b, 0x4c, 0xc8, 0xe3,
+  0xe3, 0x6f, 0xc0, 0xf0, 0x92, 0xdb, 0x0e, 0x12, 0x06, 0x12, 0x73, 0xd4,
+  0x21, 0x6c, 0x6f, 0x73, 0x19, 0xe6, 0x08, 0x1e, 0x11, 0x7f, 0x3d, 0x64,
+  0x0c, 0x41, 0x82, 0xa4, 0x1c, 0xd6, 0x39, 0xb1, 0x19, 0x89, 0xba, 0x59,
+  0x87, 0xdb, 0x17, 0x17, 0x30, 0xaa, 0xb5, 0xce, 0xdd, 0x2d, 0x91, 0x7e,
+  0xcb, 0xef, 0xc5, 0x97, 0x61, 0x40, 0x25, 0x0a, 0x87, 0x62, 0x40, 0xe5,
+  0x88, 0xd3, 0x5f, 0x8d, 0x7d, 0x4e, 0x37, 0x9b, 0x62, 0x98, 0xb0, 0x14,
+  0xb0, 0x16, 0xe0, 0xd0, 0x60, 0x19, 0x58, 0x1f, 0x04, 0x0c, 0xd4, 0xc3,
+  0xc4, 0xf8, 0x59, 0xb6, 0x87, 0x9b, 0x91, 0x96, 0xb0, 0x15, 0xca, 0x46,
+  0xdb, 0xa0, 0x55, 0x40, 0x31, 0x1d, 0xf8, 0x18, 0x4b, 0x04, 0x36, 0xd3,
+  0xa9, 0x6c, 0x7f, 0x85, 0x7d, 0x06, 0x02, 0x8d, 0x45, 0x1d, 0x02, 0x1c,
+  0xc0, 0x10, 0x3b, 0x4b, 0xfa, 0x37, 0x70, 0xc0, 0x7f, 0xd2, 0x06, 0xc2,
+  0x82, 0x61, 0x20, 0x79, 0xa3, 0x82, 0xe0, 0xff, 0xe0, 0xdd, 0xcc, 0xfa,
+  0xbf, 0xe7, 0x95, 0x96, 0x37, 0x65, 0xa1, 0xec, 0xfb, 0x01, 0xee, 0x0e,
+  0x17, 0x50, 0x56, 0x5a, 0x0c, 0x70, 0xd3, 0x3e, 0x89, 0x36, 0xae, 0x38,
+  0xef, 0xca, 0xa2, 0x3b, 0xc2, 0x62, 0x41, 0x00, 0x03, 0x7c, 0x01, 0x83,
+  0xb0, 0x61, 0x04, 0xbc, 0x41, 0x67, 0xfb, 0xe6, 0x70, 0xa8, 0xaf, 0x6d,
+  0xf9, 0x2b, 0x7a, 0x2a, 0xa6, 0x41, 0x84, 0x30, 0x36, 0x3f, 0xd5, 0x7f,
+  0x2e, 0xd2, 0xc4, 0x7e, 0xc1, 0x06, 0x76, 0x5e, 0xac, 0x0c, 0x09, 0x4f,
+  0x5b, 0x9a, 0x47, 0xe3, 0x7d, 0x05, 0xb3, 0x62, 0x81, 0x0b, 0xd2, 0xf9,
+  0xa9, 0xab, 0xaf, 0x34, 0xa7, 0x51, 0x9f, 0x38, 0x0c, 0xac, 0x18, 0x4b,
+  0x11, 0x81, 0x01, 0x8f, 0xb1, 0xdf, 0x17, 0x8e, 0xee, 0x52, 0xc1, 0xe6,
+  0x2e, 0xa2, 0xf1, 0x1a, 0x70, 0x63, 0x4d, 0x03, 0xe5, 0xff, 0xf6, 0x78,
+  0x20, 0x83, 0x0e, 0xc4, 0x31, 0x24, 0x0c, 0x34, 0xcb, 0x63, 0xe2, 0xee,
+  0x70, 0x3e, 0x63, 0x54, 0x29, 0x25, 0xff, 0xf0, 0xaf, 0x43, 0x40, 0x48,
+  0x1f, 0x87, 0x77, 0xb6, 0xdb, 0x6a, 0x1d, 0x5e, 0x8d, 0x4d, 0xaf, 0x70,
+  0xb6, 0xa0, 0x6b, 0x08, 0x61, 0x0c, 0x7e, 0x07, 0xd2, 0xd4, 0xa3, 0xf6,
+  0xcb, 0x75, 0x16, 0x64, 0x2a, 0x69, 0x8f, 0x20, 0x69, 0x8f, 0x0d, 0x9a,
+  0xc3, 0x07, 0xd8, 0x59, 0x07, 0x99, 0xae, 0x64, 0x3e, 0x9b, 0x6c, 0x5f,
+  0x48, 0x2b, 0x4f, 0xd0, 0xe9, 0x25, 0x79, 0x2a, 0xac, 0x37, 0x20, 0x66,
+  0x41, 0x6b, 0x43, 0x48, 0xa2, 0xa7, 0x62, 0x7f, 0x85, 0x97, 0xf9, 0x36,
+  0xd4, 0x52, 0x5b, 0x27, 0x68, 0x6d, 0x82, 0x63, 0x23, 0xd4, 0x9f, 0x12,
+  0x87, 0xe9, 0x03, 0xf1, 0xd3, 0x25, 0xf9, 0x3c, 0x20, 0x2a, 0xd6, 0xb7,
+  0x89, 0x3f, 0x2c, 0xbd, 0xa0, 0x61, 0x4e, 0xc0, 0x54, 0x30, 0x1e, 0x0d,
+  0xcc, 0x8d, 0x02, 0xe0, 0x33, 0x56, 0x7c, 0x10, 0x07, 0x55, 0x19, 0x56,
+  0xe6, 0x9b, 0xef, 0xbf, 0x70, 0x1f, 0x5e, 0x00, 0x52, 0x15, 0x2f, 0x5e,
+  0x58, 0xb1, 0xb3, 0x40, 0xca, 0x5a, 0xf2, 0x62, 0xd2, 0xc8, 0xa2, 0x28,
+  0x9a, 0x5d, 0xf5, 0xac, 0xb6, 0xc9, 0xce, 0x69, 0x59, 0x50, 0x72, 0x64,
+  0x2c, 0x29, 0x2e, 0x2f, 0x61, 0xb0, 0x6e, 0x7e, 0xa4, 0x4e, 0x59, 0x40,
+  0xb7, 0xd4, 0x73, 0x49, 0x4a, 0x8a, 0xd4, 0x19, 0x26, 0x23, 0x8f, 0x18,
+  0x1f, 0xa4, 0x6f, 0x2c, 0x0f, 0x67, 0xba, 0xd5, 0x42, 0xa6, 0x22, 0x9d,
+  0x1a, 0x87, 0x71, 0xd4, 0x4b, 0xe5, 0x7b, 0x6f, 0xa3, 0x5c, 0xdb, 0xf5,
+  0x25, 0xbd, 0xe6, 0xa2, 0xab, 0x28, 0x11, 0x75, 0xf7, 0xfa, 0x89, 0x63,
+  0x85, 0x3d, 0x31, 0xda, 0xa1, 0x1c, 0x20, 0xaa, 0x66, 0xb4, 0xad, 0x3f,
+  0x6c, 0xcc, 0xcd, 0x0f, 0xf2, 0x55, 0xe5, 0x47, 0x37, 0x14, 0x6e, 0xe0,
+  0x2d, 0xd6, 0x68, 0x20, 0xe8, 0x29, 0xbe, 0xd3, 0x21, 0xe5, 0xf9, 0x66,
+  0x0e, 0x5a, 0xbc, 0xca, 0xbc, 0x97, 0x81, 0xc6, 0x99, 0x16, 0xab, 0x2c,
+  0x6f, 0x9f, 0x6d, 0xbf, 0x4f, 0xf9, 0x66, 0xe6, 0x0d, 0xed, 0x40, 0xb0,
+  0x88, 0x54, 0x7c, 0x73, 0xbe, 0x1b, 0x60, 0x22, 0xa8, 0x54, 0xa0, 0x3f,
+  0xdf, 0x7d, 0x78, 0x89, 0x1f, 0x44, 0x42, 0x33, 0xff, 0xf4, 0x05, 0xaa,
+  0x5d, 0x5b, 0x36, 0x10, 0xd5, 0x35, 0x90, 0x3f, 0x6b, 0xf7, 0x18, 0xdd,
+  0xc2, 0xdf, 0x72, 0xe9, 0x65, 0xa0, 0x54, 0xa8, 0xae, 0x62, 0x90, 0xec,
+  0x1c, 0x64, 0x42, 0x3e, 0x12, 0x1b, 0xcd, 0x2c, 0xe7, 0x3f, 0xfe, 0x8e,
+  0x16, 0xeb, 0x4d, 0xf5, 0x15, 0xee, 0x08, 0xaa, 0x00, 0x49, 0x31, 0xf3,
+  0x43, 0xc6, 0xfa, 0x38, 0x6d, 0x4d, 0x51, 0x54, 0x45, 0x2b, 0x20, 0x5e,
+  0x06, 0xc7, 0x42, 0xd8, 0x40, 0x1c, 0x82, 0x20, 0x19, 0xde, 0xf3, 0xfb,
+  0x3d, 0x10, 0xe6, 0x14, 0x89, 0x8b, 0xd6, 0xeb, 0x72, 0x78, 0x82, 0xca,
+  0x16, 0xbf, 0x00, 0x00, 0x99, 0x08, 0x2c, 0x2c, 0x88, 0x5a, 0x0f, 0x05,
+  0x00, 0xd8, 0xea, 0x23, 0xa0, 0xa6, 0x2e, 0x19, 0x40, 0xf8, 0xc1, 0x66,
+  0xe6, 0xa2, 0x9b, 0x7c, 0x4a, 0x43, 0x22, 0x52, 0x8f, 0x08, 0xc2, 0x57,
+  0x06, 0xf4, 0x78, 0x5c, 0x0f, 0x17, 0x00, 0x6c, 0x3a, 0xbb, 0x6a, 0xd4,
+  0x23, 0x19, 0x04, 0xa2, 0x82, 0x51, 0x13, 0x9b, 0x31, 0x8c, 0x66, 0x76,
+  0x4f, 0xdb, 0xab, 0xaf, 0xc5, 0x86, 0x01, 0x6c, 0xc5, 0x4d, 0x35, 0xf0,
+  0xe6, 0xac, 0x37, 0x93, 0xa7, 0x14, 0x6a, 0xee, 0xd9, 0x7b, 0x02, 0x22,
+  0xb5, 0x65, 0xd1, 0x84, 0xc9, 0x87, 0x21, 0xe6, 0xd7, 0x1e, 0xea, 0xc3,
+  0x45, 0x53, 0x08, 0x31, 0x57, 0xfe, 0xc2, 0x06, 0x73, 0xbd, 0x5e, 0x58,
+  0x59, 0x7b, 0x02, 0x83, 0x42, 0x4f, 0xd1, 0x41, 0x58, 0xa0, 0xb9, 0x57,
+  0xa0, 0x8d, 0x24, 0x02, 0xb9, 0x7f, 0x4a, 0x6f, 0x29, 0xf7, 0xa4, 0x35,
+  0xe9, 0x93, 0x4c, 0x3d, 0x2d, 0xe1, 0x6c, 0x51, 0x69, 0x27, 0x20, 0xc0,
+  0x12, 0x8b, 0xa7, 0x5b, 0xda, 0xa1, 0x69, 0xca, 0x4a, 0xb9, 0xf1, 0xae,
+  0xfa, 0xf9, 0x9d, 0xca, 0x36, 0xf8, 0xba, 0x55, 0xe5, 0x06, 0x13, 0x0a,
+  0x30, 0xad, 0x8c, 0xcb, 0x66, 0xd9, 0xce, 0xa0, 0x9c, 0x90, 0x8d, 0xd1,
+  0x98, 0xa9, 0x8d, 0xd1, 0x3c, 0x50, 0x3a, 0xef, 0xe1, 0x65, 0x44, 0x13,
+  0x12, 0x9e, 0xca, 0x20, 0xea, 0x9f, 0x6c, 0x62, 0x55, 0x3c, 0xfa, 0x14,
+  0x73, 0xa5, 0x40, 0x90, 0x2f, 0x12, 0x3d, 0xd1, 0xf3, 0x4a, 0xd6, 0xbf,
+  0x67, 0x27, 0xcb, 0x62, 0x2b, 0x96, 0x07, 0x9c, 0x0d, 0x94, 0x3e, 0xfb,
+  0x08, 0x6d, 0x45, 0x96, 0xc5, 0x9d, 0x26, 0x97, 0xcd, 0xd9, 0xa8, 0xcf,
+  0xac, 0x3f, 0x57, 0xe6, 0x9a, 0xe5, 0xb7, 0x2e, 0xad, 0x14, 0x73, 0xb3,
+  0xb1, 0x1c, 0x0b, 0x53, 0x2c, 0xe7, 0xc1, 0x97, 0xbf, 0x55, 0x11, 0x37,
+  0xf9, 0x3f, 0xbd, 0xe5, 0xe7, 0x96, 0xb2, 0x06, 0xb9, 0xd3, 0x10, 0xcd,
+  0xbe, 0x03, 0x1e, 0x88, 0x94, 0x07, 0xd8, 0x36, 0x88, 0xd1, 0x06, 0x60,
+  0x2c, 0xf2, 0x41, 0x03, 0x0b, 0x2f, 0x8b, 0x69, 0x5c, 0x52, 0xa7, 0x54,
+  0xe8, 0x2b, 0xfa, 0x16, 0x13, 0x4f, 0x97, 0xe2, 0x0e, 0xf6, 0xf3, 0xcc,
+  0xf9, 0x5c, 0xe2, 0xdd, 0x92, 0xae, 0xe7, 0x19, 0x0b, 0xcb, 0xe2, 0x5c,
+  0x51, 0x72, 0xf3, 0x07, 0x1f, 0x6a, 0x7b, 0xf2, 0xf3, 0x92, 0xca, 0x81,
+  0x48, 0xa4, 0x71, 0x5a, 0xd5, 0x43, 0xdd, 0xd5, 0xaf, 0xb0, 0x3e, 0x52,
+  0xd9, 0xbf, 0x7f, 0xc0, 0xe2, 0xae, 0x29, 0x50, 0x0b, 0x75, 0x07, 0xaa,
+  0x44, 0x00, 0x65, 0xe9, 0x53, 0x2a, 0x14, 0x64, 0xed, 0xda, 0xb8, 0x79,
+  0x7d, 0x30, 0x45, 0x11, 0x7e, 0x04, 0x40, 0x48, 0xbf, 0x4a, 0x87, 0x9f,
+  0x83, 0x6b, 0xe6, 0xe2, 0xa6, 0x90, 0x4f, 0xf2, 0xf3, 0xd6, 0xc1, 0x10,
+  0xab, 0xa0, 0xc3, 0x56, 0xfa, 0x72, 0xc5, 0x96, 0x23, 0xb0, 0x6c, 0x6e,
+  0x1a, 0x36, 0x0e, 0x30, 0xa5, 0x0f, 0x65, 0xf7, 0x7b, 0xce, 0x59, 0x45,
+  0x6d, 0x68, 0x59, 0x22, 0x2e, 0x28, 0x19, 0x47, 0x2a, 0xc7, 0xc1, 0x5a,
+  0xdb, 0x00, 0x42, 0xf6, 0x14, 0x52, 0x38, 0x79, 0x74, 0x5b, 0xd5, 0x4b,
+  0x59, 0xbf, 0xf5, 0x19, 0xca, 0x28, 0x41, 0x55, 0xea, 0x56, 0x17, 0xe4,
+  0xfe, 0xe7, 0xaa, 0xd2, 0xde, 0xdb, 0x17, 0x9d, 0x1b, 0x19, 0x5a, 0xd2,
+  0xc0, 0x62, 0xde, 0x2d, 0x4b, 0x7d, 0x46, 0x56, 0x57, 0xca, 0x9b, 0x55,
+  0x4f, 0xe0, 0xdf, 0xb8, 0x32, 0x7f, 0xc7, 0xa6, 0x45, 0x2f, 0x14, 0xec,
+  0xe5, 0x67, 0x7c, 0x89, 0x47, 0xa6, 0x2e, 0x81, 0x75, 0x2a, 0x02, 0xd0,
+  0xe0, 0x0d, 0x71, 0x92, 0xf0, 0x84, 0x21, 0x96, 0x97, 0x5c, 0xac, 0x31,
+  0xa5, 0x9b, 0x7f, 0x2a, 0xfd, 0x45, 0x6e, 0x08, 0xa0, 0xc1, 0x21, 0x5c,
+  0x04, 0x54, 0xa5, 0x8c, 0xaa, 0xc2, 0xd9, 0x64, 0x1c, 0xcb, 0xdc, 0xaa,
+  0x79, 0xdb, 0xcf, 0x83, 0x8c, 0x85, 0x66, 0xda, 0xd6, 0x58, 0xd9, 0xf9,
+  0xd0, 0xf1, 0x43, 0x71, 0x1e, 0x6f, 0x62, 0x10, 0x5b, 0xca, 0x29, 0x16,
+  0xb0, 0x6e, 0xc1, 0xf3, 0x0a, 0xd3, 0x36, 0xce, 0xa7, 0xf7, 0x93, 0xf8,
+  0x18, 0x44, 0xbc, 0x97, 0x60, 0x30, 0x4e, 0xa2, 0x41, 0x23, 0xcc, 0xaa,
+  0x56, 0xaf, 0xe5, 0xfe, 0x55, 0x58, 0x45, 0x9b, 0x17, 0xd3, 0x52, 0x15,
+  0x98, 0x0a, 0xa0, 0xcd, 0x83, 0x0f, 0xb4, 0x75, 0xb8, 0x5e, 0xc2, 0xe9,
+  0x2f, 0xfb, 0xa6, 0xda, 0x9d, 0x45, 0xd4, 0x24, 0x61, 0xa5, 0x29, 0x77,
+  0xa2, 0xba, 0x20, 0x5e, 0xaa, 0x9c, 0xe2, 0xfd, 0xb5, 0xe6, 0xbd, 0x8c,
+  0x1b, 0x53, 0x78, 0xa6, 0xf4, 0x32, 0x15, 0xa9, 0xc3, 0xe8, 0x2b, 0xc5,
+  0xde, 0xbe, 0x4b, 0x0c, 0xb7, 0x78, 0xf2, 0x1e, 0x30, 0x5e, 0x39, 0x39,
+  0x84, 0x7f, 0x36, 0x32, 0xa9, 0x1d, 0xff, 0x0f, 0x6f, 0x6c, 0xa2, 0x61,
+  0x62, 0x1a, 0x84, 0x98, 0xbb, 0x00, 0x58, 0xfa, 0xdf, 0xab, 0x53, 0x63,
+  0x12, 0x18, 0xec, 0x54, 0xd8, 0xc1, 0xbf, 0x00, 0x90, 0xae, 0x0c, 0x90,
+  0x03, 0xda, 0x1e, 0x16, 0x8e, 0x93, 0xa9, 0x50, 0xdb, 0x73, 0xed, 0x59,
+  0x2e, 0x95, 0xd9, 0xcd, 0x9c, 0x41, 0x8b, 0x02, 0x48, 0xb5, 0x38, 0xf9,
+  0x5e, 0x49, 0xff, 0xf9, 0x6e, 0x45, 0xc9, 0x09, 0xc3, 0x2e, 0xfa, 0x8d,
+  0xf1, 0x18, 0xbc, 0x4c, 0x55, 0x52, 0xc7, 0xdc, 0xb3, 0xb8, 0xb9, 0xe6,
+  0xc2, 0x39, 0x6e, 0x55, 0xe5, 0x09, 0x47, 0xe5, 0xec, 0x64, 0x4f, 0xf6,
+  0x43, 0xa6, 0xad, 0xbd, 0x50, 0x88, 0x96, 0x83, 0x8c, 0x83, 0x31, 0x20,
+  0x28, 0x44, 0x32, 0xe8, 0xa3, 0xb8, 0xdc, 0xe0, 0x30, 0x8b, 0x2d, 0xe4,
+  0x29, 0xcd, 0x31, 0x49, 0xc2, 0x18, 0x8e, 0x25, 0x95, 0x5b, 0x3c, 0xd2,
+  0x25, 0x0d, 0x15, 0x41, 0x88, 0x24, 0x92, 0xca, 0x59, 0xb9, 0x16, 0x3a,
+  0x5d, 0x6c, 0x2d, 0x6c, 0x30, 0x8e, 0xc4, 0x74, 0xcc, 0x5d, 0x85, 0xda,
+  0xdd, 0x56, 0xb5, 0x8a, 0xf3, 0x79, 0x99, 0x67, 0x65, 0xf5, 0x9b, 0x9a,
+  0xa4, 0x8d, 0x00, 0x84, 0x3b, 0x06, 0xee, 0x6a, 0xa6, 0x4b, 0x04, 0x14,
+  0x3b, 0xa8, 0xdb, 0x88, 0xd6, 0xe1, 0x40, 0x24, 0x26, 0x3e, 0x12, 0xbf,
+  0xfa, 0xa3, 0x1a, 0x2d, 0x5c, 0x3d, 0xab, 0xdb, 0x0d, 0xf1, 0x46, 0x7f,
+  0x54, 0x83, 0x04, 0xa2, 0x3a, 0x0c, 0x3e, 0x2f, 0x1f, 0x87, 0xaa, 0x93,
+  0x02, 0x9b, 0x99, 0xc9, 0x7a, 0x59, 0x94, 0xd5, 0x2c, 0xd0, 0x56, 0xdb,
+  0xa1, 0xce, 0xe0, 0xb0, 0x60, 0xfd, 0x3e, 0xd8, 0xb3, 0xe1, 0x0d, 0x50,
+  0x1a, 0xa3, 0xe5, 0x4d, 0x07, 0xdc, 0xd8, 0x0a, 0xd9, 0x38, 0x89, 0x6e,
+  0x70, 0x37, 0x04, 0x90, 0xbc, 0x0a, 0x45, 0x7e, 0xf8, 0xf1, 0x40, 0xe4,
+  0xb7, 0xfe, 0xfe, 0xa9, 0x52, 0x55, 0x39, 0x7b, 0x57, 0x06, 0x09, 0x51,
+  0x4c, 0x0c, 0x5c, 0x23, 0x8f, 0x9a, 0xcd, 0x4a, 0x94, 0x7c, 0xc6, 0x29,
+  0x52, 0xdd, 0x56, 0x37, 0x6f, 0x2a, 0xfc, 0x8a, 0x0a, 0xd4, 0xe8, 0x6c,
+  0x5a, 0x2d, 0x58, 0x1c, 0x91, 0x54, 0x0f, 0x87, 0xdb, 0x83, 0x91, 0x17,
+  0xd8, 0x91, 0xbb, 0xfe, 0x22, 0x9c, 0xf6, 0xef, 0xd3, 0xee, 0x86, 0xe1,
+  0xf0, 0x30, 0xc0, 0x58, 0x54, 0xdf, 0x49, 0x0e, 0xd1, 0x04, 0xf3, 0x67,
+  0xc7, 0xcc, 0xcf, 0x0e, 0x8b, 0xb7, 0x6a, 0x89, 0x0b, 0x95, 0x12, 0xa2,
+  0x6a, 0x1c, 0x6c, 0x4f, 0xa5, 0x64, 0x3f, 0xdc, 0x83, 0x88, 0x36, 0xcd,
+  0x42, 0x4a, 0xe1, 0xe0, 0x29, 0xda, 0xc2, 0xe6, 0x95, 0xa5, 0xf9, 0x60,
+  0xf8, 0x74, 0x99, 0x36, 0xb3, 0x50, 0xda, 0x59, 0x24, 0xf4, 0x80, 0xc8,
+  0x77, 0x4f, 0xac, 0x23, 0x03, 0x02, 0x18, 0x84, 0xad, 0x2a, 0x61, 0xf0,
+  0x7c, 0xda, 0xa0, 0x37, 0xbf, 0xcd, 0x65, 0xbb, 0x27, 0xb3, 0x7b, 0xc4,
+  0xd0, 0x1e, 0x23, 0xff, 0x70, 0xe4, 0x3c, 0x2c, 0x06, 0x15, 0xb6, 0x11,
+  0xbc, 0xd2, 0x26, 0xc5, 0x7e, 0xf6, 0x62, 0x29, 0x30, 0xa0, 0xe5, 0xab,
+  0xde, 0x70, 0x98, 0x24, 0xe7, 0xe1, 0x27, 0x0d, 0xf4, 0xe1, 0xd5, 0x6a,
+  0xcb, 0x7e, 0x59, 0xde, 0xe7, 0x8b, 0x69, 0xa2, 0xb9, 0xde, 0xd0, 0xd0,
+  0x1f, 0x3f, 0xff, 0xb8, 0x44, 0x51, 0xf6, 0xfa, 0x75, 0x55, 0x3e, 0xe6,
+  0x7a, 0x77, 0x7a, 0xe2, 0x6c, 0x45, 0x0a, 0x9a, 0xf0, 0x70, 0xc6, 0x4a,
+  0x53, 0xc7, 0x2b, 0xf6, 0x6a, 0x89, 0xef, 0x5e, 0x2c, 0x1e, 0xd4, 0x6b,
+  0x9a, 0x07, 0x18, 0x51, 0x33, 0x65, 0xa9, 0x9a, 0xf9, 0xbf, 0x40, 0xa3,
+  0xe9, 0x1d, 0x7a, 0x64, 0xc7, 0xac, 0x29, 0xe2, 0x39, 0xcb, 0x57, 0x8b,
+  0x53, 0xc3, 0xd1, 0x2f, 0xfa, 0xa8, 0x7c, 0xb6, 0xc6, 0xd7, 0x8b, 0x22,
+  0xb6, 0x72, 0x86, 0xa0, 0x24, 0xbf, 0xfa, 0x5b, 0xd1, 0x11, 0x7e, 0xc1,
+  0x59, 0x90, 0x3b, 0x58, 0x03, 0x39, 0xbb, 0x25, 0x63, 0x8c, 0xe6, 0x08,
+  0xbd, 0x2d, 0xe7, 0x78, 0x1c, 0x2d, 0x4c, 0x7c, 0x06, 0x0a, 0xd9, 0x31,
+  0x98, 0x90, 0x23, 0x8e, 0xc7, 0x60, 0x1c, 0x9c, 0x70, 0x5c, 0xd3, 0x0d,
+  0xb3, 0xa9, 0x58, 0x0f, 0x6d, 0x0e, 0xa7, 0xcb, 0x27, 0xe5, 0xd0, 0xdb,
+  0xa3, 0x60, 0xec, 0x2c, 0x0a, 0xe2, 0x50, 0xfd, 0xb5, 0x41, 0x08, 0x4a,
+  0x49, 0x9e, 0xd6, 0x77, 0xde, 0xf6, 0x5d, 0x5a, 0x4f, 0x2a, 0x61, 0x61,
+  0xcf, 0xd4, 0x96, 0x0d, 0xfb, 0x0a, 0x83, 0x50, 0x62, 0x61, 0x6a, 0x44,
+  0x94, 0xb8, 0xab, 0x57, 0xf7, 0xf9, 0xb9, 0xc4, 0x39, 0x65, 0xbc, 0x0d,
+  0x4e, 0xf0, 0x38, 0xc3, 0x7d, 0x1f, 0xeb, 0x3f, 0x80, 0x6b, 0xe5, 0x90,
+  0xb9, 0xa2, 0xce, 0x6a, 0xa6, 0x18, 0x40, 0xc9, 0x59, 0x5e, 0xee, 0xf7,
+  0x41, 0x84, 0xe4, 0xf1, 0x47, 0x85, 0x7d, 0x8a, 0x38, 0x1f, 0xb7, 0xee,
+  0xd5, 0x18, 0xa2, 0xdb, 0xc5, 0xef, 0x65, 0xce, 0xae, 0x1b, 0x9f, 0xb4,
+  0xe1, 0x00, 0x7d, 0xfb, 0x6f, 0xf3, 0x76, 0xde, 0x73, 0x54, 0xde, 0xcc,
+  0x35, 0x04, 0x43, 0x18, 0x79, 0x7a, 0xd6, 0xa5, 0xd9, 0xc0, 0x45, 0x19,
+  0x87, 0x93, 0xb3, 0xd0, 0x09, 0xe4, 0x0b, 0x4a, 0xa8, 0xa8, 0xd6, 0xe0,
+  0x14, 0x25, 0x71, 0xce, 0x58, 0xbc, 0xbd, 0x32, 0x44, 0x8d, 0x08, 0x1e,
+  0x2a, 0x44, 0xa1, 0x0f, 0xff, 0xa6, 0xed, 0x42, 0x62, 0xb3, 0x40, 0xb6,
+  0xff, 0x81, 0xef, 0x3d, 0xa8, 0x0a, 0xe4, 0x44, 0x78, 0x8a, 0x74, 0xde,
+  0x4e, 0x37, 0x1b, 0xc9, 0x14, 0x14, 0xb8, 0x6c, 0xcf, 0x84, 0x0b, 0x2d,
+  0x58, 0x44, 0xfd, 0x25, 0x95, 0x18, 0x55, 0x70, 0xbc, 0xb4, 0x9b, 0xd2,
+  0xcc, 0xd6, 0x3e, 0x57, 0x7d, 0xf5, 0x2d, 0x72, 0xce, 0xa8, 0xab, 0x88,
+  0xa1, 0xc6, 0x74, 0x05, 0x9c, 0x4b, 0x75, 0xb1, 0xf2, 0x55, 0x5a, 0x05,
+  0xd4, 0x41, 0xea, 0xa8, 0x0c, 0x1b, 0x74, 0x1c, 0xa5, 0x4f, 0x70, 0x18,
+  0x4d, 0x29, 0x6a, 0x9c, 0x9b, 0xe8, 0x5a, 0x36, 0xe0, 0x89, 0x64, 0xfa,
+  0xdd, 0xe8, 0x69, 0x41, 0x20, 0xba, 0x7c, 0x50, 0x9c, 0x4a, 0xad, 0x48,
+  0xa2, 0xc9, 0x93, 0x09, 0x0b, 0x29, 0x6f, 0x43, 0x5c, 0xe6, 0x89, 0xf7,
+  0x20, 0xb4, 0xa6, 0x96, 0xcf, 0x6f, 0xd1, 0xd8, 0x50, 0x75, 0x5d, 0xf5,
+  0x04, 0x52, 0xdf, 0x2d, 0xcf, 0x02, 0xb4, 0xd4, 0xcb, 0x62, 0x30, 0xa9,
+  0x4c, 0x6f, 0xd0, 0x72, 0x9a, 0x6c, 0x9b, 0x9f, 0xb7, 0xc5, 0xab, 0x4b,
+  0x2a, 0xf0, 0xf1, 0x50, 0xef, 0xb1, 0x9f, 0x45, 0xe5, 0x28, 0x50, 0x48,
+  0x15, 0x72, 0xca, 0x0e, 0x30, 0x3f, 0x6e, 0x37, 0xc5, 0x0d, 0xb5, 0xed,
+  0x24, 0xef, 0x39, 0xc0, 0xad, 0x6e, 0xe6, 0x26, 0xf2, 0x08, 0x5b, 0xc3,
+  0x6b, 0x74, 0x99, 0x55, 0x20, 0xa6, 0xfe, 0x78, 0x0b, 0xb1, 0x50, 0x7d,
+  0x7f, 0xcc, 0x9c, 0x0f, 0x7d, 0x44, 0x5c, 0x0b, 0x14, 0x4b, 0x04, 0x01,
+  0x05, 0x42, 0xec, 0x6e, 0x46, 0x70, 0xa6, 0x70, 0xb6, 0x74, 0x18, 0x2b,
+  0xf2, 0xcb, 0x0e, 0x99, 0xe0, 0xeb, 0xde, 0x9c, 0x9f, 0xcd, 0xad, 0x12,
+  0xcc, 0x9d, 0x5e, 0x40, 0xe0, 0x89, 0x02, 0x44, 0x1b, 0xce, 0xd0, 0xdc,
+  0x98, 0xf8, 0xf1, 0xa9, 0xf6, 0x55, 0xa6, 0x67, 0x79, 0x54, 0xa9, 0xf7,
+  0xf8, 0x56, 0xbf, 0x2a, 0xc3, 0x51, 0x18, 0x37, 0x18, 0xf4, 0x0e, 0xdb,
+  0xd1, 0x7d, 0xe9, 0xa0, 0xd8, 0x85, 0xae, 0x0d, 0x9c, 0x58, 0x2d, 0x01,
+  0xa8, 0xf1, 0xb1, 0xf8, 0x40, 0x1f, 0xaa, 0x69, 0x7e, 0xfa, 0x95, 0x73,
+  0xb7, 0xa2, 0xa0, 0x7b, 0xfd, 0xaf, 0xfb, 0x77, 0x3f, 0xd9, 0xfc, 0xb6,
+  0x6c, 0xd5, 0xaf, 0x62, 0x37, 0x0b, 0xd9, 0xff, 0x94, 0xdc, 0xcf, 0xde,
+  0x14, 0xf6, 0x1f, 0x08, 0xa0, 0xc1, 0x0c, 0x21, 0x07, 0xc9, 0xc1, 0x8b,
+  0x55, 0x07, 0x4a, 0xf9, 0x15, 0xa0, 0x0f, 0x78, 0x47, 0x12, 0xba, 0xd2,
+  0xd3, 0x08, 0xa8, 0xeb, 0xc3, 0xc0, 0xb5, 0x49, 0x9d, 0x7c, 0x7b, 0x4f,
+  0x05, 0x85, 0x7c, 0x2c, 0x21, 0x18, 0x5a, 0x21, 0xa5, 0x16, 0xf5, 0xe5,
+  0x9a, 0x2e, 0xdf, 0xf3, 0xcb, 0x4f, 0xac, 0x55, 0xb6, 0x79, 0x64, 0x40,
+  0x97, 0x76, 0xe1, 0x96, 0x25, 0xce, 0xa1, 0x87, 0x86, 0xbf, 0x23, 0x0b,
+  0xc9, 0x04, 0x64, 0xcc, 0x07, 0x96, 0x62, 0xbd, 0xb8, 0x39, 0x6d, 0xba,
+  0x54, 0xc3, 0x52, 0x72, 0x70, 0x0a, 0x8e, 0x75, 0x7a, 0x55, 0x81, 0xc0,
+  0x31, 0x18, 0x7a, 0xaa, 0x87, 0x23, 0xff, 0xb5, 0xe2, 0xbf, 0x46, 0x76,
+  0x29, 0x41, 0xc9, 0xfb, 0x21, 0xe2, 0xf7, 0xca, 0x24, 0x05, 0xba, 0xd3,
+  0x8d, 0xe4, 0x8b, 0x80, 0x53, 0x6c, 0xa9, 0x46, 0x9a, 0xb0, 0x60, 0x7c,
+  0x52, 0x0c, 0xa1, 0x52, 0x61, 0xf6, 0xeb, 0x65, 0xbe, 0xde, 0xc1, 0xc0,
+  0x71, 0xb2, 0x2c, 0x88, 0x1c, 0x64, 0x67, 0xf5, 0x45, 0xb3, 0x70, 0x92,
+  0xd1, 0xa4, 0xb9, 0x73, 0x9d, 0x80, 0x92, 0xc8, 0xb8, 0xb0, 0x24, 0xb6,
+  0x56, 0x81, 0xf4, 0xbe, 0xb7, 0x15, 0x2f, 0x96, 0xa9, 0xee, 0xfa, 0x22,
+  0xa8, 0x2a, 0x95, 0x2a, 0x4c, 0x05, 0x76, 0x01, 0x84, 0x01, 0xea, 0x46,
+  0xd3, 0xa7, 0x98, 0x3e, 0x65, 0xab, 0x3d, 0x54, 0x2c, 0xd6, 0xed, 0x9d,
+  0x2d, 0x9e, 0x11, 0x75, 0x67, 0xa2, 0x10, 0x1a, 0x85, 0xe5, 0x4c, 0x0f,
+  0x07, 0xe9, 0x7f, 0x99, 0x39, 0xbe, 0x61, 0x4f, 0xbb, 0xc0, 0xea, 0xfd,
+  0x4a, 0x8c, 0xc0, 0xdc, 0x18, 0x80, 0x5d, 0x01, 0x87, 0x42, 0x3b, 0x69,
+  0xe6, 0xab, 0xf2, 0x65, 0x5e, 0xbf, 0xeb, 0x61, 0xec, 0xa5, 0x5d, 0x0e,
+  0xa0, 0xd8, 0x0c, 0xe0, 0x2d, 0x44, 0x77, 0x15, 0x28, 0x8a, 0x5b, 0x52,
+  0x0a, 0x80, 0x62, 0x14, 0x53, 0x21, 0x0b, 0x66, 0x70, 0x46, 0xc5, 0x61,
+  0xea, 0x6f, 0xe3, 0x71, 0x4a, 0x84, 0x5c, 0xbd, 0x14, 0x0b, 0x0b, 0x81,
+  0xbc, 0x3f, 0x57, 0x54, 0x0e, 0x19, 0xcf, 0x28, 0xed, 0x57, 0x24, 0xc9,
+  0xde, 0x74, 0xb3, 0xca, 0x46, 0xfa, 0x0e, 0xf1, 0x00, 0x54, 0x8c, 0x0f,
+  0x00, 0x39, 0xaf, 0x70, 0xb3, 0x2d, 0xc9, 0x9d, 0xdd, 0xac, 0x97, 0xfe,
+  0x44, 0x65, 0x8a, 0x4a, 0xb3, 0x31, 0x6d, 0x53, 0x85, 0x9e, 0x06, 0x21,
+  0x27, 0x34, 0x49, 0x6f, 0xc0, 0xf0, 0x50, 0x0c, 0xa6, 0xc9, 0x7f, 0x7d,
+  0x7c, 0xac, 0xbf, 0x64, 0xf4, 0x96, 0x77, 0xb3, 0xc0, 0xc8, 0x41, 0xc2,
+  0x28, 0x31, 0x18, 0xee, 0xa8, 0x40, 0x44, 0x79, 0x68, 0xa8, 0xb0, 0xb2,
+  0x21, 0x17, 0x0f, 0xc4, 0x64, 0xd5, 0xa4, 0x82, 0x41, 0x7a, 0xb4, 0xfb,
+  0x80, 0x5f, 0xfe, 0x69, 0x8b, 0x64, 0x0e, 0xa4, 0x51, 0xa5, 0x58, 0x8f,
+  0x42, 0xd2, 0xd8, 0x3c, 0x05, 0x09, 0x7d, 0xeb, 0x3e, 0x89, 0x32, 0x0d,
+  0x87, 0x2d, 0xc5, 0x0d, 0x0c, 0xb0, 0xb7, 0x5b, 0x07, 0x07, 0x80, 0x90,
+  0x5f, 0xd8, 0x23, 0x83, 0xc2, 0x7f, 0xd6, 0x23, 0xb4, 0xd4, 0x5c, 0xa8,
+  0xb9, 0x8f, 0x34, 0xde, 0xf1, 0x7e, 0x16, 0xe9, 0x68, 0xe3, 0x14, 0x4a,
+  0x0f, 0x9b, 0xff, 0xd9, 0xf1, 0xf8, 0x21, 0xfa, 0x7c, 0x70, 0xc4, 0xd1,
+  0xfa, 0x8a, 0x59, 0xc5, 0x3f, 0xb8, 0xb2, 0x0a, 0x1f, 0x03, 0x02, 0x4e,
+  0xf5, 0xf6, 0x6a, 0xa6, 0x2e, 0x8a, 0xf3, 0xba, 0x5e, 0x08, 0x23, 0xd9,
+  0xf4, 0x4d, 0x65, 0x05, 0x32, 0x98, 0x8e, 0x56, 0x74, 0x19, 0x06, 0x03,
+  0x06, 0xc1, 0xc1, 0x81, 0x52, 0x61, 0xf0, 0x1f, 0x5b, 0x80, 0xaa, 0x12,
+  0x32, 0xa3, 0x4c, 0x5c, 0xc4, 0x8d, 0xd2, 0x5f, 0xd5, 0x03, 0x70, 0x23,
+  0xa5, 0xbf, 0x06, 0x3a, 0x21, 0xf0, 0x96, 0xdf, 0x93, 0x63, 0x6c, 0xb0,
+  0x1f, 0x76, 0x75, 0xa5, 0x59, 0xe5, 0xe4, 0xbc, 0x0f, 0x68, 0x89, 0x99,
+  0xab, 0x16, 0x29, 0x06, 0x3a, 0xb5, 0xd0, 0x86, 0xae, 0x87, 0x8d, 0x6c,
+  0xc0, 0xdb, 0x92, 0xa8, 0xea, 0x3e, 0x87, 0x20, 0xc4, 0xe7, 0x57, 0x00,
+  0x00, 0xa3, 0x08, 0x6c, 0x98, 0x37, 0x15, 0x17, 0x84, 0x04, 0xc9, 0x9b,
+  0x63, 0x15, 0xb0, 0xca, 0xa4, 0xda, 0xce, 0x08, 0x92, 0xc5, 0x5e, 0xe0,
+  0x13, 0x04, 0xb0, 0xd6, 0x3b, 0x06, 0x08, 0x45, 0xd6, 0x7f, 0x47, 0x40,
+  0x63, 0xe8, 0xe7, 0xb7, 0xbb, 0xee, 0x92, 0x51, 0xbe, 0x03, 0xe5, 0xc0,
+  0x0e, 0x81, 0x75, 0x07, 0x82, 0x80, 0x64, 0xb9, 0x47, 0x38, 0x06, 0x98,
+  0x52, 0x81, 0x7a, 0xd3, 0x82, 0xae, 0xf6, 0x3c, 0x94, 0x27, 0xc5, 0xb0,
+  0xeb, 0x61, 0x58, 0x46, 0x56, 0xcd, 0x12, 0x93, 0x34, 0x9e, 0xe8, 0x29,
+  0xfd, 0x31, 0x51, 0x7a, 0x94, 0x7d, 0xf7, 0xb9, 0xc9, 0x44, 0x55, 0x3b,
+  0x14, 0xa9, 0x06, 0x21, 0x4b, 0x00, 0xbb, 0x66, 0xf8, 0xc8, 0x64, 0xf5,
+  0x65, 0xd5, 0x25, 0xb6, 0xec, 0x90, 0x6e, 0xba, 0xdb, 0xe4, 0x32, 0x86,
+  0x98, 0x57, 0xe0, 0x71, 0x8a, 0x4a, 0xac, 0x3e, 0x48, 0x5e, 0x5f, 0x8c,
+  0x56, 0xf5, 0xac, 0xad, 0xfa, 0x0d, 0x94, 0x87, 0x9c, 0xb3, 0xa1, 0xc2,
+  0x83, 0xe5, 0xf7, 0xae, 0x84, 0x29, 0x8d, 0x02, 0x18, 0x97, 0x82, 0x51,
+  0x73, 0x6a, 0xe8, 0xde, 0x74, 0x71, 0x8b, 0x77, 0xec, 0xa0, 0x81, 0x9e,
+  0x83, 0x09, 0x82, 0xf8, 0x33, 0x05, 0xed, 0x97, 0x80, 0x70, 0x8d, 0xf6,
+  0x7f, 0xd6, 0x59, 0x2e, 0x9b, 0xf4, 0x0b, 0xcf, 0xef, 0x8b, 0x64, 0x0e,
+  0x16, 0x70, 0x7b, 0x4e, 0x3d, 0x6c, 0x20, 0xd8, 0xad, 0x91, 0x13, 0xf9,
+  0x15, 0x01, 0x0f, 0x5b, 0x28, 0x78, 0x56, 0x37, 0x69, 0x48, 0x3e, 0x47,
+  0xff, 0x60, 0xb4, 0x10, 0x92, 0x7d, 0x85, 0x60, 0x19, 0xad, 0xb3, 0x41,
+  0xc9, 0x04, 0x88, 0x5d, 0xf4, 0xd8, 0xb3, 0x57, 0xe5, 0xe5, 0x97, 0xed,
+  0x86, 0xb9, 0xb2, 0x67, 0xb0, 0x1f, 0x23, 0xff, 0xb6, 0xc5, 0xba, 0xf8,
+  0xd8, 0xa7, 0x71, 0xe1, 0xf0, 0x4b, 0x69, 0x58, 0x38, 0x14, 0x6a, 0xd5,
+  0xe3, 0x3e, 0xd5, 0x57, 0x1a, 0x55, 0xf5, 0x57, 0x3b, 0x7b, 0xee, 0xc8,
+  0x1e, 0x86, 0xb7, 0xe5, 0x40, 0xb7, 0x32, 0x10, 0xc7, 0xe0, 0xca, 0x07,
+  0x49, 0xcb, 0xd0, 0xb1, 0x91, 0x41, 0x2e, 0xdb, 0x3d, 0x03, 0x30, 0x60,
+  0xa4, 0x30, 0xd0, 0x52, 0xe5, 0x6e, 0xd6, 0xa3, 0x69, 0x59, 0xaa, 0xd1,
+  0x62, 0xca, 0x76, 0xaf, 0x6d, 0xa0, 0xb4, 0x12, 0x4d, 0xe5, 0x56, 0x5d,
+  0x6e, 0xa8, 0x06, 0x26, 0x59, 0xc2, 0x14, 0xc2, 0xfb, 0x42, 0x4f, 0xbb,
+  0xe2, 0xa2, 0xcb, 0x99, 0x27, 0xa7, 0x4a, 0xa2, 0xdc, 0x9c, 0x06, 0x13,
+  0x15, 0x54, 0xad, 0x2a, 0x95, 0x3d, 0x37, 0xc8, 0x22, 0x73, 0xa0, 0xc1,
+  0x48, 0x47, 0x1d, 0x30, 0x39, 0x2c, 0xdb, 0x39, 0xbc, 0xce, 0xf2, 0x5d,
+  0xe6, 0xad, 0x6c, 0x58, 0x4e, 0x2a, 0x6f, 0xf1, 0xa6, 0xb1, 0x9f, 0xb0,
+  0x6a, 0x61, 0xbb, 0x79, 0xd9, 0x78, 0x1a, 0x39, 0xd9, 0x5b, 0xa4, 0xd0,
+  0xb1, 0x24, 0x2f, 0x03, 0x6d, 0x79, 0x07, 0xda, 0xb1, 0x64, 0x1c, 0xe2,
+  0x37, 0x6e, 0xd2, 0xd8, 0xcf, 0x6f, 0x72, 0x5c, 0xe0, 0x89, 0xcb, 0x65,
+  0x44, 0x1c, 0x9c, 0x3e, 0x20, 0xd4, 0xfb, 0x2a, 0x2e, 0x20, 0x0c, 0x4f,
+  0x6d, 0x66, 0xb1, 0x64, 0xfa, 0x14, 0x44, 0xae, 0x3d, 0xcf, 0x36, 0x80,
+  0xe6, 0xdb, 0x9b, 0xd5, 0x91, 0x14, 0x74, 0x84, 0x60, 0x3f, 0x53, 0xd6,
+  0x7c, 0x1c, 0x87, 0xad, 0x21, 0x9d, 0x88, 0x02, 0x94, 0x58, 0x57, 0x14,
+  0x95, 0xf2, 0xcb, 0xde, 0x62, 0x2a, 0xba, 0x23, 0xc8, 0xff, 0x27, 0x25,
+  0x8b, 0xdc, 0xea, 0x84, 0x15, 0x11, 0x33, 0xeb, 0x8e, 0x65, 0xd7, 0x6d,
+  0x03, 0x2e, 0xc7, 0x50, 0xc9, 0x71, 0x45, 0x47, 0x16, 0xe0, 0x3b, 0x0c,
+  0xab, 0x9b, 0xf5, 0x5e, 0x1f, 0x4d, 0x05, 0x68, 0x81, 0xaa, 0xf5, 0x5f,
+  0xf5, 0x17, 0xbb, 0xd2, 0xc9, 0x01, 0xc3, 0x60, 0xdc, 0xc1, 0x92, 0xdf,
+  0xb7, 0x8c, 0x5f, 0x77, 0x39, 0xa1, 0xea, 0x0e, 0xdb, 0x3b, 0xca, 0x1c,
+  0x98, 0x69, 0xf6, 0x4f, 0x36, 0x39, 0x2a, 0xdb, 0xf9, 0xfe, 0x7a, 0x42,
+  0xbf, 0x7a, 0xad, 0x39, 0x44, 0x5d, 0x30, 0xe7, 0xdc, 0xa5, 0x63, 0xdc,
+  0x53, 0x56, 0xde, 0x0c, 0xe3, 0xce, 0x5a, 0xdd, 0xd9, 0x16, 0xe3, 0x1e,
+  0xf6, 0x96, 0xd5, 0x94, 0xac, 0xbc, 0xe6, 0x15, 0x05, 0xa6, 0x77, 0xf8,
+  0x9c, 0x7c, 0xd7, 0xd8, 0xfd, 0xde, 0x5a, 0x1d, 0x87, 0x76, 0xc5, 0xaa,
+  0xc1, 0xb1, 0xe4, 0xda, 0x6c, 0x14, 0xec, 0x56, 0x2d, 0x51, 0xf5, 0x08,
+  0xf8, 0x32, 0xec, 0x0e, 0x40, 0x4f, 0x6d, 0x0d, 0xe3, 0x2a, 0x90, 0x29,
+  0xaa, 0x54, 0x51, 0x81, 0xc3, 0x41, 0xda, 0x6c, 0xf6, 0xc0, 0xf4, 0xb9,
+  0x7f, 0xfa, 0xae, 0x39, 0x61, 0x15, 0x82, 0xf7, 0x1b, 0x1f, 0x7e, 0xa9,
+  0xd1, 0xf3, 0x28, 0xe2, 0x9c, 0x88, 0x3b, 0x62, 0x38, 0x04, 0xc6, 0xe1,
+  0x69, 0x76, 0xbc, 0xdf, 0x87, 0xb1, 0x8a, 0x1d, 0x6f, 0xad, 0xc9, 0x50,
+  0x43, 0x41, 0xa0, 0x25, 0x46, 0x2d, 0xa9, 0x2c, 0x69, 0xa5, 0x7d, 0x46,
+  0xd5, 0x55, 0xbf, 0xcb, 0xdb, 0xd9, 0x7a, 0xc0, 0x13, 0x46, 0x60, 0x44,
+  0xab, 0xda, 0xa8, 0x7d, 0x6a, 0xbb, 0x77, 0x6e, 0x1b, 0x45, 0xde, 0x11,
+  0x98, 0x63, 0x8c, 0xe2, 0x52, 0xee, 0x5c, 0x9f, 0x56, 0xae, 0x7a, 0xa1,
+  0xc6, 0x65, 0x53, 0x2c, 0x0d, 0x70, 0xfb, 0x1d, 0x33, 0xa9, 0x4b, 0x9a,
+  0xea, 0xed, 0xaa, 0xd0, 0xf9, 0x94, 0x1d, 0xbe, 0x58, 0x1d, 0xa0, 0x93,
+  0x4a, 0x16, 0x58, 0xdc, 0xb4, 0x3f, 0x57, 0x15, 0x26, 0x8b, 0x45, 0xfe,
+  0x80, 0xa6, 0x05, 0x67, 0x41, 0x92, 0x8e, 0xa2, 0x50, 0x38, 0x96, 0xa0,
+  0x4c, 0xab, 0x74, 0xdd, 0xec, 0x44, 0x0c, 0x09, 0xa1, 0x7c, 0x3e, 0x05,
+  0x6c, 0xdc, 0xc9, 0xec, 0xc9, 0x14, 0x20, 0x29, 0xa7, 0x83, 0x08, 0x30,
+  0x96, 0xae, 0x60, 0x07, 0x08, 0xeb, 0xf0, 0x19, 0x6d, 0x18, 0xa2, 0x80,
+  0xc1, 0x5d, 0x2e, 0xc1, 0xd4, 0x6d, 0x08, 0x0f, 0x26, 0x20, 0x25, 0x24,
+  0xfa, 0x55, 0x6c, 0x30, 0xd6, 0x29, 0xfb, 0x7f, 0xcc, 0xf4, 0x25, 0xaf,
+  0xd1, 0x11, 0x2d, 0x78, 0x4d, 0x06, 0x05, 0x10, 0x42, 0xad, 0x97, 0xfc,
+  0x4b, 0xd8, 0x1e, 0x0f, 0xb2, 0x28, 0xb4, 0x18, 0x39, 0xfc, 0x45, 0x03,
+  0x4c, 0x07, 0x29, 0x30, 0xcc, 0xd8, 0x27, 0x8b, 0x81, 0x44, 0x25, 0x08,
+  0xca, 0x95, 0x03, 0x2c, 0xd7, 0xd2, 0xc6, 0xbb, 0xad, 0xec, 0xb7, 0xaa,
+  0xd6, 0xed, 0x85, 0x6b, 0x15, 0x80, 0x9a, 0x82, 0x37, 0x87, 0x0c, 0x32,
+  0x9d, 0x8c, 0x6d, 0x2a, 0x8a, 0x5b, 0xfd, 0xe6, 0xe4, 0xea, 0xfc, 0x93,
+  0x54, 0x85, 0x82, 0xc5, 0x6c, 0xa8, 0xd5, 0x05, 0x97, 0x50, 0xdb, 0x96,
+  0x52, 0xce, 0x93, 0xbf, 0xec, 0x04, 0x4f, 0xc5, 0x32, 0xff, 0xf2, 0x96,
+  0x67, 0x50, 0x8a, 0x48, 0xe4, 0x9c, 0x79, 0x64, 0xcd, 0x86, 0xc0, 0x61,
+  0x2c, 0x7a, 0x98, 0x4a, 0x2e, 0x2c, 0x4c, 0xa2, 0x0f, 0x52, 0x87, 0x8a,
+  0x31, 0x65, 0x1e, 0xa8, 0xff, 0x62, 0x00, 0x60, 0x8c, 0x35, 0x02, 0x88,
+  0x20, 0x36, 0xc9, 0x5a, 0x8e, 0xa1, 0xe2, 0x3b, 0x7a, 0x8a, 0x40, 0xe7,
+  0x4c, 0x9a, 0x2e, 0x06, 0x48, 0xcb, 0x25, 0xff, 0x2f, 0x08, 0x2c, 0xa9,
+  0x67, 0xff, 0xdf, 0x88, 0x1e, 0xed, 0xfc, 0x95, 0x12, 0xe2, 0x22, 0x90,
+  0x7c, 0x78, 0x01, 0xc1, 0x79, 0x83, 0xc5, 0x43, 0xc0, 0xf3, 0x3a, 0x5c,
+  0xc2, 0xc1, 0xd4, 0xe7, 0xed, 0x29, 0xd2, 0xbb, 0xa1, 0xa1, 0x60, 0xb1,
+  0xae, 0xa9, 0xfa, 0xe4, 0x46, 0x5d, 0x5c, 0x16, 0xad, 0x85, 0xdd, 0x06,
+  0x82, 0x39, 0x7d, 0x06, 0x5f, 0x3c, 0xc3, 0x19, 0xd1, 0x01, 0x4b, 0x2a,
+  0x27, 0xb2, 0x50, 0xf1, 0x61, 0x17, 0x73, 0x8e, 0x15, 0x0f, 0x81, 0x00,
+  0x74, 0x5d, 0xef, 0xfa, 0xf9, 0x20, 0xfd, 0xbf, 0x8d, 0xeb, 0x7f, 0xb7,
+  0xd2, 0x21, 0x94, 0xa8, 0x18, 0x2a, 0xe0, 0xc5, 0x82, 0x40, 0xfe, 0xdb,
+  0xf4, 0xe3, 0xf6, 0xff, 0xaa, 0x54, 0x7f, 0x7f, 0xcf, 0x49, 0xda, 0xb4,
+  0x11, 0x1a, 0x0e, 0x00, 0x88, 0x30, 0xad, 0x26, 0x80, 0xf0, 0xe9, 0xac,
+  0x9c, 0xf2, 0xb2, 0xc5, 0x94, 0xe6, 0xfe, 0xa8, 0xdb, 0xc0, 0x2b, 0x46,
+  0xfb, 0x88, 0xca, 0x8b, 0x40, 0x54, 0xfe, 0xdf, 0x91, 0xbd, 0xf8, 0x5b,
+  0x68, 0x08, 0x11, 0x40, 0xe3, 0x04, 0x7a, 0x91, 0x23, 0x41, 0xda, 0x61,
+  0x29, 0x53, 0x49, 0x3d, 0x32, 0x15, 0x70, 0x41, 0xdd, 0x53, 0x81, 0xc2,
+  0x90, 0xf0, 0x12, 0x92, 0x83, 0xc5, 0x6c, 0xaa, 0x99, 0x89, 0x41, 0x94,
+  0x35, 0xda, 0x54, 0xa8, 0x1c, 0x94, 0x7f, 0x49, 0x59, 0x2f, 0x52, 0x55,
+  0xba, 0xb1, 0x56, 0x16, 0x83, 0xe4, 0x40, 0x0e, 0x49, 0x82, 0xe4, 0xca,
+  0x81, 0xe0, 0xe0, 0x17, 0x69, 0x84, 0x93, 0xa1, 0xed, 0x64, 0xae, 0xd2,
+  0x48, 0x0b, 0x6d, 0xbb, 0xa1, 0xed, 0x9f, 0xee, 0x7a, 0x69, 0x6a, 0x8c,
+  0xbc, 0x58, 0xaf, 0xb0, 0x39, 0xd1, 0x10, 0x2d, 0x77, 0xbf, 0x82, 0x37,
+  0x95, 0x5c, 0xdb, 0xe6, 0x44, 0x76, 0x43, 0x92, 0xff, 0xf9, 0xa6, 0x3a,
+  0x51, 0xa5, 0xbb, 0xa8, 0xa1, 0x5e, 0x80, 0xb4, 0x9b, 0x68, 0x0f, 0xa5,
+  0x2d, 0x07, 0x17, 0xb0, 0xc3, 0x53, 0xbc, 0x2c, 0xaa, 0x63, 0x59, 0x11,
+  0xcf, 0x4c, 0x2a, 0x02, 0x7a, 0x5a, 0x88, 0x16, 0xeb, 0xa9, 0x4a, 0xdc,
+  0x91, 0x84, 0xc9, 0x6f, 0xef, 0xe4, 0xf6, 0xab, 0xf7, 0x9a, 0xe7, 0x91,
+  0x96, 0xf0, 0x45, 0xc5, 0x05, 0x4a, 0x41, 0xc6, 0x0b, 0x32, 0xa9, 0xb2,
+  0xbe, 0xb3, 0xcd, 0xb2, 0xf1, 0x47, 0xf9, 0x3a, 0x87, 0x90, 0x45, 0x31,
+  0xf6, 0x61, 0xa0, 0x0e, 0xac, 0xc1, 0xc8, 0x92, 0x10, 0xdb, 0x4e, 0xd4,
+  0x0e, 0xa7, 0xbf, 0x7d, 0x0b, 0x0d, 0x5b, 0x03, 0x93, 0xe2, 0xff, 0x62,
+  0x44, 0xca, 0x18, 0x2e, 0x55, 0x31, 0x69, 0xca, 0xb0, 0xbe, 0x88, 0x80,
+  0xe3, 0x2a, 0xe2, 0x6c, 0x8c, 0x7b, 0xd9, 0xf9, 0x76, 0x48, 0xa7, 0x76,
+  0x15, 0x6f, 0xf8, 0x8b, 0x88, 0x14, 0xe8, 0x3e, 0x3f, 0xff, 0x6a, 0xd4,
+  0x85, 0x72, 0xa5, 0x6f, 0x7f, 0x68, 0x14, 0xf5, 0xe7, 0xa1, 0x48, 0x72,
+  0x84, 0x18, 0x9b, 0xec, 0x8c, 0x1c, 0xcc, 0x0f, 0x6c, 0xcb, 0x6a, 0xe5,
+  0x7d, 0x9c, 0xe2, 0xd0, 0x12, 0x31, 0x6f, 0x83, 0x95, 0xf8, 0x8e, 0x2c,
+  0xe3, 0x7a, 0xcb, 0x05, 0x93, 0xcd, 0x2d, 0x18, 0x52, 0x8a, 0x2c, 0x8d,
+  0x79, 0x03, 0x90, 0x12, 0xb3, 0x4a, 0xea, 0xbd, 0xe0, 0x80, 0xa7, 0x0d,
+  0xd4, 0x10, 0xd9, 0xef, 0x7f, 0x00, 0x00, 0xa8, 0x08, 0x6c, 0x82, 0x69,
+  0x41, 0xb8, 0x5c, 0x0f, 0x0f, 0x00, 0x7a, 0xa0, 0x78, 0xb8, 0x02, 0x5d,
+  0x57, 0x54, 0x23, 0x87, 0x44, 0x41, 0x0b, 0x18, 0x4a, 0x10, 0x07, 0x4a,
+  0x64, 0xd2, 0xc2, 0xe5, 0x4d, 0x03, 0xc5, 0x40, 0x1b, 0x08, 0x83, 0x10,
+  0x21, 0xe0, 0xec, 0x75, 0xfd, 0xfb, 0x42, 0x55, 0x4a, 0x3c, 0x9e, 0xb4,
+  0x41, 0x63, 0x41, 0x5b, 0xe9, 0x10, 0x7f, 0xda, 0x8c, 0x15, 0x06, 0x45,
+  0x8f, 0x0b, 0xa0, 0x73, 0x76, 0x20, 0xe1, 0x6f, 0x96, 0x5e, 0xd8, 0x15,
+  0xa8, 0x25, 0x66, 0xcc, 0x12, 0x40, 0x3b, 0xf7, 0xb4, 0x15, 0xbf, 0x1f,
+  0x7e, 0xa1, 0x2e, 0x67, 0xa1, 0xe4, 0x06, 0x0d, 0x1b, 0xee, 0x02, 0xb8,
+  0x2c, 0x1f, 0x0f, 0x87, 0xe9, 0x47, 0xbf, 0x94, 0x74, 0x3a, 0x2f, 0x5b,
+  0xaa, 0x5b, 0xdf, 0x49, 0xef, 0x59, 0x38, 0xb7, 0xd0, 0xee, 0xe8, 0x08,
+  0x37, 0x8a, 0xcb, 0xc4, 0x81, 0x1f, 0x3e, 0x94, 0xb5, 0x53, 0x7f, 0xfc,
+  0x2d, 0x52, 0x1f, 0xb3, 0xfb, 0xeb, 0x43, 0xa4, 0xd7, 0x5b, 0x51, 0x98,
+  0xa7, 0x85, 0x78, 0xab, 0xc4, 0x45, 0xe0, 0xb2, 0x53, 0x2d, 0x87, 0xd5,
+  0x00, 0xc1, 0xf2, 0xbc, 0xdf, 0xb0, 0x5a, 0x20, 0x33, 0x47, 0x09, 0xb7,
+  0xb8, 0x20, 0xb3, 0x3f, 0x57, 0x0d, 0x9a, 0xcd, 0x8a, 0x54, 0x81, 0x50,
+  0xb0, 0x20, 0x7a, 0x8f, 0x52, 0xfa, 0xfd, 0x89, 0x80, 0xa7, 0x10, 0x26,
+  0x96, 0xa2, 0x6b, 0x15, 0xf2, 0x6c, 0x81, 0xa2, 0x90, 0x7c, 0x98, 0x01,
+  0xd2, 0x06, 0xd1, 0xf2, 0xbd, 0x10, 0xd3, 0xa7, 0x48, 0xa7, 0xbb, 0x7d,
+  0x7e, 0xd2, 0xf6, 0xb6, 0x1e, 0x2e, 0x97, 0xc5, 0x4b, 0xe2, 0x30, 0x60,
+  0xac, 0x58, 0x10, 0x36, 0x41, 0x29, 0x52, 0xc5, 0x6c, 0xfa, 0x6e, 0xa0,
+  0xbd, 0xe4, 0xe8, 0x30, 0xd3, 0xb8, 0x45, 0x30, 0x85, 0xb3, 0x20, 0xc1,
+  0x0f, 0xc0, 0x7c, 0x7e, 0x3e, 0x1f, 0x52, 0xec, 0x9f, 0xc5, 0x5d, 0x6c,
+  0x7a, 0x93, 0xdf, 0xea, 0x9f, 0x96, 0x48, 0x1e, 0x03, 0x1b, 0x10, 0x03,
+  0xd0, 0x61, 0xa8, 0x7c, 0x06, 0xf2, 0xb1, 0xf2, 0xa4, 0xea, 0xd4, 0xe6,
+  0x81, 0xbd, 0xff, 0x1a, 0x96, 0x77, 0x99, 0x10, 0x77, 0x46, 0xc8, 0x41,
+  0x18, 0xc4, 0x33, 0xf2, 0x31, 0x00, 0x35, 0x03, 0x81, 0xe8, 0x38, 0x0f,
+  0x89, 0x0a, 0x30, 0x7e, 0xd5, 0x52, 0xcf, 0x90, 0x32, 0x6e, 0xc8, 0x22,
+  0xb6, 0x0f, 0x97, 0xff, 0xda, 0x60, 0x79, 0xb3, 0x78, 0xa6, 0x18, 0x5b,
+  0x38, 0x75, 0xb0, 0x57, 0x03, 0x41, 0x24, 0xb8, 0xbf, 0xec, 0x97, 0x16,
+  0xc8, 0xad, 0x52, 0x8d, 0xfb, 0x4b, 0x5b, 0xcf, 0xa2, 0x02, 0x78, 0x05,
+  0x70, 0x16, 0xe1, 0x4b, 0x5a, 0x69, 0xb6, 0xae, 0x7c, 0x3a, 0xe7, 0x56,
+  0x5a, 0xac, 0x85, 0xc1, 0xf0, 0x19, 0xa0, 0x80, 0x5e, 0x3b, 0x1d, 0xb0,
+  0x07, 0x4b, 0xff, 0x0b, 0xa3, 0x1b, 0x1b, 0xf0, 0xe3, 0xc3, 0x86, 0x53,
+  0xef, 0x50, 0xa8, 0x1b, 0x60, 0x6a, 0x0c, 0x46, 0x0a, 0x56, 0x95, 0x88,
+  0x29, 0x9b, 0x6a, 0xef, 0x34, 0xb3, 0x46, 0xf5, 0x6e, 0xf1, 0x6e, 0xa8,
+  0x46, 0x56, 0x56, 0x16, 0x5f, 0xd2, 0xda, 0xa4, 0x12, 0x1c, 0x4c, 0x99,
+  0xcc, 0x04, 0x45, 0x54, 0x0c, 0x67, 0x2e, 0xf5, 0x47, 0xf5, 0x7b, 0x64,
+  0xab, 0xf2, 0xe9, 0x5e, 0x03, 0x8c, 0x49, 0x7a, 0xa6, 0x87, 0xbe, 0x8a,
+  0x6d, 0x53, 0x33, 0xb9, 0xb1, 0x65, 0xc9, 0x43, 0x93, 0x03, 0x44, 0xd9,
+  0xbd, 0xf0, 0x37, 0x6c, 0xd5, 0x69, 0x13, 0x4c, 0x2d, 0xf6, 0x71, 0xae,
+  0xff, 0x9d, 0x2c, 0xe8, 0xd9, 0x4f, 0x20, 0xd0, 0xbc, 0x1e, 0x96, 0x49,
+  0xe5, 0x28, 0x61, 0x2a, 0xc8, 0x60, 0x30, 0x9e, 0xd8, 0x16, 0x2a, 0x63,
+  0x95, 0x5f, 0x2f, 0x54, 0x95, 0x7f, 0x7b, 0x1a, 0x49, 0x96, 0xfd, 0x2f,
+  0xd1, 0x66, 0x5f, 0x7e, 0x02, 0xb2, 0xa8, 0x02, 0xea, 0x79, 0xbf, 0x02,
+  0x9e, 0x16, 0x0b, 0x83, 0xf8, 0xa7, 0x03, 0xdc, 0x5f, 0x3a, 0x6f, 0xb6,
+  0x8a, 0xc5, 0x4c, 0x71, 0x3e, 0x7e, 0xf7, 0xb2, 0xf6, 0x6e, 0x71, 0x18,
+  0xad, 0x2a, 0x3e, 0xf7, 0x87, 0x16, 0x7a, 0x75, 0x0e, 0x20, 0xb6, 0xc4,
+  0x60, 0x8d, 0x21, 0x86, 0x27, 0x32, 0xf5, 0x64, 0x3c, 0x6d, 0x7c, 0xc9,
+  0xe1, 0x9c, 0x98, 0x0c, 0x4e, 0x68, 0x18, 0x6f, 0x6a, 0xcd, 0x7e, 0xcb,
+  0x8d, 0x54, 0x36, 0x42, 0xc4, 0x7d, 0x0e, 0x34, 0x6e, 0x16, 0x0c, 0x40,
+  0xd5, 0xa0, 0xc1, 0xfa, 0xad, 0x51, 0x44, 0x16, 0x3f, 0xcc, 0x44, 0xb5,
+  0x8b, 0x76, 0x83, 0x05, 0x52, 0xab, 0x1a, 0x60, 0x79, 0xec, 0xc9, 0x9e,
+  0xbe, 0x9b, 0x39, 0xc5, 0x2b, 0xc8, 0x86, 0x88, 0xad, 0xa2, 0x2b, 0x06,
+  0x38, 0x70, 0xc5, 0xd8, 0x1a, 0xc4, 0xc3, 0x86, 0xb5, 0x68, 0x56, 0xd7,
+  0xb9, 0xbc, 0x93, 0xab, 0xf0, 0xf2, 0x91, 0x33, 0x6a, 0xbf, 0x6c, 0xb3,
+  0x64, 0xf5, 0xb8, 0x51, 0xd9, 0x6f, 0xb8, 0x1b, 0x8d, 0xc1, 0x84, 0xda,
+  0x33, 0x0b, 0xd2, 0x31, 0xfe, 0x15, 0xaf, 0x91, 0x6e, 0x64, 0xb2, 0xf2,
+  0x40, 0xd4, 0x2c, 0xa6, 0xbf, 0x6a, 0x50, 0x34, 0xbd, 0x03, 0x42, 0x08,
+  0xe3, 0x54, 0xa1, 0x5a, 0x59, 0x60, 0x6c, 0x36, 0x06, 0x1a, 0xd7, 0xb4,
+  0xa8, 0x7c, 0xae, 0xe0, 0x88, 0x9f, 0xfe, 0xbf, 0x35, 0x78, 0xb5, 0x9d,
+  0x05, 0xba, 0xc0, 0xab, 0x67, 0xcc, 0xa6, 0xe1, 0x5e, 0x45, 0x0c, 0x32,
+  0xa5, 0x19, 0x6f, 0xff, 0xc0, 0x76, 0x72, 0x95, 0x83, 0x10, 0xda, 0x8f,
+  0x83, 0x29, 0xc6, 0x6f, 0x07, 0x11, 0xa9, 0x95, 0x7e, 0xec, 0xef, 0x27,
+  0x78, 0x27, 0x2f, 0x98, 0x5a, 0x5f, 0x22, 0x89, 0xbc, 0x93, 0x54, 0xa0,
+  0x9c, 0x59, 0x60, 0xdc, 0x8e, 0x76, 0x46, 0xa4, 0x6b, 0x59, 0xa9, 0xfc,
+  0xb5, 0x9d, 0xea, 0xcb, 0x6a, 0xdd, 0xe8, 0x38, 0xcc, 0x08, 0xdd, 0x4c,
+  0x1f, 0xa7, 0xfa, 0x9b, 0x89, 0x59, 0x52, 0x56, 0x8f, 0x85, 0x92, 0x40,
+  0xa1, 0x1d, 0x66, 0x66, 0x95, 0x66, 0xae, 0x19, 0x93, 0x9b, 0x2d, 0x57,
+  0x7f, 0xf2, 0xde, 0x46, 0xa7, 0x33, 0xd1, 0x4f, 0x6d, 0xa8, 0x7b, 0x06,
+  0x40, 0xef, 0x03, 0x11, 0x70, 0xb1, 0x5f, 0xcb, 0xf0, 0x71, 0xdf, 0x54,
+  0x70, 0x66, 0x50, 0xe0, 0xfc, 0x0c, 0x10, 0x42, 0x1a, 0x6a, 0x10, 0x34,
+  0x75, 0x9b, 0x8c, 0x8f, 0x53, 0xb7, 0x9e, 0x0f, 0x9a, 0xb3, 0x59, 0xcc,
+  0x0e, 0xed, 0xff, 0x86, 0xe4, 0x03, 0xfe, 0xfd, 0x17, 0xf1, 0x65, 0x2b,
+  0x71, 0x1a, 0xd5, 0x1f, 0x41, 0x2a, 0x1b, 0x08, 0x0c, 0x2a, 0x4e, 0xc9,
+  0x78, 0xf9, 0x52, 0xaa, 0xaf, 0xff, 0xff, 0xd5, 0x97, 0x8f, 0xff, 0x36,
+  0x35, 0x6c, 0x9d, 0xe5, 0xd1, 0x4c, 0x42, 0xd4, 0x67, 0x1b, 0x0f, 0xcd,
+  0x03, 0x60, 0x1d, 0xb7, 0xdb, 0x44, 0xa6, 0x73, 0xdc, 0x96, 0x65, 0xe4,
+  0xb6, 0xa3, 0x44, 0x16, 0x82, 0xbc, 0x0e, 0x2a, 0x07, 0x01, 0xe1, 0x19,
+  0xa1, 0xf3, 0x0d, 0x34, 0x1f, 0xd0, 0x32, 0x9d, 0xbd, 0xff, 0x32, 0xb3,
+  0xf4, 0x70, 0xb2, 0x0d, 0xd4, 0x0d, 0xbc, 0x1e, 0x87, 0x46, 0x01, 0x6e,
+  0x59, 0x53, 0x8e, 0x1b, 0xf9, 0x7b, 0x36, 0x2d, 0x98, 0x20, 0x78, 0x40,
+  0x48, 0xa7, 0x9b, 0xde, 0x5d, 0xcf, 0x6b, 0x79, 0x99, 0x29, 0x58, 0x31,
+  0x15, 0x7b, 0xe3, 0xec, 0xfc, 0x61, 0x85, 0x79, 0xad, 0xa0, 0x0f, 0x6e,
+  0xd2, 0x8a, 0x54, 0xa5, 0x48, 0x6c, 0x0c, 0x71, 0xc2, 0xcb, 0xd2, 0x62,
+  0xcb, 0x56, 0x6c, 0x52, 0x39, 0xd9, 0x6e, 0xf0, 0xa9, 0x44, 0xcc, 0x5a,
+  0x73, 0x9c, 0x1b, 0xe8, 0x30, 0xd4, 0xcc, 0xea, 0xb5, 0x38, 0x5b, 0x58,
+  0x6a, 0x22, 0x1c, 0x15, 0x52, 0x8a, 0x1c, 0x18, 0xbb, 0xeb, 0xfe, 0xdd,
+  0xe4, 0x1b, 0x96, 0xde, 0x72, 0xf4, 0x92, 0x08, 0x80, 0xe3, 0x2a, 0x8e,
+  0x18, 0x4c, 0xa3, 0xad, 0xfd, 0x42, 0xf5, 0x44, 0x8a, 0x54, 0xf1, 0x17,
+  0x4a, 0xc9, 0x6e, 0x80, 0x85, 0x73, 0xe9, 0xd6, 0x09, 0x0a, 0xb3, 0xe5,
+  0xb2, 0x7f, 0x11, 0xe9, 0x6d, 0x4e, 0xdc, 0x2d, 0xa6, 0xff, 0x30, 0x6f,
+  0x9a, 0x1b, 0xfc, 0x1f, 0x22, 0x00, 0x74, 0xc7, 0x09, 0x97, 0x52, 0xda,
+  0x1b, 0xfe, 0x2e, 0x59, 0xd5, 0x96, 0x94, 0x6e, 0x65, 0x50, 0x53, 0x97,
+  0x62, 0xe0, 0x67, 0xe1, 0xb5, 0xec, 0xce, 0x94, 0x69, 0x50, 0x3e, 0x5f,
+  0xff, 0x64, 0x98, 0x6d, 0xa5, 0x79, 0x34, 0x71, 0x4a, 0xb8, 0x4b, 0x8b,
+  0xce, 0xf0, 0x55, 0x9e, 0xef, 0x55, 0x9a, 0xe2, 0xaa, 0xa2, 0xa0, 0x83,
+  0x8b, 0x44, 0xe6, 0x17, 0x55, 0x9f, 0x66, 0xab, 0xa1, 0xff, 0xfd, 0x03,
+  0xcc, 0xc0, 0xf6, 0xd3, 0x50, 0xac, 0x04, 0x4b, 0x31, 0x3b, 0x36, 0x78,
+  0x19, 0x12, 0x49, 0x90, 0xad, 0x6d, 0xbb, 0xa8, 0xd1, 0x06, 0xc3, 0x61,
+  0x61, 0x6c, 0x68, 0xbb, 0x01, 0x97, 0x99, 0xdf, 0xe0, 0xdc, 0xb5, 0x7d,
+  0xec, 0x47, 0x43, 0x64, 0x20, 0x2e, 0xe5, 0xa9, 0x15, 0xab, 0x8d, 0x4d,
+  0x06, 0x1c, 0x7f, 0xf3, 0x17, 0xfb, 0x2a, 0xf7, 0xd6, 0xe5, 0xa8, 0x6f,
+  0xb0, 0xaf, 0x01, 0xc6, 0x0e, 0x83, 0xc1, 0x7f, 0xc6, 0xdf, 0xef, 0xfd,
+  0xac, 0xc5, 0x3c, 0x1c, 0x31, 0x9a, 0x06, 0x98, 0x2c, 0xea, 0xe3, 0x75,
+  0x3a, 0xa1, 0x16, 0x03, 0x13, 0x99, 0x06, 0x10, 0x6e, 0xa7, 0xd0, 0x78,
+  0x28, 0x05, 0xee, 0xfa, 0x72, 0xb0, 0xce, 0x7e, 0xdf, 0x7e, 0xd4, 0x56,
+  0xf9, 0x42, 0x81, 0xb5, 0xa0, 0x24, 0x49, 0xdd, 0x8d, 0x6d, 0x6f, 0xd3,
+  0xdc, 0xea, 0x8c, 0xf7, 0x3b, 0xc8, 0xb9, 0x68, 0x6c, 0x89, 0x40, 0x30,
+  0x9f, 0x5e, 0x1e, 0x2c, 0x48, 0xd0, 0x1b, 0x92, 0xd1, 0xdb, 0x2c, 0x29,
+  0xd0, 0xeb, 0xca, 0xbb, 0xe9, 0x09, 0x2d, 0x11, 0x41, 0xf2, 0x60, 0x07,
+  0xe1, 0xfc, 0xcb, 0x56, 0xc0, 0xcd, 0x4e, 0x8a, 0x46, 0xc2, 0x52, 0x5f,
+  0x2b, 0xdd, 0x69, 0x85, 0x48, 0xbb, 0xa0, 0xad, 0xde, 0xa1, 0x5e, 0xdb,
+  0xb8, 0xa5, 0x42, 0x90, 0x7c, 0xf8, 0x01, 0xc5, 0x6a, 0x43, 0xdf, 0x67,
+  0xb3, 0xdd, 0x93, 0xb4, 0x9b, 0x6a, 0x28, 0xbc, 0xa2, 0xb3, 0x7d, 0x56,
+  0x88, 0x96, 0x5e, 0xde, 0x70, 0xd8, 0x24, 0x74, 0xe5, 0xcd, 0xfe, 0x5c,
+  0x9f, 0x99, 0x94, 0x44, 0x11, 0x78, 0x0c, 0x13, 0xc3, 0x34, 0xaa, 0x96,
+  0x5c, 0x2d, 0x81, 0xea, 0x8e, 0xf0, 0x60, 0x1b, 0x29, 0x3e, 0xbf, 0xb5,
+  0x94, 0xbe, 0x02, 0x0d, 0xc8, 0x04, 0x4a, 0x89, 0x78, 0x54, 0x57, 0xa6,
+  0x25, 0xb3, 0x1e, 0x1e, 0x66, 0x72, 0x5d, 0xdd, 0x2b, 0x5e, 0x23, 0x83,
+  0x30, 0x61, 0x39, 0x60, 0x2d, 0x35, 0x65, 0x11, 0x72, 0xda, 0x8a, 0xf0,
+  0x91, 0xd2, 0xc3, 0x51, 0x8a, 0x57, 0xa2, 0x0b, 0x77, 0xb5, 0x4d, 0xec,
+  0x92, 0x52, 0x04, 0x16, 0xd5, 0x0a, 0x67, 0x56, 0x0f, 0x4d, 0x28, 0x25,
+  0x7f, 0xb6, 0xb8, 0x07, 0x08, 0xe2, 0x40, 0x29, 0x8b, 0x87, 0xd8, 0x97,
+  0xc0, 0x6f, 0xc9, 0x13, 0x16, 0xfa, 0xad, 0x4b, 0x41, 0x13, 0xd6, 0xf0,
+  0x39, 0x47, 0x41, 0x86, 0x81, 0x79, 0xb1, 0xfe, 0x37, 0xf8, 0xc7, 0x97,
+  0x9b, 0xde, 0xea, 0x07, 0x8e, 0x02, 0x10, 0x84, 0xde, 0x26, 0xf2, 0x72,
+  0xc8, 0xa5, 0x5b, 0x5e, 0xaa, 0x41, 0x51, 0x7d, 0x39, 0x20, 0x8a, 0x36,
+  0x90, 0xb4, 0x18, 0x56, 0x26, 0xf2, 0x68, 0xd7, 0x35, 0x1d, 0x58, 0x90,
+  0x81, 0x7f, 0x67, 0x64, 0xc4, 0x40, 0xf9, 0x9f, 0xfd, 0xc8, 0x89, 0xcd,
+  0x9a, 0xad, 0x46, 0x1a, 0xdf, 0x31, 0x93, 0xcb, 0x22, 0xc2, 0xab, 0xc3,
+  0x51, 0x46, 0x15, 0x69, 0xc1, 0xb8, 0x30, 0x81, 0xf6, 0xd3, 0xb6, 0x3f,
+  0xfa, 0xa8, 0x5b, 0x79, 0xc5, 0xe6, 0xc9, 0xe8, 0x55, 0x20, 0x70, 0xa4,
+  0x1f, 0x5e, 0x00, 0x74, 0x2d, 0x2d, 0xb2, 0x10, 0x08, 0x9b, 0xbc, 0xc5,
+  0x11, 0x6e, 0x85, 0x1c, 0x21, 0x43, 0xc5, 0xa8, 0xca, 0x4e, 0x2b, 0x61,
+  0x3e, 0xc0, 0x56, 0xf9, 0x4a, 0x84, 0x35, 0x1a, 0x33, 0xf4, 0x9a, 0xdf,
+  0xe5, 0xb4, 0xa8, 0xd4, 0x45, 0x4a, 0x4f, 0x53, 0x4a, 0xbd, 0xf2, 0xbf,
+  0xf3, 0x54, 0x29, 0x92, 0x58, 0x86, 0xd4, 0x61, 0x55, 0xab, 0xc9, 0x96,
+  0x6e, 0x2d, 0x11, 0x70, 0x83, 0x92, 0x1e, 0x6c, 0x34, 0x03, 0x68, 0xec,
+  0x14, 0xa3, 0xcc, 0xfb, 0x23, 0xc1, 0xe3, 0x0d, 0xa6, 0xf2, 0x34, 0xf9,
+  0xd6, 0xdb, 0xf4, 0x37, 0x53, 0x42, 0xc5, 0x18, 0x88, 0xac, 0x18, 0xe8,
+  0x70, 0xba, 0x07, 0xc1, 0x05, 0xba, 0xdb, 0x6d, 0xf6, 0x4d, 0x02, 0xed,
+  0xfe, 0x34, 0xd6, 0x6f, 0x51, 0x40, 0xdd, 0x71, 0xb0, 0x7a, 0x2d, 0x13,
+  0x8f, 0x75, 0x5b, 0x10, 0x72, 0xc6, 0xc9, 0x33, 0xea, 0x55, 0xe2, 0x85,
+  0x23, 0x94, 0xdc, 0xf9, 0x6f, 0xa4, 0x0e, 0x51, 0x0d, 0x01, 0x76, 0xa8,
+  0x7c, 0x07, 0x84, 0x7d, 0x05, 0x3a, 0x46, 0x34, 0xb9, 0x5c, 0x59, 0xae,
+  0xac, 0x91, 0x8f, 0xf0, 0x3b, 0xf4, 0xc0, 0x56, 0x63, 0x62, 0x2a, 0x90,
+  0xec, 0x04, 0xd8, 0xd7, 0xe9, 0x5f, 0x43, 0xc0, 0x62, 0x17, 0xd9, 0x4d,
+  0x9c, 0x4c, 0x17, 0x60, 0x18, 0x91, 0x38, 0xe9, 0x23, 0x0c, 0x0e, 0x7a,
+  0x55, 0x83, 0x91, 0x07, 0xff, 0xda, 0xa7, 0x8b, 0xc2, 0xb1, 0xb6, 0x60,
+  0x71, 0x80, 0x28, 0x64, 0xd2, 0xbe, 0x35, 0xcb, 0x65, 0x24, 0x9d, 0x99,
+  0xd0, 0x61, 0xa8, 0xb9, 0x20, 0x3c, 0x1f, 0xfc, 0xaa, 0x82, 0x11, 0x7b,
+  0x4d, 0xea, 0x74, 0xea, 0x59, 0x10, 0x7d, 0x14, 0xe7, 0x95, 0x78, 0x15,
+  0x22, 0x26, 0x29, 0xe6, 0x28, 0x06, 0x21, 0x28, 0xac, 0x75, 0x7b, 0xd6,
+  0x38, 0x22, 0x42, 0xc4, 0x59, 0xc8, 0x72, 0x6a, 0xc8, 0x42, 0xd4, 0x4d,
+  0x3e, 0x95, 0x16, 0xcb, 0xd0, 0xe6, 0x14, 0xa3, 0xa7, 0xcc, 0xe5, 0x69,
+  0xbd, 0xb8, 0x8b, 0x57, 0x44, 0xb1, 0xde, 0x3c, 0xf4, 0xf2, 0x75, 0x6d,
+  0x7f, 0x9f, 0x93, 0xd0, 0x92, 0x2f, 0xce, 0xb9, 0x0c, 0x12, 0x95, 0x79,
+  0x3b, 0x4a, 0xe1, 0x52, 0x8d, 0x29, 0x95, 0x67, 0xb6, 0x91, 0xcb, 0xe3,
+  0xe6, 0x3c, 0xab, 0xaa, 0x3f, 0xfb, 0x3f, 0x2f, 0xef, 0x61, 0x57, 0x61,
+  0x2a, 0x91, 0xb9, 0x95, 0xc1, 0x56, 0x06, 0xfe, 0x20, 0x26, 0xda, 0x5b,
+  0xed, 0x2c, 0x56, 0x8c, 0x0c, 0x52, 0xcc, 0xa1, 0xc1, 0x59, 0x50, 0xb5,
+  0x12, 0xff, 0x8e, 0x39, 0x3d, 0xb9, 0x85, 0xa5, 0x44, 0xbd, 0xb2, 0xa2,
+  0x0e, 0x0c, 0x9d, 0x48, 0x25, 0x7c, 0xbb, 0x15, 0x4f, 0x37, 0x77, 0x2e,
+  0xb3, 0xa9, 0xf5, 0xbd, 0xad, 0xfd, 0x9d, 0xbc, 0x91, 0x7d, 0xd1, 0x10,
+  0xf2, 0x16, 0xda, 0x2b, 0x35, 0xfd, 0x0e, 0x2e, 0x72, 0xff, 0x46, 0xfb,
+  0xfe, 0x2e, 0x0c, 0x26, 0x55, 0x26, 0x66, 0x28, 0xea, 0x2f, 0x96, 0xd8,
+  0x82, 0xcc, 0xbc, 0x92, 0x70, 0x38, 0x58, 0x12, 0x64, 0x7e, 0xd4, 0x6d,
+  0xaf, 0xfb, 0xb6, 0x73, 0x24, 0xc4, 0x01, 0xec, 0x2b, 0x07, 0x08, 0x82,
+  0x7f, 0xcf, 0x2b, 0x69, 0x53, 0x68, 0x5a, 0x58, 0x97, 0xa4, 0xe8, 0x2d,
+  0x4f, 0x91, 0xd9, 0x5c, 0xc1, 0xc5, 0x0f, 0xb2, 0x4d, 0xf4, 0xf5, 0xb1,
+  0x07, 0x3f, 0x2b, 0x86, 0x83, 0xcd, 0xc8, 0xcf, 0xb3, 0xea, 0x0b, 0x6d,
+  0xd5, 0x35, 0x0c, 0x93, 0x96, 0xda, 0x1a, 0xed, 0x06, 0x05, 0xc2, 0xe3,
+  0xd6, 0xea, 0x6f, 0xe6, 0xcd, 0xa3, 0x60, 0xeb, 0x9c, 0x9a, 0x33, 0x52,
+  0x55, 0xaa, 0x41, 0x2d, 0x7d, 0x4c, 0x0f, 0x05, 0xff, 0x1b, 0x25, 0xed,
+  0x7b, 0x1b, 0xf7, 0x94, 0x33, 0x73, 0xd6, 0x29, 0xec, 0x6a, 0xdb, 0xd1,
+  0x17, 0x14, 0x6f, 0x00, 0xa0, 0x31, 0x19, 0x87, 0x5a, 0xdf, 0xd5, 0x74,
+  0x7a, 0xda, 0x6f, 0x6c, 0xbf, 0xfe, 0xe6, 0xe7, 0xec, 0x2a, 0xc5, 0x5e,
+  0x47, 0xe0, 0xd7, 0x3a, 0x0f, 0x91, 0xff, 0xd8, 0xa5, 0xa1, 0xbb, 0x70,
+  0x73, 0x37, 0xeb, 0x68, 0x80, 0x83, 0x32, 0x01, 0x0a, 0x27, 0x14, 0xaa,
+  0xb8, 0xaf, 0x85, 0xe5, 0x93, 0x0b, 0x24, 0x53, 0x54, 0xc1, 0xb5, 0x92,
+  0xbc, 0xdb, 0x73, 0xf9, 0xfa, 0xdf, 0xbe, 0xd6, 0x35, 0xf5, 0x00, 0xad,
+  0x11, 0x4b, 0x22, 0xf6, 0x40, 0xd4, 0xc7, 0x2c, 0xc7, 0xc7, 0x2c, 0xff,
+  0x7b, 0xb7, 0x18, 0x59, 0x41, 0x65, 0x50, 0xdd, 0x5a, 0xf7, 0xb4, 0x2c,
+  0x37, 0x1b, 0x2c, 0xcb, 0xce, 0x66, 0x4d, 0xaa, 0x3b, 0x7b, 0x6f, 0x3a,
+  0xb5, 0xbb, 0x8a, 0x54, 0x82, 0xdd, 0x46, 0xcb, 0xd8, 0x43, 0xf5, 0xf1,
+  0x71, 0xb7, 0x2a, 0x84, 0x4b, 0x45, 0x23, 0x64, 0x65, 0x78, 0x68, 0xc9,
+  0x86, 0xf8, 0xaf, 0x3c, 0xad, 0x54, 0xdd, 0xfe, 0x6e, 0xe7, 0xae, 0xc2,
+  0xc4, 0xd1, 0x18, 0x77, 0xed, 0x07, 0x07, 0x86, 0x7e, 0xd4, 0xea, 0xb6,
+  0x54, 0xdd, 0xe3, 0x0d, 0x22, 0x9a, 0x8a, 0x2e, 0x6b, 0xe2, 0x2e, 0x86,
+  0xe0, 0xf9, 0x3f, 0xfd, 0x93, 0x10, 0x07, 0x57, 0x7c, 0x0f, 0x09, 0xff,
+  0x9f, 0xd8, 0xef, 0x26, 0xf5, 0xbc, 0x52, 0x86, 0xf2, 0x61, 0x5e, 0x91,
+  0xa6, 0xd3, 0x0d, 0xe2, 0x9d, 0x2f, 0x4f, 0x2f, 0x87, 0x13, 0x8d, 0x62,
+  0x29, 0x27, 0x03, 0xd0, 0xd7, 0x4c, 0x25, 0x0b, 0x56, 0xfb, 0x1b, 0x26,
+  0x40, 0x61, 0x11, 0x8e, 0x77, 0xa8, 0xa4, 0x66, 0xa9, 0x2b, 0xd0, 0xd8,
+  0x3c, 0x07, 0xc7, 0xff, 0xee, 0xbd, 0xfa, 0x3a, 0xcd, 0x67, 0xec, 0x97,
+  0xc0, 0x30, 0xc1, 0x53, 0x1e, 0x9f, 0xb9, 0xe5, 0x11, 0x72, 0xce, 0x60,
+  0x88, 0x0b, 0x65, 0x34, 0x7a, 0x3e, 0xf7, 0x71, 0xac, 0xf6, 0x6f, 0xf9,
+  0x0a, 0xa1, 0x64, 0xea, 0x00, 0xf7, 0x46, 0xfb, 0xa3, 0x75, 0x00, 0xfa,
+  0x1f, 0xfd, 0xa9, 0x27, 0xf6, 0xe8, 0x7f, 0x6d, 0x94, 0x3c, 0x1c, 0x71,
+  0x4f, 0x62, 0x25, 0xa2, 0x90, 0x5a, 0xa3, 0xf6, 0x18, 0x68, 0x3d, 0xad,
+  0x49, 0x72, 0x49, 0x8d, 0x6f, 0x14, 0x62, 0xc8, 0xdc, 0xbd, 0x98, 0x61,
+  0x32, 0xbf, 0xd2, 0xd2, 0xfd, 0xaa, 0x24, 0x8a, 0x3d, 0xb6, 0xcf, 0x14,
+  0xdf, 0x07, 0x01, 0xb0, 0x3e, 0x6c, 0x00, 0xe9, 0xa5, 0xa5, 0xc0, 0x63,
+  0xcd, 0xb7, 0xbb, 0xb6, 0x55, 0x1e, 0xc5, 0xa5, 0x9d, 0x40, 0x1c, 0x18,
+  0x58, 0x41, 0x6d, 0x5c, 0x0e, 0x31, 0x4a, 0xe8, 0x67, 0x17, 0x20, 0x5d,
+  0xa6, 0xb4, 0x72, 0xa5, 0x1c, 0xce, 0xc9, 0xfd, 0x5f, 0x6d, 0xea, 0x00,
+  0x63, 0x46, 0x25, 0x2f, 0x52, 0xe5, 0x56, 0xc6, 0xee, 0xcd, 0xf4, 0xce,
+  0xdc, 0x9d, 0xde, 0x54, 0x1d, 0x53, 0xa0, 0xc0, 0x92, 0xaf, 0x9b, 0x66,
+  0xf0, 0xb1, 0x54, 0xcf, 0x5f, 0xa8, 0xf7, 0xaf, 0x32, 0x28, 0x02, 0x36,
+  0xe8, 0x8a, 0xa6, 0x05, 0x85, 0x9a, 0x8d, 0xcd, 0xa8, 0xf9, 0x01, 0x19,
+  0x61, 0x5a, 0xc9, 0xcb, 0xb5, 0xb2, 0xcf, 0xeb, 0x7b, 0xb3, 0x3f, 0x37,
+  0x4b, 0x1b, 0xfe, 0x62, 0x1e, 0xf3, 0xc1, 0xab, 0xf5, 0x23, 0xb4, 0x8b,
+  0xee, 0xe2, 0x3f, 0xa8, 0x43, 0xcf, 0x59, 0xce, 0xca, 0x1b, 0x03, 0x05,
+  0x26, 0x1a, 0x64, 0x7f, 0x7d, 0x7c, 0xc3, 0x5e, 0xcf, 0x40, 0x64, 0x36,
+  0xdd, 0xbc, 0xec, 0xed, 0xa1, 0xce, 0x99, 0x54, 0x40, 0x41, 0xcd, 0x8b,
+  0xaf, 0x36, 0xaf, 0xc4, 0x00, 0xc3, 0x52, 0x65, 0x9a, 0x58, 0x54, 0xa3,
+  0x80, 0xed, 0x90, 0xd7, 0x01, 0x82, 0x7b, 0x4b, 0x32, 0x3f, 0x4a, 0xc8,
+  0xf1, 0x5f, 0xbe, 0x0a, 0xd4, 0xfd, 0xd9, 0xe6, 0x3c, 0xc7, 0x3c, 0xd6,
+  0x6d, 0x95, 0x1d, 0xa1, 0xce, 0xf0, 0x15, 0xc1, 0x69, 0xec, 0x2f, 0x65,
+  0xbe, 0xf9, 0x5a, 0x42, 0xcc, 0x5a, 0x71, 0x7d, 0xb5, 0x60, 0x46, 0x50,
+  0x1b, 0x81, 0x52, 0xa0, 0x62, 0x25, 0xe6, 0x15, 0xe4, 0xaa, 0x6e, 0xd8,
+  0x05, 0x45, 0x0b, 0x55, 0x51, 0x4e, 0x36, 0xda, 0xdc, 0xea, 0x25, 0xfb,
+  0x5f, 0x1e, 0x99, 0x2c, 0xa7, 0xa6, 0x31, 0x8a, 0x18, 0xf1, 0x67, 0x51,
+  0x7b, 0xd8, 0x22, 0x92, 0xc0, 0x5a, 0x18, 0x4d, 0x35, 0x8a, 0xdb, 0x6c,
+  0xfd, 0x47, 0xd9, 0xb3, 0xd9, 0xeb, 0x7a, 0x59, 0x64, 0xb1, 0x68, 0x80,
+  0x85, 0x34, 0xd4, 0x71, 0x4a, 0xb2, 0xa8, 0xce, 0xf7, 0x4d, 0x9f, 0x51,
+  0xbe, 0x8e, 0x73, 0x54, 0x5d, 0x81, 0xc4, 0x58, 0xf4, 0xcf, 0xd9, 0x54,
+  0x8a, 0x9a, 0xd2, 0xdb, 0xab, 0x6e, 0x77, 0x3b, 0x6c, 0xed, 0x80, 0xe2,
+  0xa0, 0x5a, 0xc6, 0x79, 0xbb, 0x4b, 0x3d, 0xef, 0x56, 0xb2, 0xa1, 0x0e,
+  0x01, 0xc5, 0x60, 0xb5, 0x86, 0xbd, 0xab, 0xd8, 0xa2, 0x29, 0x84, 0x8b,
+  0x52, 0x52, 0xa1, 0x4e, 0x89, 0x95, 0xf3, 0x69, 0x6d, 0xb9, 0x7b, 0x6a,
+  0x81, 0xb1, 0xef, 0xb4, 0x8b, 0x33, 0xda, 0xbf, 0xed, 0xb1, 0x02, 0x3e,
+  0x0a, 0xb7, 0xed, 0x59, 0x44, 0x51, 0xef, 0xad, 0xc8, 0x8e, 0x93, 0xce,
+  0x6b, 0x18, 0x1d, 0x7a, 0xb7, 0xf2, 0x51, 0xb0, 0x9d, 0x16, 0x8b, 0x68,
+  0x7b, 0xbb, 0x32, 0x20, 0xf6, 0x1a, 0x27, 0xbb, 0x00, 0x00, 0xb2, 0x08,
+  0x2c, 0x2d, 0x8f, 0x37, 0xa3, 0xa1, 0x28, 0x90, 0x74, 0x5d, 0x01, 0xe2,
+  0xa0, 0x0d, 0x16, 0x27, 0x77, 0x8a, 0x68, 0xa5, 0x31, 0x23, 0x80, 0xc2,
+  0x00, 0xeb, 0xa0, 0xf0, 0xb0, 0x0b, 0x97, 0x03, 0xc5, 0xc0, 0x1a, 0x2c,
+  0x5d, 0x2b, 0x60, 0xe1, 0x99, 0x00, 0xb8, 0xa6, 0x10, 0x26, 0x66, 0x6a,
+  0x3b, 0x56, 0x26, 0x6b, 0xff, 0x45, 0x2b, 0x12, 0x21, 0xb7, 0x9c, 0x25,
+  0x26, 0x2c, 0xa2, 0x64, 0x43, 0x03, 0x3f, 0x94, 0x86, 0xc0, 0xb6, 0x43,
+  0xea, 0x99, 0x26, 0xb9, 0x03, 0xc4, 0x7c, 0xee, 0xfe, 0xa0, 0x94, 0xab,
+  0x0f, 0x19, 0x56, 0x8d, 0xed, 0x32, 0x2b, 0x79, 0x33, 0xa5, 0x52, 0x20,
+  0xe4, 0x5c, 0x1c, 0xa5, 0xea, 0x37, 0xf9, 0x3f, 0x72, 0xd2, 0xb5, 0xc2,
+  0x95, 0x74, 0x6c, 0xfe, 0xf1, 0x7e, 0x8a, 0xcc, 0xa6, 0x03, 0x89, 0x9b,
+  0x12, 0x19, 0x54, 0x56, 0x1e, 0x0e, 0xe8, 0xfe, 0x6a, 0xf9, 0x79, 0x7f,
+  0xda, 0xd7, 0xae, 0x68, 0x70, 0x02, 0x14, 0x4b, 0xfc, 0xf0, 0x73, 0xba,
+  0x83, 0x3d, 0x3b, 0x78, 0x6c, 0x1c, 0x60, 0xf3, 0x02, 0x58, 0xed, 0xb4,
+  0xac, 0x8f, 0x15, 0x66, 0x87, 0xd5, 0x46, 0xa9, 0xea, 0xf1, 0x98, 0x1e,
+  0xfa, 0x74, 0x6c, 0x1f, 0x6f, 0x03, 0xdc, 0xd0, 0xef, 0xc0, 0xc4, 0xc2,
+  0xfe, 0x01, 0x76, 0xbd, 0x32, 0x38, 0x39, 0xf7, 0xec, 0x2a, 0x51, 0x9d,
+  0xde, 0xdd, 0x92, 0xcc, 0x97, 0x9c, 0xaa, 0x44, 0x4c, 0xe4, 0x05, 0x78,
+  0x08, 0x16, 0x2a, 0x2f, 0xd5, 0x78, 0xa3, 0xd3, 0x7a, 0xb1, 0x5d, 0x85,
+  0x4b, 0xc5, 0xb9, 0x41, 0x2c, 0x48, 0xa8, 0x0f, 0x2a, 0x03, 0xe9, 0x18,
+  0x6c, 0x76, 0xca, 0xb1, 0xcb, 0x0a, 0x47, 0x2c, 0x30, 0xac, 0x15, 0x97,
+  0xfd, 0x5e, 0x27, 0x8d, 0x15, 0x6e, 0x2d, 0x00, 0x45, 0x97, 0x08, 0x38,
+  0x5b, 0x03, 0xea, 0xd2, 0xa6, 0xbb, 0x8a, 0x4b, 0x65, 0x9f, 0xc9, 0x16,
+  0xbe, 0xf6, 0x62, 0x98, 0xd2, 0x22, 0xc5, 0x21, 0xe8, 0x30, 0xa8, 0xd5,
+  0xbb, 0x5c, 0xe9, 0xbc, 0x06, 0x5b, 0xeb, 0xd5, 0x2d, 0xf2, 0x07, 0xfa,
+  0x80, 0xc2, 0x17, 0x54, 0xa1, 0xef, 0x51, 0x0a, 0x08, 0x97, 0x35, 0xef,
+  0x4d, 0xfc, 0xc2, 0xb4, 0xf6, 0x7d, 0x9a, 0x8f, 0xb7, 0x9c, 0xf4, 0x0d,
+  0x02, 0xc6, 0x97, 0xdf, 0x03, 0x01, 0xf5, 0x9e, 0x0f, 0x62, 0x99, 0xc5,
+  0xb6, 0x2f, 0xd8, 0x04, 0xc6, 0xe2, 0x6b, 0x5f, 0x1b, 0xa6, 0x07, 0xcc,
+  0x48, 0xd4, 0xd6, 0xdb, 0xff, 0xf3, 0xbb, 0x23, 0x7a, 0xa7, 0xb6, 0xf5,
+  0x70, 0x46, 0xaa, 0x14, 0x01, 0x03, 0x0b, 0x88, 0x6a, 0xc1, 0xb8, 0x98,
+  0x72, 0xa3, 0xff, 0xbe, 0x51, 0x3c, 0xa9, 0xa8, 0xa6, 0xdb, 0x6f, 0x24,
+  0x9e, 0x11, 0x77, 0x76, 0x85, 0x91, 0x0a, 0xd4, 0x51, 0xb6, 0xa0, 0x21,
+  0xa6, 0x79, 0x5b, 0x81, 0xe2, 0x96, 0xe5, 0xa5, 0x88, 0x03, 0x6e, 0xb9,
+  0xc2, 0xd7, 0x3e, 0xdc, 0xb0, 0x9b, 0x4b, 0xf6, 0x0e, 0x7b, 0x2a, 0x89,
+  0x7f, 0xe4, 0x45, 0x9b, 0x50, 0x15, 0x15, 0x03, 0x02, 0x67, 0xf6, 0x08,
+  0x1a, 0x5e, 0x3e, 0xd0, 0xeb, 0xd2, 0xb3, 0xe1, 0xaa, 0x69, 0xba, 0xc1,
+  0x6a, 0x92, 0xbb, 0x7a, 0x53, 0xd3, 0xe3, 0x96, 0x44, 0xbc, 0x81, 0x0d,
+  0xb6, 0xb7, 0xdf, 0x9f, 0xbe, 0xca, 0x88, 0xab, 0xea, 0x97, 0xc5, 0xa8,
+  0x8a, 0xa3, 0x90, 0x05, 0xdd, 0xbd, 0x80, 0xe3, 0x0e, 0xdc, 0x39, 0x66,
+  0x84, 0x9c, 0xd4, 0xe9, 0x98, 0x67, 0xc5, 0x7e, 0xf6, 0x5b, 0x60, 0x8a,
+  0x89, 0x6e, 0x50, 0xe5, 0x49, 0xe3, 0x23, 0xc2, 0xd8, 0x25, 0xd2, 0xdc,
+  0xb8, 0xa6, 0x42, 0xd3, 0x5b, 0x95, 0xa9, 0xd9, 0x60, 0x88, 0x02, 0x57,
+  0x56, 0x5e, 0xca, 0xa4, 0x89, 0x4a, 0xa2, 0x91, 0xf3, 0x2a, 0xbf, 0xe1,
+  0x13, 0xaa, 0x99, 0xa1, 0xe0, 0x11, 0x2b, 0xc3, 0x14, 0x3b, 0xd2, 0xdc,
+  0xc1, 0xd9, 0x75, 0x2a, 0x4b, 0x98, 0x20, 0x9b, 0xce, 0x45, 0xef, 0x43,
+  0x9d, 0xd8, 0xa0, 0x18, 0x4c, 0x68, 0xc5, 0x95, 0x2e, 0x67, 0x01, 0x4c,
+  0xa7, 0x18, 0xfc, 0xef, 0xff, 0x88, 0x3b, 0x27, 0xba, 0x8e, 0x0d, 0xca,
+  0xf8, 0x09, 0x0a, 0x33, 0xef, 0x6c, 0xd8, 0xdc, 0x6d, 0x45, 0x99, 0xa1,
+  0xe2, 0xda, 0xb2, 0xd6, 0x50, 0xe3, 0x17, 0x07, 0xc9, 0xff, 0xed, 0x66,
+  0x19, 0xab, 0x7b, 0x7b, 0xcc, 0xb0, 0x15, 0xeb, 0x72, 0xde, 0x40, 0xdf,
+  0xa0, 0x92, 0x5d, 0x56, 0x01, 0xb6, 0x62, 0x85, 0xa7, 0x69, 0x2c, 0x51,
+  0xea, 0x8c, 0x0a, 0x03, 0x83, 0x73, 0x1c, 0x2c, 0xb8, 0x2a, 0x98, 0xc1,
+  0xc3, 0x38, 0xd2, 0x76, 0x65, 0xc8, 0xa1, 0xa9, 0xe9, 0x93, 0xb6, 0x2c,
+  0x06, 0xff, 0x85, 0x7b, 0x98, 0x0b, 0x55, 0x7e, 0xa5, 0xa9, 0xd5, 0x72,
+  0x34, 0x1c, 0x7b, 0xc5, 0x70, 0x92, 0x83, 0x10, 0x09, 0x43, 0xd5, 0xb2,
+  0x49, 0x32, 0xc5, 0xea, 0x10, 0x60, 0x4f, 0x0c, 0x40, 0x82, 0xac, 0x14,
+  0xdd, 0xeb, 0x5d, 0x99, 0xcd, 0x10, 0x75, 0x7c, 0x97, 0xf6, 0xe7, 0xbd,
+  0xc0, 0x5a, 0xf9, 0xe2, 0xd5, 0x8a, 0x19, 0xf5, 0xa5, 0x6b, 0xca, 0x57,
+  0x45, 0x67, 0xf1, 0xa4, 0xbe, 0x82, 0x03, 0x45, 0xa5, 0x93, 0xa5, 0x51,
+  0x7b, 0x57, 0x42, 0x0b, 0x53, 0x4d, 0x0f, 0x61, 0x7b, 0x19, 0x27, 0xe7,
+  0xe1, 0xb5, 0x9a, 0x53, 0x22, 0x3b, 0xcd, 0x05, 0xa1, 0x2c, 0x6c, 0x70,
+  0xc2, 0xde, 0xfa, 0x9d, 0x2b, 0x2c, 0xc8, 0x5a, 0x86, 0xc0, 0xef, 0x04,
+  0x50, 0x4b, 0xda, 0xf5, 0xc5, 0xd7, 0x99, 0x4b, 0xef, 0xef, 0xbf, 0x32,
+  0x32, 0xa4, 0x3c, 0xcf, 0x52, 0xdd, 0xc8, 0x6e, 0x86, 0xa0, 0xb4, 0x21,
+  0x62, 0x55, 0x4a, 0xbd, 0x2f, 0xb1, 0x2e, 0x95, 0xee, 0xea, 0xc5, 0xb3,
+  0xf4, 0xd2, 0x90, 0x5a, 0x6a, 0xd8, 0xe1, 0xa5, 0x2d, 0xfb, 0x8c, 0xfe,
+  0x95, 0x60, 0x8a, 0x87, 0x94, 0x37, 0x07, 0x19, 0xbf, 0x6b, 0x65, 0x80,
+  0xad, 0x8a, 0x36, 0xad, 0x31, 0x4f, 0x14, 0x44, 0x6b, 0x95, 0x02, 0x4a,
+  0xd3, 0xf7, 0x5e, 0xfa, 0x99, 0x9e, 0x2b, 0x9d, 0xc9, 0xdd, 0x2c, 0xa3,
+  0x7e, 0x23, 0xe2, 0x95, 0x18, 0x16, 0xb0, 0x65, 0xd4, 0x5e, 0x28, 0x9b,
+  0x11, 0x62, 0x9e, 0xd3, 0xdd, 0xbd, 0x5f, 0x9d, 0xa1, 0xa6, 0x2d, 0x05,
+  0x69, 0xe3, 0x55, 0x65, 0xa0, 0xcc, 0xae, 0x70, 0x57, 0xe5, 0xa4, 0xc5,
+  0xfe, 0xfa, 0x68, 0xe2, 0xf9, 0xbc, 0xb1, 0x1a, 0xf6, 0xec, 0x47, 0x78,
+  0x36, 0xc0, 0xb6, 0xb5, 0x2a, 0x8e, 0x4c, 0x10, 0x4b, 0x57, 0x0f, 0x31,
+  0x12, 0xe8, 0xab, 0xca, 0x15, 0xf1, 0x6e, 0x5a, 0x4a, 0x70, 0xd3, 0x78,
+  0xae, 0x01, 0x8f, 0xec, 0x5e, 0x75, 0x15, 0xd8, 0x50, 0x73, 0xaf, 0xbb,
+  0xf2, 0xda, 0x57, 0x2a, 0x9a, 0x8d, 0x48, 0x77, 0x68, 0x2a, 0x46, 0x10,
+  0x69, 0x15, 0x75, 0x89, 0x8e, 0xc6, 0xb9, 0x6f, 0x51, 0x92, 0x2c, 0x44,
+  0x86, 0x5e, 0x5e, 0xcc, 0xa1, 0x95, 0xb4, 0xd8, 0x38, 0xc4, 0x6b, 0xf7,
+  0xa8, 0x26, 0x96, 0x08, 0xb6, 0x23, 0x28, 0x06, 0x08, 0x92, 0xce, 0xcc,
+  0x0f, 0x3d, 0x2e, 0x81, 0x49, 0xcb, 0x2f, 0x09, 0x68, 0x25, 0x3a, 0xd3,
+  0x3f, 0xe5, 0x46, 0x6e, 0x11, 0x6f, 0x16, 0xf5, 0x4f, 0xff, 0x4d, 0x23,
+  0xe8, 0xc8, 0xf7, 0x2d, 0x4b, 0xaa, 0x6c, 0x9b, 0x81, 0xea, 0x18, 0xa7,
+  0xb9, 0xd0, 0x60, 0x9e, 0x07, 0x0d, 0xde, 0xc1, 0xb6, 0x1a, 0x84, 0x45,
+  0xaf, 0xf2, 0x77, 0x77, 0x7d, 0xef, 0x40, 0x23, 0x7d, 0x96, 0xf4, 0x09,
+  0x9c, 0x1b, 0x8e, 0xc1, 0x99, 0x00, 0xe1, 0x1a, 0x6c, 0xd1, 0x2d, 0x51,
+  0x6f, 0x68, 0x78, 0xab, 0xa9, 0xfe, 0x8a, 0xf0, 0x0b, 0x16, 0xe6, 0x29,
+  0xd0, 0xe4, 0x05, 0x58, 0xda, 0x78, 0x3e, 0xc8, 0x8d, 0xb5, 0xa8, 0x70,
+  0x8d, 0x72, 0x7d, 0x8d, 0x34, 0xaa, 0x95, 0x5f, 0xde, 0x23, 0x36, 0x78,
+  0x30, 0xf8, 0x18, 0x10, 0xf0, 0x7f, 0x3c, 0xc2, 0xa2, 0xea, 0x1f, 0xfc,
+  0x6e, 0x20, 0xb7, 0x77, 0x3c, 0x32, 0xcc, 0xf0, 0xe4, 0x1f, 0x2a, 0x00,
+  0x71, 0x88, 0x86, 0x0c, 0x1f, 0x89, 0x39, 0x41, 0xe0, 0xbf, 0xe9, 0x56,
+  0x81, 0x43, 0x59, 0xa3, 0x86, 0x96, 0x45, 0x2f, 0x9a, 0x51, 0xd0, 0x71,
+  0x91, 0x6f, 0x24, 0xfb, 0x7e, 0x53, 0x80, 0x24, 0xac, 0x55, 0xff, 0x91,
+  0x36, 0x38, 0x03, 0xa0, 0xc3, 0xb0, 0x38, 0x07, 0x80, 0xc6, 0x5c, 0x4e,
+  0x5e, 0x85, 0x53, 0x1c, 0xb7, 0x28, 0x2a, 0x7f, 0x8a, 0x73, 0x35, 0x60,
+  0x48, 0x06, 0x10, 0x41, 0x06, 0x12, 0xc0, 0x3c, 0x47, 0x6f, 0x9e, 0xfd,
+  0x1e, 0x24, 0xe9, 0x53, 0x4c, 0x2d, 0xbc, 0xed, 0x0e, 0xd9, 0x1b, 0xd2,
+  0xa0, 0xe0, 0xb3, 0xc0, 0xc2, 0xa0, 0xd8, 0xc0, 0x1c, 0x67, 0xff, 0xfe,
+  0x6d, 0x2c, 0x50, 0x22, 0xa3, 0xaf, 0xe9, 0x44, 0x8a, 0x5d, 0x3b, 0x1b,
+  0xbf, 0x17, 0x51, 0x80, 0x2d, 0x28, 0x7c, 0xaf, 0x8a, 0x6b, 0x5f, 0xc8,
+  0x60, 0xa1, 0x03, 0x70, 0x81, 0xb0, 0xdc, 0x0f, 0x03, 0xfd, 0x8b, 0x0c,
+  0x26, 0x68, 0x78, 0x3c, 0x54, 0xd8, 0xf4, 0xbd, 0x21, 0x73, 0x0d, 0x7e,
+  0x28, 0xbe, 0x69, 0xaf, 0xc6, 0xa7, 0xa4, 0xbf, 0x1b, 0xe9, 0x5c, 0xa3,
+  0x62, 0x63, 0x43, 0xf0, 0x43, 0xd6, 0x1a, 0x00, 0xcd, 0x1f, 0xfe, 0xc6,
+  0xdb, 0x67, 0xca, 0xd5, 0x96, 0x45, 0x96, 0x9b, 0x3e, 0x1a, 0x35, 0x9b,
+  0x46, 0xc0, 0x28, 0x38, 0x09, 0x1a, 0x9e, 0x78, 0x20, 0xc4, 0xd9, 0xdd,
+  0xf8, 0x96, 0x9d, 0x4f, 0x67, 0x33, 0x92, 0xc0, 0x2a, 0x6f, 0x17, 0x01,
+  0x06, 0x44, 0x76, 0xd8, 0x57, 0xf1, 0xf7, 0xae, 0xff, 0x59, 0xe6, 0x31,
+  0xb2, 0xd5, 0xfd, 0xe2, 0xd8, 0x5b, 0x38, 0x22, 0x6e, 0xf5, 0x40, 0x2b,
+  0x82, 0xd2, 0xe2, 0xee, 0x3f, 0x34, 0xe5, 0x85, 0x14, 0x9c, 0xd0, 0x65,
+  0xe7, 0x37, 0x39, 0x0b, 0x34, 0x44, 0xbd, 0x5c, 0xb6, 0x06, 0xca, 0x38,
+  0x0c, 0x35, 0x75, 0x47, 0x6e, 0xf6, 0xed, 0x5c, 0xa0, 0x4c, 0x0a, 0x35,
+  0x58, 0xa1, 0x8c, 0xf7, 0xa7, 0x33, 0xd0, 0xab, 0x09, 0x08, 0x2a, 0x90,
+  0x30, 0xba, 0x6a, 0xb5, 0xfe, 0x70, 0x97, 0x82, 0x63, 0xc3, 0xfd, 0xea,
+  0x5d, 0x52, 0x8b, 0xa4, 0x6b, 0xf5, 0x77, 0x0d, 0x93, 0xa5, 0xb5, 0xb5,
+  0x7b, 0x92, 0xed, 0x9d, 0x0f, 0x11, 0xdb, 0x62, 0x28, 0x08, 0xe7, 0x9a,
+  0xc2, 0x28, 0x98, 0xf5, 0x29, 0x72, 0x4f, 0x84, 0x3e, 0x55, 0x7f, 0xdf,
+  0x8f, 0xeb, 0x1e, 0xac, 0x2f, 0x67, 0xd3, 0x7b, 0xdd, 0xfa, 0xa2, 0xa0,
+  0x2c, 0xd2, 0x2d, 0xfe, 0xe8, 0x77, 0xf5, 0x01, 0xe8, 0x31, 0x00, 0x83,
+  0xd1, 0x33, 0x0c, 0x4f, 0x31, 0xe9, 0xe9, 0x88, 0x9a, 0x40, 0x8b, 0x88,
+  0x86, 0xca, 0x14, 0x3c, 0x2e, 0xaa, 0xc6, 0xbd, 0x99, 0xd1, 0xc6, 0xa5,
+  0x9e, 0xa2, 0x0a, 0xbf, 0x64, 0xbc, 0xb5, 0x1f, 0xa7, 0xc3, 0x80, 0xb5,
+  0x95, 0x32, 0x8d, 0x6d, 0x5e, 0x0c, 0x29, 0xea, 0x88, 0x51, 0xb6, 0x32,
+  0x06, 0x04, 0x41, 0x24, 0x7f, 0xff, 0x2a, 0x1d, 0x0f, 0xf0, 0x4a, 0x12,
+  0x94, 0xe5, 0x64, 0xb0, 0xb6, 0x33, 0x2a, 0xe1, 0xe3, 0x0a, 0x14, 0x15,
+  0x68, 0x73, 0xbf, 0xff, 0x80, 0x40, 0x4f, 0x55, 0xe0, 0x44, 0x63, 0xca,
+  0x94, 0xeb, 0x79, 0x24, 0xef, 0xfe, 0xbe, 0xfe, 0xf3, 0x9d, 0x78, 0x5b,
+  0x12, 0x22, 0x8f, 0x2e, 0x87, 0x83, 0x17, 0x26, 0x87, 0x68, 0x31, 0xa2,
+  0xbe, 0x21, 0xe1, 0xb7, 0x1b, 0x46, 0xef, 0xb5, 0xcd, 0xe1, 0xb2, 0x25,
+  0xa2, 0x01, 0x44, 0x35, 0x6f, 0xf7, 0x50, 0xf1, 0x00, 0xa8, 0xdb, 0x65,
+  0xfe, 0xa8, 0xd7, 0x17, 0xc3, 0xf9, 0x26, 0xa9, 0xf8, 0x79, 0x74, 0x91,
+  0x74, 0x04, 0xde, 0x10, 0xc7, 0xda, 0x7f, 0x9c, 0xca, 0xb7, 0x68, 0xbc,
+  0x90, 0x29, 0x30, 0xc7, 0xbf, 0x43, 0xbd, 0xd5, 0x08, 0x0d, 0xf0, 0xd9,
+  0xf1, 0x4a, 0xc6, 0xa7, 0x57, 0x25, 0x13, 0x97, 0x53, 0x6f, 0x54, 0xa3,
+  0x5e, 0x2c, 0x8b, 0x88, 0x01, 0x84, 0xeb, 0x13, 0x46, 0xcd, 0x98, 0x8f,
+  0xa8, 0x8a, 0x46, 0xa1, 0xb9, 0xb0, 0x0f, 0x1f, 0xa5, 0x06, 0x4b, 0x82,
+  0x09, 0x67, 0x93, 0x30, 0x0a, 0x71, 0xd2, 0xaf, 0x48, 0x57, 0xcf, 0xad,
+  0x2f, 0xea, 0x82, 0xbd, 0xd5, 0x70, 0x58, 0x61, 0x4f, 0x64, 0xe2, 0xf1,
+  0x7e, 0x94, 0xc3, 0x96, 0x10, 0xc1, 0x48, 0x38, 0x10, 0xd2, 0x97, 0xdb,
+  0xb3, 0xca, 0xd5, 0xd4, 0xfe, 0xb1, 0x69, 0xdb, 0x7b, 0x60, 0x12, 0x32,
+  0x9e, 0xea, 0xf2, 0x45, 0x34, 0xc9, 0x49, 0x85, 0xa2, 0xad, 0x6f, 0x13,
+  0x59, 0xdf, 0x27, 0x55, 0x58, 0xb5, 0x19, 0x66, 0xc8, 0x5a, 0xc7, 0x68,
+  0x88, 0x06, 0x2d, 0x04, 0x63, 0x26, 0x07, 0xd2, 0xc4, 0x83, 0xd6, 0xbd,
+  0x73, 0xf7, 0xc9, 0xfc, 0x1a, 0x71, 0x15, 0xe5, 0x0d, 0xf4, 0xf9, 0xcf,
+  0xb3, 0xbe, 0x06, 0x1c, 0x17, 0xf3, 0xac, 0x7f, 0x85, 0xaa, 0x17, 0xb8,
+  0xcf, 0x9b, 0xab, 0xda, 0x22, 0x81, 0x8f, 0xd0, 0x61, 0xa6, 0xf6, 0xf9,
+  0x21, 0x78, 0x41, 0x80, 0xc8, 0x2f, 0x99, 0xf8, 0x13, 0xb2, 0x7c, 0x1c,
+  0xa5, 0xe3, 0x54, 0xe7, 0x65, 0x31, 0xa2, 0xd5, 0x1f, 0xcc, 0xfc, 0x9b,
+  0xed, 0x67, 0x88, 0xf6, 0x6c, 0xb9, 0x0b, 0x25, 0x41, 0x8a, 0x22, 0x8f,
+  0x01, 0x00, 0x61, 0x3a, 0x6a, 0x94, 0xc5, 0x20, 0x53, 0x33, 0xa5, 0x42,
+  0x2f, 0x50, 0xce, 0x88, 0xa0, 0xe3, 0x2c, 0x79, 0x28, 0x7d, 0x95, 0x4f,
+  0x2f, 0x9b, 0xde, 0xee, 0xaf, 0x14, 0x5f, 0x7b, 0xa7, 0xa9, 0x3f, 0xf2,
+  0x28, 0x63, 0xd5, 0x6b, 0x06, 0xe8, 0xd1, 0xae, 0xed, 0x8b, 0x1e, 0xab,
+  0x2f, 0x4e, 0xde, 0x2a, 0x51, 0xbf, 0xf6, 0x31, 0x66, 0x95, 0x6a, 0xff,
+  0x9d, 0x45, 0x41, 0x81, 0x7c, 0x68, 0x47, 0x6b, 0x04, 0xba, 0xa1, 0xbd,
+  0x6d, 0x3e, 0x79, 0xac, 0xba, 0xaa, 0xfe, 0xfa, 0x7d, 0x5c, 0x25, 0xcc,
+  0xd2, 0xac, 0xca, 0x1e, 0x83, 0x0a, 0xd5, 0x81, 0xee, 0x61, 0x60, 0x14,
+  0x53, 0x9d, 0xd5, 0xb3, 0x92, 0xa1, 0x79, 0x66, 0x3c, 0xa0, 0x19, 0x7d,
+  0xfe, 0xfe, 0x7a, 0xd0, 0xf3, 0x3f, 0x46, 0xe8, 0xf8, 0x1b, 0xa9, 0xd8,
+  0xa5, 0x40, 0x10, 0x30, 0xb1, 0xc5, 0xc3, 0x4d, 0x35, 0x85, 0x8c, 0x2a,
+  0x1f, 0x42, 0xd6, 0x16, 0xff, 0xf6, 0x15, 0x76, 0x2d, 0x67, 0x83, 0x60,
+  0x71, 0x94, 0xac, 0xfe, 0xdc, 0xf5, 0xd9, 0xee, 0x76, 0xd9, 0xee, 0xca,
+  0xa3, 0xa4, 0x26, 0x71, 0x5b, 0x2d, 0xb3, 0x1a, 0x5b, 0x3a, 0xa6, 0xfd,
+  0x45, 0x5f, 0xb5, 0x04, 0xa1, 0xce, 0x03, 0x10, 0xaf, 0xa1, 0xe6, 0x08,
+  0x0a, 0x94, 0xfd, 0xba, 0x56, 0x57, 0xbd, 0xbc, 0xa8, 0x6d, 0x13, 0xf4,
+  0xfd, 0xad, 0xff, 0xd1, 0xcf, 0xf6, 0x76, 0xcc, 0x5b, 0x11, 0x5b, 0xd3,
+  0x60, 0xfa, 0xbf, 0xfe, 0xa9, 0x75, 0x4c, 0x2d, 0xe7, 0x7e, 0xb7, 0x3a,
+  0x8a, 0x3d, 0x16, 0x98, 0x51, 0x14, 0xef, 0x2e, 0xf2, 0x2f, 0xc9, 0xce,
+  0x83, 0x04, 0xf7, 0xdc, 0xde, 0xa1, 0x0e, 0x51, 0x49, 0xd9, 0x78, 0x88,
+  0x2c, 0xda, 0xf7, 0xa5, 0xd5, 0xef, 0xd0, 0x40, 0xf3, 0x25, 0x9c, 0x37,
+  0xd0, 0x5a, 0xef, 0x30, 0x8b, 0x7b, 0xa5, 0x1d, 0xe3, 0xe5, 0xac, 0xe5,
+  0xda, 0x6b, 0xa8, 0x2c, 0x5b, 0xa0, 0xc1, 0x41, 0x7b, 0xba, 0x59, 0x83,
+  0x62, 0xb3, 0x4b, 0xd3, 0xcb, 0xb6, 0xae, 0xb5, 0xde, 0x28, 0xf4, 0x29,
+  0xdf, 0xde, 0xb8, 0xbd, 0xf6, 0xd9, 0x92, 0xaf, 0x56, 0x82, 0x65, 0x14,
+  0x37, 0xf0, 0xea, 0xc9, 0x3d, 0xc5, 0x2b, 0xf5, 0x63, 0x6f, 0xb6, 0xdb,
+  0xc4, 0xde, 0x97, 0x57, 0x53, 0xd9, 0x9f, 0x8b, 0xcb, 0x61, 0x0c, 0x74,
+  0xe5, 0xd4, 0x4e, 0x6c, 0x5b, 0x5a, 0x8d, 0x5a, 0x81, 0x11, 0x2d, 0x3a,
+  0x7c, 0x7e, 0x23, 0x8f, 0x92, 0x6c, 0x68, 0x3d, 0x65, 0xb5, 0x0a, 0x47,
+  0x0a, 0xbd, 0x7f, 0xfe, 0x12, 0xcc, 0x2a, 0x68, 0x35, 0xdf, 0x8b, 0x07,
+  0xc3, 0xf1, 0x1d, 0x31, 0x78, 0x82, 0x3c, 0x05, 0x5d, 0x69, 0x5f, 0xd4,
+  0xfb, 0xbe, 0xdb, 0xef, 0xf8, 0x96, 0x50, 0xb1, 0x62, 0xe4, 0xca, 0xc4,
+  0x81, 0x1b, 0x1a, 0xd2, 0xd1, 0xeb, 0x73, 0xbe, 0xf6, 0xfb, 0x14, 0xb7,
+  0x7d, 0xdb, 0x7d, 0xda, 0xa4, 0x6c, 0x12, 0x97, 0x8c, 0x07, 0x24, 0x42,
+  0x98, 0xa8, 0x39, 0x01, 0x0d, 0x8e, 0x20, 0x32, 0xb5, 0x65, 0x78, 0x99,
+  0x21, 0x65, 0x96, 0x45, 0x0c, 0xd0, 0xf5, 0x74, 0x56, 0xcc, 0x1b, 0xa0,
+  0x06, 0x21, 0x36, 0xd8, 0x33, 0x62, 0x5c, 0x61, 0xb6, 0xbe, 0x90, 0xb9,
+  0x86, 0xf3, 0x68, 0x19, 0xc5, 0xfd, 0x96, 0x5e, 0x5f, 0xd8, 0xa0, 0xaf,
+  0x71, 0x72, 0xa0, 0x16, 0x19, 0x04, 0xb1, 0xd0, 0x43, 0x6d, 0x3c, 0x6d,
+  0x86, 0x8b, 0xfd, 0xff, 0xee, 0xd0, 0x56, 0xfa, 0x4b, 0x91, 0x0f, 0xbb,
+  0x9a, 0x0c, 0x36, 0x5a, 0x15, 0x06, 0xe6, 0x47, 0xe5, 0xec, 0x04, 0x1a,
+  0xce, 0x02, 0x2b, 0x4d, 0xfc, 0xb7, 0x7e, 0xd2, 0xac, 0x93, 0xa5, 0xb7,
+  0xd7, 0x3b, 0x67, 0x86, 0x70, 0x04, 0x8a, 0x96, 0xa4, 0x80, 0xf0, 0x90,
+  0x07, 0xa9, 0x79, 0x45, 0x9e, 0x06, 0x05, 0xa3, 0x63, 0x56, 0xd2, 0x30,
+  0x01, 0xec, 0xc1, 0xeb, 0x25, 0xe0, 0xca, 0x7f, 0x3d, 0x9c, 0x53, 0xfe,
+  0x64, 0xe0, 0x14, 0x10, 0x03, 0x83, 0xa7, 0x13, 0x82, 0x83, 0x1b, 0x66,
+  0xeb, 0x49, 0xb6, 0xf0, 0x19, 0x1f, 0xb2, 0x15, 0x7b, 0x62, 0x1f, 0x06,
+  0xda, 0x0c, 0x13, 0x96, 0x2e, 0x1e, 0x0e, 0xd2, 0x32, 0xd3, 0x63, 0x82,
+  0xff, 0x55, 0x33, 0x9e, 0x6b, 0xd6, 0xac, 0x6d, 0x6d, 0x06, 0x0a, 0x82,
+  0x43, 0x09, 0x4b, 0xb2, 0xe0, 0x83, 0x5b, 0x1e, 0x27, 0x9c, 0x97, 0xff,
+  0x8a, 0x1a, 0x6f, 0x7a, 0x88, 0x18, 0x22, 0xfd, 0xff, 0x74, 0x0b, 0x28,
+  0x07, 0xcb, 0x80, 0x1c, 0xbc, 0x98, 0x04, 0x02, 0xc6, 0xcc, 0xaa, 0x03,
+  0xde, 0xf3, 0x2a, 0x44, 0x0d, 0x9b, 0x39, 0x7c, 0xbd, 0xf4, 0xc0, 0x46,
+  0x04, 0x91, 0x1a, 0x6d, 0xdc, 0xcf, 0x83, 0x21, 0xfc, 0xe8, 0xe2, 0x21,
+  0xbf, 0x44, 0x0c, 0x34, 0x58, 0x7f, 0x9b, 0xf1, 0x24, 0xae, 0xcf, 0x64,
+  0xe6, 0x69, 0x66, 0x0d, 0xef, 0xca, 0xfd, 0xfe, 0x29, 0x52, 0x82, 0x95,
+  0x87, 0x40, 0x24, 0xaf, 0xbd, 0xe2, 0xe6, 0xda, 0xc1, 0x01, 0x3f, 0xdb,
+  0x6e, 0xf6, 0x5c, 0x62, 0xec, 0x80, 0xaf, 0xa0, 0xc1, 0x58, 0xa9, 0x6a,
+  0xaf, 0x65, 0x51, 0xef, 0x63, 0xd0, 0x04, 0x36, 0x0b, 0xe4, 0x80, 0x84,
+  0xaf, 0xe9, 0x14, 0xab, 0x64, 0x40, 0x56, 0xce, 0xee, 0x83, 0x22, 0x96,
+  0xe4, 0xb7, 0xa5, 0x9c, 0x52, 0xa0, 0x04, 0x06, 0x40, 0x0d, 0x05, 0x20,
+  0xec, 0x7c, 0x0c, 0x57, 0xf6, 0xc1, 0x15, 0x27, 0x43, 0xb8, 0x54, 0xa2,
+  0x54, 0x3f, 0xf0, 0x7a, 0x7a, 0x53, 0x83, 0x01, 0xb5, 0x6a, 0x14, 0x25,
+  0x82, 0x53, 0x4b, 0x83, 0x08, 0x9d, 0x2f, 0xbb, 0xd3, 0x5b, 0xab, 0x62,
+  0xc0, 0xc1, 0x41, 0x40, 0x86, 0x0c, 0x1f, 0xa4, 0xbb, 0xef, 0xa5, 0x56,
+  0xca, 0xad, 0xe9, 0x5d, 0xda, 0x59, 0x61, 0xa3, 0xc3, 0x5f, 0xfe, 0xfe,
+  0x2f, 0xff, 0x9e, 0x6b, 0x0f, 0xbf, 0x00, 0x00, 0xbc, 0x08, 0x6c, 0x78,
+  0x3a, 0xa9, 0x82, 0x10, 0x8c, 0x5f, 0xf4, 0xbf, 0x03, 0x03, 0xd1, 0xea,
+  0xb0, 0x2d, 0x14, 0xb6, 0x5b, 0xff, 0xde, 0x72, 0x15, 0x15, 0xe6, 0x47,
+  0x8e, 0xc7, 0xc2, 0x52, 0x71, 0x24, 0x7e, 0xda, 0xbf, 0x34, 0x5b, 0x8c,
+  0x4f, 0xee, 0x63, 0x7c, 0xbd, 0x43, 0x3b, 0x43, 0x91, 0x14, 0x15, 0xe6,
+  0x46, 0xcd, 0x63, 0x4c, 0xab, 0xd8, 0xaf, 0xfe, 0xa5, 0x9a, 0xc9, 0x63,
+  0x4a, 0xea, 0x86, 0x03, 0xb4, 0x2f, 0x0b, 0x6c, 0x0f, 0x80, 0xe9, 0x79,
+  0x77, 0xe8, 0x84, 0x5d, 0x8a, 0xb1, 0x42, 0x85, 0x49, 0xd8, 0xe5, 0x68,
+  0x44, 0xed, 0x03, 0x21, 0xb0, 0x8a, 0x0f, 0x95, 0xff, 0xd8, 0x9c, 0x38,
+  0xb1, 0x63, 0x8d, 0x82, 0x9d, 0x35, 0x8d, 0x8f, 0x93, 0x7e, 0x72, 0xa9,
+  0x6b, 0x29, 0x2c, 0xbc, 0x9d, 0x07, 0x6b, 0xf9, 0x90, 0xe6, 0x0d, 0x80,
+  0xa3, 0xa3, 0xc9, 0x42, 0x00, 0x1d, 0x1c, 0xb4, 0xce, 0x7f, 0x4b, 0x12,
+  0xef, 0xa0, 0xe2, 0xcb, 0x6d, 0xe5, 0xfe, 0x0d, 0xb1, 0x4f, 0x75, 0x4e,
+  0x87, 0x80, 0x24, 0x56, 0x3d, 0x06, 0x4a, 0x07, 0x87, 0xca, 0x73, 0x13,
+  0xf8, 0xbd, 0x3c, 0x9a, 0x06, 0x15, 0x6c, 0xb1, 0x12, 0xdd, 0xf8, 0xdb,
+  0x0a, 0xc3, 0x82, 0xd1, 0x6a, 0x1e, 0x15, 0x9a, 0xe6, 0xc6, 0x40, 0x74,
+  0x4b, 0x54, 0x24, 0x0f, 0xb5, 0xb6, 0x55, 0xf9, 0xab, 0xfe, 0xf9, 0xa5,
+  0x28, 0xef, 0xcd, 0x40, 0xd0, 0xc0, 0x7f, 0xd4, 0xb4, 0x7f, 0x91, 0x33,
+  0x4d, 0xee, 0x62, 0xbd, 0x5d, 0x96, 0x2a, 0x8d, 0x51, 0x11, 0xc9, 0x54,
+  0x0a, 0x01, 0xa0, 0x10, 0xc0, 0xf8, 0xf4, 0x03, 0x52, 0xeb, 0x29, 0xf6,
+  0x4c, 0xce, 0x8e, 0x13, 0x4d, 0xb1, 0xa6, 0xb0, 0xd7, 0x83, 0x70, 0xdc,
+  0x18, 0x84, 0x5a, 0x07, 0x07, 0xca, 0xcb, 0x27, 0xf6, 0x2d, 0x43, 0xae,
+  0xa3, 0x51, 0x51, 0x03, 0x05, 0x53, 0xd2, 0x6f, 0xe2, 0xca, 0x61, 0x86,
+  0x9a, 0xa5, 0xed, 0x88, 0x04, 0x86, 0xd3, 0xa6, 0xf6, 0x2a, 0x4c, 0xdd,
+  0x5f, 0x92, 0x62, 0xd6, 0x92, 0x2e, 0x64, 0x2e, 0xa6, 0xc1, 0x25, 0xac,
+  0x10, 0x47, 0xed, 0xfb, 0xa2, 0x23, 0x5e, 0x93, 0x7e, 0x49, 0x2d, 0x05,
+  0xaa, 0x82, 0x32, 0x7c, 0x48, 0x5f, 0x0b, 0x57, 0x2c, 0xca, 0x56, 0xb6,
+  0x49, 0x56, 0xe0, 0xdd, 0x18, 0x30, 0x98, 0x5e, 0x3e, 0x95, 0x5b, 0x11,
+  0x2d, 0xea, 0x9d, 0x97, 0x5a, 0xce, 0x70, 0xa9, 0x07, 0x46, 0x2a, 0x41,
+  0x5c, 0x16, 0x10, 0xcd, 0xf6, 0x6a, 0x8f, 0x41, 0x62, 0x3d, 0x31, 0x7a,
+  0xa1, 0xea, 0xb1, 0xb9, 0x67, 0xba, 0xb5, 0x10, 0x37, 0x66, 0xef, 0x49,
+  0x3c, 0x16, 0x21, 0x44, 0x7f, 0xdd, 0xef, 0xf9, 0x9a, 0xb0, 0xd9, 0x69,
+  0x36, 0x2d, 0x61, 0xe1, 0x9d, 0xc6, 0x7e, 0x9e, 0x6e, 0x20, 0xe8, 0x7a,
+  0x4a, 0x7c, 0x43, 0xf1, 0xe4, 0xfa, 0x65, 0x4d, 0xed, 0xeb, 0x3f, 0xf1,
+  0x5e, 0xc5, 0x97, 0x15, 0x8d, 0x5a, 0xb9, 0xf6, 0xbc, 0xa5, 0x84, 0xf7,
+  0x14, 0xf9, 0x46, 0xde, 0x5b, 0xfc, 0x45, 0x61, 0x2b, 0x85, 0x8c, 0x24,
+  0xf4, 0xcb, 0xbc, 0x95, 0x47, 0x42, 0xa3, 0xb4, 0x3f, 0x4c, 0xa0, 0x45,
+  0xe2, 0x21, 0x12, 0x70, 0x52, 0x18, 0x15, 0x83, 0x7d, 0x2a, 0xa0, 0x0c,
+  0x6c, 0x21, 0xb2, 0x3e, 0xf2, 0x98, 0x06, 0x1a, 0x2e, 0x55, 0xbd, 0x8d,
+  0xed, 0x6e, 0x30, 0xc5, 0xee, 0x60, 0xdb, 0x7a, 0xa5, 0x49, 0x60, 0x74,
+  0x0c, 0x40, 0xd4, 0xb8, 0x84, 0x80, 0x98, 0xa6, 0xde, 0x6d, 0xe8, 0xac,
+  0x2f, 0x26, 0x4f, 0x9e, 0x54, 0xd3, 0x76, 0x01, 0x9f, 0xb5, 0x85, 0x48,
+  0xb9, 0x6c, 0x96, 0x86, 0x80, 0x26, 0xae, 0xd6, 0xef, 0x51, 0x51, 0xac,
+  0xe3, 0xd3, 0x5c, 0x73, 0xcf, 0x8d, 0xb6, 0x4b, 0x51, 0x94, 0x23, 0xa0,
+  0xe3, 0x06, 0x99, 0x63, 0xe5, 0xe0, 0x43, 0xec, 0x71, 0x68, 0x87, 0x9d,
+  0x9d, 0xe0, 0x6e, 0x0b, 0x7b, 0x56, 0xa8, 0xb6, 0xe6, 0x96, 0xec, 0xdf,
+  0x66, 0x96, 0x58, 0x88, 0x3d, 0x96, 0x72, 0xc1, 0x14, 0x8d, 0x44, 0x89,
+  0x9b, 0x4d, 0xd1, 0xc6, 0xde, 0x5d, 0x2d, 0xb8, 0x05, 0x14, 0xd4, 0x76,
+  0x44, 0x0a, 0x4c, 0x97, 0xd3, 0x54, 0xee, 0xd8, 0xf1, 0x5b, 0x00, 0xa6,
+  0x1f, 0x0f, 0xcb, 0xb7, 0x6c, 0x69, 0x66, 0xd5, 0x1b, 0xce, 0xb7, 0xb7,
+  0x92, 0x87, 0x28, 0xcc, 0x27, 0x38, 0xca, 0x71, 0xf3, 0x7a, 0xbf, 0x87,
+  0xe5, 0xdf, 0xc6, 0x50, 0x6e, 0x46, 0x27, 0x3f, 0x68, 0x72, 0x56, 0x0c,
+  0x44, 0x44, 0x47, 0x54, 0xa3, 0x7c, 0x20, 0xf7, 0x7c, 0x3d, 0xd8, 0xd7,
+  0x62, 0x39, 0x7f, 0x7b, 0x60, 0x54, 0xba, 0x6c, 0xbf, 0x54, 0x93, 0xb2,
+  0xa9, 0xdf, 0x0e, 0xd2, 0x40, 0xe7, 0x24, 0xbd, 0x02, 0x4a, 0x79, 0x4b,
+  0x4c, 0x0d, 0x7c, 0x12, 0x47, 0x3e, 0x37, 0x79, 0x65, 0x9a, 0x2a, 0x1e,
+  0x0f, 0xda, 0x50, 0xb6, 0x07, 0xcd, 0xc2, 0xc5, 0xeb, 0x79, 0x7d, 0x01,
+  0x1d, 0x40, 0x31, 0x0b, 0x57, 0xca, 0xa9, 0x33, 0x79, 0xf2, 0xad, 0x51,
+  0x9b, 0xbc, 0xe4, 0x92, 0x44, 0x40, 0xc2, 0x75, 0x58, 0xc4, 0xe1, 0xfe,
+  0xfe, 0x5f, 0xe6, 0x7f, 0xcc, 0x42, 0xc9, 0xc9, 0xc8, 0xc4, 0x99, 0x67,
+  0x83, 0x4d, 0xee, 0x83, 0x10, 0x24, 0x93, 0x3c, 0xd2, 0xa1, 0xea, 0x66,
+  0x6a, 0x94, 0xcc, 0x37, 0xa5, 0x9d, 0x5f, 0xb9, 0xfa, 0x0c, 0x73, 0x73,
+  0xd6, 0x9f, 0x3e, 0x59, 0x5a, 0xc2, 0xa2, 0xab, 0x71, 0x40, 0x8b, 0x49,
+  0x68, 0x72, 0x1b, 0x03, 0x10, 0x28, 0x91, 0x49, 0x79, 0x76, 0xb4, 0x5a,
+  0x58, 0xdb, 0x4d, 0x83, 0x2f, 0xa2, 0x2d, 0x43, 0x21, 0xfb, 0x12, 0x35,
+  0x96, 0x29, 0x7b, 0x17, 0x36, 0xb0, 0xc7, 0xbb, 0xea, 0x8e, 0xf2, 0xc0,
+  0x2d, 0xd0, 0xe5, 0x70, 0xf0, 0x50, 0x92, 0xae, 0x64, 0xd2, 0xcc, 0x59,
+  0x3d, 0xcd, 0xea, 0x15, 0xa5, 0x97, 0xb0, 0x36, 0x04, 0x85, 0xed, 0x3f,
+  0xf2, 0x03, 0x0d, 0x98, 0xf7, 0x27, 0x27, 0xf5, 0x16, 0xa9, 0x42, 0x76,
+  0xd7, 0x69, 0x9b, 0xa3, 0x69, 0x5a, 0xcf, 0x14, 0xa2, 0xe7, 0x06, 0x9f,
+  0x77, 0x96, 0xcb, 0x96, 0xf0, 0x6d, 0xc5, 0xe5, 0xde, 0x5a, 0xb8, 0x2d,
+  0xe3, 0x58, 0x10, 0x73, 0x07, 0x37, 0x9f, 0xbf, 0xe7, 0x3a, 0xa6, 0x87,
+  0x92, 0x07, 0x96, 0x88, 0x84, 0x1d, 0xb9, 0xb8, 0xb5, 0xee, 0xdd, 0xda,
+  0x36, 0xc1, 0x12, 0x1a, 0x76, 0xee, 0x95, 0x22, 0xea, 0x22, 0x45, 0x90,
+  0x48, 0x09, 0x69, 0x60, 0x6e, 0xb6, 0x9d, 0xf4, 0x6c, 0xb2, 0x25, 0xca,
+  0x78, 0x4d, 0x29, 0x7b, 0xb3, 0x96, 0xa2, 0x97, 0xb2, 0xc8, 0x88, 0x94,
+  0xfc, 0x83, 0x2c, 0xa9, 0x8a, 0xde, 0xf3, 0x18, 0x92, 0x77, 0xf5, 0x68,
+  0x79, 0x3f, 0x78, 0xb7, 0xca, 0x21, 0x54, 0xe8, 0xcf, 0x82, 0xae, 0x3d,
+  0x49, 0xef, 0xaa, 0x99, 0x7d, 0x19, 0x62, 0x74, 0x41, 0xc5, 0x17, 0xaa,
+  0x38, 0xb5, 0xe2, 0x92, 0xbc, 0x31, 0x27, 0xbd, 0x77, 0xa4, 0xcd, 0x8f,
+  0x07, 0xa0, 0xa3, 0x07, 0x02, 0x9c, 0x46, 0x03, 0x4d, 0xa4, 0x82, 0x06,
+  0xdf, 0x36, 0x88, 0xb5, 0x0a, 0xd7, 0x06, 0xf8, 0xcb, 0x5d, 0x06, 0x1a,
+  0x93, 0xee, 0x34, 0x01, 0xc9, 0x34, 0x44, 0x55, 0xec, 0xe1, 0xae, 0x5b,
+  0xa7, 0xc9, 0x44, 0x8d, 0x7f, 0xc9, 0x95, 0x01, 0x86, 0x4b, 0xbc, 0xb0,
+  0xe6, 0xaf, 0x56, 0x5b, 0xd0, 0x39, 0xd2, 0xa1, 0x14, 0x05, 0xb1, 0x1c,
+  0x4a, 0x0f, 0xc7, 0xda, 0x24, 0x0e, 0x75, 0x8c, 0x2a, 0x50, 0x58, 0x8e,
+  0x16, 0x5b, 0xce, 0x5d, 0x1b, 0xe2, 0xe1, 0x61, 0x78, 0xe1, 0x1c, 0xc9,
+  0x84, 0x49, 0x86, 0x3f, 0x46, 0x07, 0xe9, 0x7c, 0x97, 0x99, 0x64, 0x66,
+  0x8e, 0x22, 0x32, 0x49, 0x43, 0x62, 0x30, 0xa4, 0xc3, 0x45, 0x4a, 0x36,
+  0xcd, 0xb3, 0xb0, 0xda, 0x22, 0x26, 0x24, 0x00, 0x70, 0xfd, 0xa5, 0x7f,
+  0xf0, 0xfc, 0x40, 0xa9, 0x98, 0x0e, 0xbe, 0xaa, 0x16, 0x6a, 0x74, 0x5c,
+  0x2d, 0x8a, 0x56, 0xcc, 0x02, 0xa6, 0x11, 0x2e, 0xf3, 0x65, 0x94, 0x38,
+  0xe2, 0xc6, 0xec, 0x43, 0xc0, 0xd0, 0x16, 0x8a, 0x2a, 0x44, 0xc6, 0x3e,
+  0x4e, 0x39, 0xef, 0x2e, 0x6f, 0x97, 0x2b, 0x88, 0xfb, 0x2d, 0x97, 0xdc,
+  0x11, 0x14, 0x1e, 0x1f, 0x7c, 0x4b, 0x4c, 0xa8, 0x21, 0xb3, 0xa9, 0x7b,
+  0xfb, 0x26, 0xcf, 0x36, 0x8f, 0x1a, 0x63, 0x93, 0xbe, 0x90, 0x19, 0x01,
+  0x58, 0x76, 0x04, 0x45, 0xa3, 0x01, 0xe3, 0x1b, 0x19, 0x2f, 0xd1, 0x05,
+  0x56, 0x97, 0x33, 0x41, 0x58, 0xa1, 0x7d, 0xbf, 0x9f, 0x0f, 0x69, 0x21,
+  0x5f, 0x70, 0x15, 0xf8, 0x65, 0x14, 0xa2, 0x43, 0x19, 0x9a, 0xc4, 0x62,
+  0x75, 0xbe, 0xec, 0xd5, 0xe5, 0x2d, 0xa8, 0x6d, 0x01, 0x22, 0xab, 0x2c,
+  0x75, 0x5b, 0x17, 0x02, 0x28, 0xfa, 0xa6, 0xfa, 0x71, 0xce, 0x08, 0x0c,
+  0x50, 0x32, 0x58, 0x57, 0xc1, 0x51, 0x8a, 0x01, 0xa0, 0x80, 0xde, 0x07,
+  0xcc, 0xe9, 0x6f, 0xb7, 0x90, 0x19, 0x76, 0xaa, 0x82, 0x9e, 0x87, 0xa0,
+  0x24, 0xf0, 0x28, 0x95, 0x32, 0xc6, 0xfd, 0x22, 0xb6, 0xac, 0x95, 0x7e,
+  0xa3, 0x63, 0x64, 0xfd, 0x40, 0x1c, 0xa8, 0xa0, 0xef, 0x83, 0xe5, 0x40,
+  0x0e, 0xa0, 0x1d, 0x06, 0xc0, 0x36, 0x95, 0xb5, 0x63, 0xce, 0xe6, 0xad,
+  0x0b, 0x28, 0x75, 0xb2, 0x2c, 0xb0, 0x70, 0x16, 0x31, 0x1f, 0xda, 0x4e,
+  0xda, 0x81, 0x03, 0xd8, 0x0e, 0x03, 0xe9, 0x7e, 0x39, 0xa5, 0xed, 0x37,
+  0x14, 0x17, 0x6e, 0xa2, 0x9c, 0xb2, 0xd9, 0xd0, 0x70, 0x74, 0x50, 0x64,
+  0x2d, 0xa7, 0xde, 0x76, 0xa9, 0x51, 0xc8, 0x33, 0xe4, 0x01, 0x3d, 0xa6,
+  0x0b, 0xc2, 0x00, 0x80, 0xce, 0xe4, 0x1c, 0x26, 0x6a, 0x23, 0xe6, 0x4b,
+  0xb5, 0x1d, 0x02, 0x7b, 0xd3, 0x21, 0x9e, 0x04, 0x1f, 0x97, 0xb6, 0x20,
+  0xb7, 0x14, 0xb5, 0xd1, 0xb7, 0xb9, 0xb9, 0xcb, 0x51, 0xac, 0x37, 0xd0,
+  0x4b, 0x4c, 0x63, 0x77, 0xa4, 0xd5, 0xc9, 0x87, 0x10, 0x36, 0x3f, 0x10,
+  0x68, 0x29, 0xf4, 0x11, 0x53, 0x66, 0xfc, 0x3a, 0xdb, 0x1b, 0xe7, 0x56,
+  0x5f, 0x4b, 0x54, 0x6e, 0x60, 0x2d, 0x04, 0x8a, 0xc7, 0x89, 0xa8, 0x95,
+  0x7b, 0xf6, 0x74, 0xb6, 0x4a, 0xd0, 0xe4, 0xae, 0xa8, 0xbc, 0xe4, 0xbf,
+  0x0e, 0x57, 0x52, 0x1d, 0x02, 0x50, 0x5e, 0xd1, 0x23, 0xc1, 0xf3, 0x29,
+  0xc7, 0xd6, 0x34, 0x9c, 0xb0, 0x72, 0x54, 0x8b, 0x64, 0x9d, 0x5d, 0xcb,
+  0x89, 0x40, 0x77, 0xdb, 0x5a, 0x1f, 0x6f, 0xae, 0xdf, 0x2a, 0x1c, 0xab,
+  0xde, 0x07, 0x9e, 0xd9, 0x11, 0x06, 0x60, 0xc3, 0x57, 0x9e, 0xe4, 0xef,
+  0x54, 0x85, 0x91, 0x00, 0x00, 0xc1, 0x08, 0x6c, 0x37, 0x01, 0xaf, 0x67,
+  0xc1, 0x16, 0x4e, 0xf3, 0x6a, 0x94, 0x75, 0x75, 0xea, 0xe0, 0xc2, 0x71,
+  0x28, 0x84, 0x0c, 0xad, 0x58, 0xf8, 0x15, 0x99, 0xed, 0xfe, 0x5f, 0xe6,
+  0x32, 0xba, 0x8f, 0x28, 0xb7, 0xf2, 0xd6, 0x3d, 0xaa, 0x14, 0xb6, 0x04,
+  0x00, 0xaf, 0xc5, 0x88, 0x84, 0x14, 0xa0, 0xa6, 0x4c, 0x91, 0xb5, 0x4a,
+  0xa6, 0xb7, 0xc8, 0x1f, 0xde, 0xdd, 0x96, 0x70, 0x18, 0x93, 0x0a, 0x81,
+  0x84, 0xe1, 0x9b, 0xc9, 0x58, 0x57, 0xea, 0x20, 0x37, 0x3c, 0x96, 0xd8,
+  0x06, 0x2c, 0xa5, 0xb2, 0xd9, 0x7b, 0x7d, 0xfd, 0x11, 0x73, 0x4a, 0x94,
+  0x82, 0xdc, 0x2f, 0x99, 0x2a, 0x30, 0x4b, 0x16, 0xab, 0x9e, 0x6c, 0x31,
+  0x03, 0x0f, 0x55, 0xb0, 0xda, 0x5f, 0x6c, 0xfb, 0x29, 0xda, 0x57, 0xea,
+  0xcc, 0xac, 0xac, 0x94, 0x7d, 0xb7, 0xf4, 0x1c, 0x5d, 0x18, 0x06, 0x02,
+  0x8d, 0x66, 0x73, 0x4a, 0xcb, 0x7e, 0xac, 0x3b, 0x2d, 0x16, 0x06, 0x7a,
+  0x55, 0x85, 0xb7, 0xdf, 0xb3, 0xfd, 0x51, 0xfd, 0x8a, 0x25, 0xe2, 0xd6,
+  0x40, 0xec, 0x12, 0x06, 0xbb, 0x77, 0xec, 0xeb, 0x5f, 0xff, 0xf7, 0x33,
+  0x69, 0x69, 0x6f, 0x6b, 0x62, 0x0f, 0x2c, 0x5e, 0x83, 0x21, 0xc0, 0x60,
+  0x96, 0x2a, 0x9b, 0xdf, 0x75, 0x42, 0x35, 0x19, 0xde, 0xe2, 0xe8, 0xe7,
+  0x83, 0x7d, 0x58, 0x69, 0x37, 0xd2, 0x43, 0x87, 0x1e, 0x6d, 0x7c, 0x9d,
+  0xab, 0x59, 0x09, 0x6a, 0xd3, 0xa8, 0xcf, 0x0b, 0x1a, 0x00, 0xd4, 0xfe,
+  0xcc, 0xf7, 0xa6, 0x45, 0x12, 0x2e, 0xba, 0x04, 0x40, 0x97, 0x37, 0x39,
+  0x67, 0x94, 0x59, 0x44, 0x54, 0x37, 0xa2, 0x83, 0xa5, 0x5e, 0x0e, 0xaf,
+  0x4a, 0x73, 0x96, 0x12, 0x8d, 0xc1, 0xd8, 0x2b, 0x37, 0xdf, 0xff, 0xba,
+  0xa2, 0x85, 0x90, 0xc3, 0x65, 0x30, 0x0e, 0xd6, 0xd9, 0x2e, 0x53, 0x24,
+  0x68, 0x3f, 0x55, 0x47, 0x76, 0x2f, 0xac, 0x87, 0xb2, 0x5e, 0x83, 0x12,
+  0x2e, 0xa0, 0x2c, 0x04, 0xc0, 0xf8, 0x76, 0xd0, 0x18, 0xd5, 0x38, 0xa3,
+  0x99, 0x7b, 0xd5, 0x94, 0x54, 0x21, 0x5f, 0x97, 0xc5, 0x93, 0x37, 0x34,
+  0xb6, 0x6a, 0xdc, 0x58, 0xaa, 0xca, 0xb0, 0x23, 0x9e, 0x06, 0x20, 0x20,
+  0x02, 0x17, 0xe2, 0x65, 0x55, 0x96, 0x5b, 0xdd, 0xbb, 0xea, 0x58, 0x05,
+  0x1a, 0x60, 0x6e, 0x59, 0xd0, 0xdc, 0x0a, 0xe1, 0x82, 0x98, 0x85, 0xbd,
+  0xe8, 0x3e, 0x4f, 0xff, 0x65, 0x7b, 0xa7, 0x53, 0x16, 0xb2, 0x91, 0x23,
+  0x61, 0xec, 0x84, 0xaa, 0x71, 0x65, 0x89, 0xe7, 0xed, 0x8e, 0x72, 0x4e,
+  0x95, 0x7b, 0x27, 0x03, 0x7b, 0x22, 0x20, 0x60, 0x8c, 0x20, 0xfc, 0x7f,
+  0x58, 0x68, 0x3e, 0xf6, 0x95, 0xd0, 0xea, 0x41, 0x13, 0xc8, 0x7b, 0x46,
+  0x88, 0x8f, 0xbb, 0xff, 0x50, 0xf5, 0x0d, 0x44, 0x8e, 0x0a, 0xad, 0xce,
+  0x4e, 0xbd, 0x53, 0x19, 0xe2, 0x51, 0x07, 0xc3, 0xff, 0x2b, 0x51, 0x8d,
+  0x96, 0xcc, 0xc4, 0x1c, 0x9f, 0x85, 0x92, 0x5a, 0x32, 0xba, 0x0c, 0x26,
+  0xe1, 0x08, 0x7c, 0x0c, 0xa0, 0x7c, 0xa8, 0x79, 0x9f, 0xad, 0xf9, 0x37,
+  0xf7, 0x8b, 0xdd, 0x51, 0x96, 0xdb, 0x3d, 0x3f, 0xa3, 0x75, 0x1d, 0xa5,
+  0x62, 0xb1, 0xb8, 0x28, 0xd2, 0x46, 0xc1, 0x54, 0x24, 0x35, 0x95, 0x43,
+  0x29, 0xe2, 0xb5, 0x6a, 0xef, 0xef, 0x4b, 0x7c, 0xbc, 0x0f, 0x30, 0xad,
+  0xb0, 0x54, 0x82, 0xa3, 0x00, 0x50, 0x5c, 0x04, 0x51, 0xe4, 0xf4, 0xd9,
+  0xe2, 0xc6, 0x47, 0x05, 0x7c, 0xca, 0x36, 0x58, 0xd0, 0x73, 0xc8, 0x65,
+  0xec, 0x5a, 0x50, 0x5a, 0xbb, 0x78, 0x41, 0x48, 0xd8, 0x8e, 0x58, 0x0a,
+  0xdc, 0x4f, 0x9e, 0xdd, 0x06, 0x43, 0x3d, 0xfc, 0xf5, 0xe7, 0x2d, 0x50,
+  0x38, 0xd0, 0x7c, 0xbf, 0xfe, 0xc5, 0xad, 0x6c, 0xdd, 0xe6, 0x2e, 0x2e,
+  0x38, 0x61, 0x5c, 0xf2, 0x56, 0x22, 0xb6, 0x11, 0xe4, 0x9d, 0x36, 0x78,
+  0xf8, 0x85, 0x44, 0x01, 0x07, 0xed, 0xdb, 0x61, 0x67, 0x61, 0xa2, 0x74,
+  0xb8, 0x1e, 0x52, 0x79, 0x1c, 0x99, 0x7f, 0xe7, 0x0a, 0x6c, 0x0a, 0xc6,
+  0x3f, 0xed, 0x5b, 0xcb, 0x71, 0x6b, 0x4d, 0x57, 0x23, 0xe0, 0x87, 0x8a,
+  0xfe, 0x55, 0x29, 0x62, 0x85, 0xd0, 0x93, 0x22, 0xb4, 0xee, 0xcb, 0x2e,
+  0x21, 0x36, 0x34, 0x65, 0x1c, 0x23, 0xdb, 0x18, 0x0f, 0xe2, 0xbc, 0x50,
+  0xa2, 0xf7, 0x9c, 0xbb, 0xb5, 0x1d, 0xde, 0xc4, 0x41, 0xc0, 0x58, 0xbb,
+  0x4a, 0xc3, 0xea, 0x99, 0xa0, 0x60, 0xe0, 0xbf, 0x71, 0x7a, 0x0c, 0x1c,
+  0xb7, 0x4b, 0x38, 0x1c, 0x95, 0x47, 0xa0, 0x96, 0xe6, 0xf9, 0x59, 0xaf,
+  0xb5, 0xbc, 0x37, 0xc9, 0x09, 0x87, 0x81, 0xdc, 0x1f, 0x33, 0xea, 0x05,
+  0xd5, 0x97, 0x53, 0x7c, 0x92, 0x7f, 0xa5, 0x28, 0x9c, 0x63, 0x64, 0x07,
+  0xab, 0x9c, 0xe5, 0x05, 0xa9, 0x64, 0x87, 0x98, 0x0e, 0x2f, 0x67, 0x6a,
+  0xf5, 0x56, 0x32, 0xa9, 0x4a, 0x1e, 0x4b, 0x3f, 0xe0, 0x76, 0x3c, 0xcf,
+  0xc6, 0xc5, 0xf3, 0xeb, 0x8e, 0x7a, 0x55, 0x17, 0xa8, 0xf9, 0x28, 0x56,
+  0x24, 0xc0, 0x2e, 0x07, 0xf7, 0xdc, 0xc5, 0x2c, 0x0f, 0x98, 0x52, 0x86,
+  0xfe, 0xfa, 0xf7, 0xb0, 0x66, 0xa4, 0x18, 0x86, 0x33, 0x2c, 0xda, 0x39,
+  0xd9, 0xfc, 0x69, 0xa9, 0x14, 0xf2, 0x44, 0x53, 0x91, 0x61, 0x13, 0x42,
+  0xd3, 0x0f, 0x7d, 0x97, 0xfe, 0xe2, 0x64, 0x9f, 0xfc, 0x80, 0x66, 0xfa,
+  0x74, 0xdd, 0xb2, 0x70, 0xea, 0xc3, 0xc6, 0xff, 0xa5, 0xc0, 0x6f, 0xfc,
+  0x52, 0xa7, 0x67, 0xbd, 0x16, 0x42, 0xb8, 0x30, 0x26, 0x98, 0x4e, 0xd0,
+  0x7e, 0x3e, 0x50, 0x86, 0x0d, 0xd7, 0x5e, 0x71, 0x6b, 0x4f, 0xa8, 0x92,
+  0xfb, 0x5a, 0x2c, 0xef, 0x40, 0xd7, 0x3c, 0xa3, 0x9c, 0xec, 0x07, 0x07,
+  0x3c, 0x01, 0x32, 0xda, 0x55, 0x9c, 0xc3, 0x57, 0xb2, 0x29, 0x95, 0x0f,
+  0x48, 0x76, 0xc0, 0xeb, 0x7a, 0x8a, 0x52, 0xd3, 0x6b, 0xf1, 0x70, 0xdb,
+  0x48, 0x92, 0x2b, 0x53, 0x59, 0xcc, 0xa1, 0xe7, 0x3b, 0x91, 0x7b, 0xf2,
+  0x4a, 0x6f, 0x0c, 0x20, 0x5b, 0x2a, 0x8f, 0xf2, 0xe4, 0xb0, 0xae, 0x59,
+  0xc5, 0xc8, 0x65, 0xba, 0x53, 0x56, 0xe5, 0x58, 0x2b, 0x2a, 0xd4, 0x98,
+  0xba, 0x0b, 0xc0, 0xc9, 0x70, 0x60, 0xae, 0x15, 0x16, 0x7c, 0x6c, 0x45,
+  0x19, 0x83, 0x7b, 0xd5, 0xbd, 0x0a, 0x69, 0xff, 0x6d, 0xcc, 0x5a, 0xb2,
+  0x39, 0x53, 0x24, 0xd9, 0x5a, 0x5a, 0x72, 0x8a, 0x4b, 0xe6, 0xd5, 0x6d,
+  0x66, 0x31, 0xd8, 0x86, 0xaf, 0xda, 0xa4, 0x15, 0x20, 0xb5, 0xeb, 0xf2,
+  0xd4, 0x77, 0xa3, 0x2b, 0x38, 0x44, 0x70, 0x19, 0x48, 0x29, 0xbd, 0x73,
+  0x33, 0x01, 0x4e, 0xcd, 0xe1, 0x50, 0x14, 0x95, 0x0b, 0xd6, 0xce, 0x64,
+  0x78, 0x9e, 0x07, 0x4e, 0x4d, 0x4e, 0x2a, 0x55, 0xef, 0xe3, 0x31, 0x85,
+  0xfb, 0xb6, 0x87, 0x51, 0x4f, 0xea, 0x9e, 0xd1, 0xb9, 0x5a, 0xe1, 0x68,
+  0xf4, 0xbd, 0x28, 0xfd, 0x55, 0xdd, 0x05, 0x30, 0x29, 0xd5, 0x4e, 0xa8,
+  0x4a, 0x5d, 0xff, 0x6c, 0x2c, 0x88, 0xa7, 0x06, 0xe1, 0x6d, 0x44, 0x93,
+  0xfc, 0x0f, 0xc0, 0xcf, 0x3b, 0xde, 0x8d, 0xb7, 0xf5, 0x1f, 0xec, 0x11,
+  0x51, 0x03, 0xe4, 0x40, 0x0e, 0x2c, 0xd9, 0x18, 0x6b, 0xfb, 0x33, 0x81,
+  0xed, 0xe4, 0x88, 0xa7, 0xbd, 0xe6, 0xea, 0xc1, 0xc0, 0x38, 0x3d, 0x23,
+  0x2b, 0x10, 0x38, 0xa4, 0xc6, 0x43, 0xe0, 0x41, 0x1f, 0x0f, 0x75, 0x5e,
+  0x7c, 0x72, 0xc6, 0xb5, 0x32, 0xee, 0x6c, 0x5e, 0xf6, 0x55, 0xa7, 0x11,
+  0xe0, 0x6e, 0x04, 0x5e, 0x5d, 0xb1, 0xf8, 0x20, 0x96, 0x68, 0x29, 0x87,
+  0xcc, 0x02, 0x9b, 0xd2, 0xb7, 0x9e, 0x56, 0xae, 0x81, 0xbf, 0xb1, 0x3d,
+  0xc9, 0x39, 0x83, 0x6d, 0xdd, 0x0e, 0x43, 0xd0, 0x28, 0x58, 0x02, 0x03,
+  0x48, 0x40, 0xd2, 0xf1, 0xd8, 0x8e, 0x3d, 0xd4, 0xe3, 0xe1, 0xc1, 0x72,
+  0xd8, 0xa8, 0x41, 0x2e, 0x8d, 0x37, 0xf9, 0x6f, 0x7d, 0x63, 0x25, 0x5b,
+  0x73, 0x32, 0x52, 0xad, 0xf0, 0x71, 0xf0, 0x63, 0x82, 0xf6, 0xf3, 0x19,
+  0x12, 0xd8, 0x11, 0x8b, 0x59, 0x5d, 0xaa, 0x3d, 0x67, 0x9c, 0xe7, 0xd8,
+  0x62, 0xcf, 0x16, 0x5a, 0xa1, 0x6c, 0xdd, 0xff, 0xb4, 0xa8, 0x3d, 0x2a,
+  0x33, 0x09, 0xd9, 0x33, 0xd8, 0x3b, 0x12, 0x04, 0x96, 0x98, 0xfc, 0x54,
+  0xce, 0x27, 0xac, 0xc5, 0x59, 0xe6, 0x98, 0xfc, 0x8d, 0x5e, 0x5b, 0x7f,
+  0xfb, 0x85, 0x43, 0x85, 0xa9, 0x5e, 0x81, 0x50, 0xb0, 0xbd, 0x1d, 0xa7,
+  0x1d, 0x77, 0xea, 0xcb, 0xbe, 0x9c, 0x4a, 0x85, 0x41, 0xfb, 0x0a, 0xad,
+  0xfe, 0x2f, 0x27, 0x2f, 0xb0, 0xac, 0xc8, 0x83, 0x13, 0x7b, 0x3d, 0x47,
+  0x1c, 0x68, 0xaa, 0xae, 0x59, 0xee, 0x61, 0xbb, 0xc0, 0xb0, 0x31, 0x89,
+  0x69, 0x84, 0x9a, 0x3e, 0x4e, 0x3f, 0x2e, 0xd5, 0x5a, 0x59, 0x20, 0x80,
+  0xaa, 0x61, 0x64, 0x6c, 0x3d, 0x93, 0xe2, 0x0a, 0x8d, 0x02, 0xea, 0x2d,
+  0xd5, 0x00, 0xb6, 0x61, 0xca, 0x0e, 0x03, 0x10, 0xaa, 0x65, 0xda, 0xc0,
+  0x56, 0x96, 0xf5, 0xbd, 0x89, 0xff, 0xdf, 0x31, 0x57, 0xdf, 0x44, 0x53,
+  0x90, 0x19, 0x06, 0x01, 0x11, 0x4c, 0x60, 0x41, 0x1d, 0x03, 0x2f, 0x31,
+  0xbf, 0x7c, 0x3e, 0x99, 0x76, 0xb4, 0x57, 0x92, 0xde, 0x87, 0x85, 0xa3,
+  0x6d, 0xd5, 0x12, 0x95, 0x03, 0x8c, 0x0c, 0x42, 0x08, 0x92, 0x0c, 0x1f,
+  0x08, 0x41, 0xf8, 0xe2, 0x37, 0xaa, 0xff, 0xe5, 0x43, 0x8c, 0x97, 0x16,
+  0xfd, 0x85, 0xb1, 0x62, 0xb5, 0x0a, 0x3a, 0x36, 0x02, 0xb8, 0x60, 0x89,
+  0x70, 0x1c, 0x12, 0x13, 0x2a, 0x91, 0x50, 0xf3, 0xcd, 0x34, 0xde, 0x42,
+  0xd9, 0x73, 0xb6, 0xdb, 0x3a, 0xba, 0x90, 0x60, 0x9c, 0x82, 0xda, 0x72,
+  0x36, 0x18, 0x15, 0x88, 0x69, 0xc4, 0x94, 0xfb, 0xe6, 0x39, 0x83, 0xe5,
+  0xe7, 0x36, 0x4e, 0xff, 0x3a, 0xbf, 0x6e, 0xe7, 0xca, 0x8e, 0x23, 0xe2,
+  0xe5, 0x4a, 0xb9, 0x41, 0x4d, 0x99, 0x2c, 0x0e, 0xd8, 0x5d, 0x47, 0x4d,
+  0xb9, 0x30, 0x6a, 0x0a, 0x46, 0xea, 0x66, 0xd9, 0x03, 0xdf, 0xd6, 0x2f,
+  0xa4, 0x2d, 0x1e, 0x7b, 0x93, 0xdf, 0x9e, 0x42, 0xc2, 0x82, 0xc1, 0xc3,
+  0x61, 0xb0, 0x31, 0x08, 0xff, 0xc0, 0xd5, 0x80, 0x35, 0x47, 0x42, 0x4f,
+  0x99, 0x80, 0xe1, 0xf3, 0x00, 0x67, 0xdb, 0x6e, 0xa9, 0xbe, 0x9d, 0x96,
+  0x6e, 0x29, 0xc4, 0x63, 0x72, 0xd0, 0xef, 0x01, 0x85, 0x65, 0xe0, 0x05,
+  0xe1, 0x6b, 0x62, 0x90, 0x37, 0x8d, 0x0e, 0xbe, 0xa3, 0x0b, 0x7f, 0x9e,
+  0xe7, 0xad, 0x35, 0x79, 0xca, 0x0c, 0x34, 0x1d, 0x7b, 0xec, 0x88, 0x93,
+  0x27, 0xd6, 0x5f, 0x88, 0xa7, 0x91, 0x40, 0x71, 0x83, 0xa0, 0xf0, 0x3f,
+  0xe2, 0xb3, 0xea, 0x0e, 0x49, 0x01, 0x8a, 0xa4, 0x91, 0xa4, 0xcd, 0xf3,
+  0x6a, 0xd6, 0x4b, 0x7e, 0xce, 0x67, 0xb7, 0x73, 0x57, 0x05, 0x77, 0xc2,
+  0xc0, 0x90, 0x5d, 0x81, 0xfa, 0x46, 0x07, 0xea, 0x24, 0x1c, 0xfa, 0x55,
+  0x19, 0xaa, 0x56, 0xb2, 0x55, 0xea, 0x8f, 0x00, 0x93, 0xbf, 0xb1, 0x03,
+  0xb0, 0xb5, 0xb1, 0xa8, 0x96, 0x23, 0xb2, 0x20, 0x36, 0x25, 0x45, 0x59,
+  0x7b, 0xbb, 0xd6, 0x4b, 0x6c, 0x97, 0x0b, 0x6e, 0xcf, 0x59, 0x99, 0xe0,
+  0x7c, 0xbf, 0xfe, 0xc6, 0xfe, 0x53, 0x36, 0xed, 0x63, 0xbe, 0x2b, 0xc5,
+  0x02, 0x24, 0xec, 0x0e, 0xe5, 0x1b, 0x82, 0xb8, 0xc1, 0x8d, 0xf7, 0xbe,
+  0x5e, 0xcc, 0xf8, 0x79, 0xc5, 0x7a, 0xa3, 0xcb, 0xdb, 0xfb, 0x6d, 0xa5,
+  0xb3, 0x88, 0xd0, 0x69, 0x58, 0x74, 0x16, 0x8a, 0x63, 0x1d, 0xdf, 0xb4,
+  0xcd, 0xbf, 0x51, 0x81, 0xfb, 0x1b, 0xad, 0xc2, 0xd9, 0xd5, 0x84, 0x4c,
+  0x51, 0x88, 0xc1, 0x85, 0x65, 0xe6, 0x76, 0x38, 0xc2, 0x66, 0xde, 0xf8,
+  0xb7, 0x7d, 0xad, 0x29, 0x92, 0xd5, 0xd1, 0xe5, 0x59, 0x1f, 0xfb, 0xa0,
+  0xf9, 0x5f, 0xfd, 0x89, 0x12, 0x09, 0x50, 0xbf, 0x2f, 0x19, 0x6b, 0x97,
+  0xf3, 0x0b, 0x57, 0xe8, 0x83, 0x22, 0xd2, 0x4c, 0x2b, 0x02, 0x78, 0x2c,
+  0x14, 0x0f, 0x00, 0xe6, 0xb6, 0x5c, 0xd2, 0x86, 0x2f, 0xdb, 0xd5, 0xbc,
+  0x57, 0xdb, 0xab, 0xce, 0xb7, 0x7e, 0x1c, 0x62, 0xe5, 0x42, 0xb9, 0x56,
+  0x24, 0x30, 0x3c, 0x1d, 0xe0, 0x39, 0x2e, 0xda, 0xb0, 0x38, 0x14, 0xd3,
+  0xb1, 0xad, 0x88, 0xe7, 0xe0, 0x7a, 0x39, 0x6d, 0x48, 0x75, 0x80, 0xf9,
+  0x70, 0x03, 0xad, 0x92, 0x10, 0x10, 0x16, 0x36, 0xa8, 0x96, 0x21, 0x54,
+  0x9a, 0xd6, 0x25, 0xb0, 0x3f, 0xdf, 0xcf, 0x75, 0x4f, 0x6e, 0xc9, 0xd8,
+  0x8e, 0x61, 0x52, 0x01, 0xb8, 0x31, 0x17, 0x03, 0x40, 0xdc, 0xdd, 0xf3,
+  0x25, 0x8c, 0xb0, 0x04, 0x3c, 0x1e, 0xe3, 0x17, 0xeb, 0xf7, 0xfe, 0xc1,
+  0xba, 0x85, 0xb0, 0x3b, 0x06, 0x23, 0x18, 0x00, 0x6c, 0xdf, 0xa5, 0xf6,
+  0xe3, 0x3e, 0x98, 0xce, 0xf8, 0x3c, 0xd9, 0xca, 0x9b, 0x22, 0x30, 0x36,
+  0xc9, 0x5e, 0x62, 0x3b, 0xaa, 0x30, 0x18, 0xe8, 0xc9, 0xb2, 0xfb, 0x9f,
+  0x57, 0x55, 0x02, 0xb3, 0xde, 0x51, 0xe6, 0x04, 0x0e, 0x6f, 0x7f, 0xe5,
+  0x83, 0xc6, 0x73, 0x17, 0xcd, 0xca, 0x37, 0xd0, 0xf4, 0x04, 0xda, 0x58,
+  0x68, 0x2c, 0xb4, 0xa9, 0xed, 0xb0, 0x84, 0x90, 0x7d, 0xa1, 0x05, 0xac,
+  0xdc, 0xbf, 0x4d, 0xe5, 0xff, 0x7f, 0xb2, 0x77, 0x64, 0xcb, 0xce, 0x68,
+  0x2d, 0xc2, 0xd3, 0x45, 0xec, 0x5e, 0x28, 0xcb, 0x68, 0xba, 0xf2, 0x13,
+  0xd7, 0xd3, 0x81, 0xa6, 0xcb, 0x92, 0xe3, 0x54, 0xb5, 0x6d, 0x56, 0x5b,
+  0xe2, 0xcd, 0xdd, 0x43, 0x3a, 0x0e, 0x2b, 0x0f, 0x11, 0x19, 0x0c, 0x00,
+  0x1c, 0x07, 0x47, 0x82, 0x5a, 0xbd, 0x4d, 0xf1, 0xc9, 0x70, 0x78, 0xa6,
+  0x6a, 0xdc, 0xdc, 0x88, 0xe4, 0x50, 0x09, 0x0b, 0x85, 0x93, 0xdc, 0x42,
+  0x66, 0x61, 0x94, 0xc7, 0xa9, 0x12, 0x83, 0x16, 0xab, 0xb9, 0xec, 0x6f,
+  0x8c, 0x36, 0xa2, 0xc1, 0x12, 0xd8, 0x8d, 0xe2, 0x42, 0xf2, 0xf6, 0xcb,
+  0x9a, 0xf3, 0x09, 0x98, 0xd6, 0x4b, 0xdb, 0xe0, 0xe1, 0x86, 0xb9, 0xd9,
+  0x3a, 0xbf, 0xff, 0x74, 0xa9, 0xac, 0x30, 0x2f, 0xa0, 0xdf, 0x1f, 0x24,
+  0xe8, 0xf0, 0x0f, 0x26, 0x1c, 0xab, 0xdb, 0x14, 0x56, 0xc3, 0xc9, 0xfd,
+  0xad, 0xf3, 0xfc, 0x2a, 0x52, 0xa7, 0x17, 0xd5, 0x20, 0xc4, 0x49, 0x97,
+  0x76, 0x26, 0x0f, 0xdb, 0x53, 0x1b, 0x66, 0x52, 0xd5, 0xca, 0xc5, 0x07,
+  0x5c, 0xa0, 0x97, 0x13, 0x16, 0xdc, 0xba, 0xcf, 0xb7, 0xfc, 0xdd, 0x51,
+  0x04, 0x55, 0x25, 0x96, 0xc0, 0xf6, 0x74, 0x1c, 0x64, 0xd0, 0x30, 0xd9,
+  0x5e, 0x7c, 0x08, 0xe4, 0x83, 0x0a, 0xbc, 0x07, 0x38, 0x31, 0x32, 0xae,
+  0x88, 0x49, 0xcb, 0x35, 0x40, 0x7c, 0x3d, 0xe4, 0x2e, 0x8a, 0x40, 0xc8,
+  0x29, 0xcb, 0x57, 0xec, 0xd5, 0x0a, 0x71, 0x9e, 0xc2, 0xb2, 0xd0, 0xf3,
+  0x85, 0x80, 0x96, 0x17, 0x23, 0x7a, 0xc9, 0x73, 0x4d, 0xc2, 0xbd, 0x63,
+  0x8a, 0x78, 0x6b, 0x88, 0xc2, 0x85, 0x1b, 0x10, 0xab, 0x63, 0xc0, 0x66,
+  0xd3, 0x27, 0x61, 0x8a, 0x94, 0x78, 0x3d, 0x6c, 0xb9, 0x8f, 0xf2, 0xa5,
+  0xcf, 0x75, 0x7d, 0x47, 0x3e, 0x0c, 0x13, 0x0e, 0xc0, 0x30, 0x21, 0x8e,
+  0xf0, 0x78, 0xd8, 0x90, 0x5f, 0x76, 0x96, 0xec, 0xdf, 0x2b, 0x6d, 0x76,
+  0xdb, 0x62, 0xaf, 0xca, 0x68, 0x80, 0x88, 0x20, 0xfd, 0x27, 0xc0, 0x30,
+  0x7a, 0x0a, 0x7b, 0x63, 0x02, 0x00, 0x7b, 0xc9, 0xdd, 0x47, 0x37, 0x92,
+  0x07, 0x2a, 0x40, 0x40, 0x63, 0x6c, 0x76, 0xde, 0xea, 0x49, 0x0b, 0x73,
+  0x9f, 0x55, 0x89, 0x23, 0x19, 0x36, 0x46, 0x27, 0xb3, 0xd3, 0xbf, 0x11,
+  0x74, 0x88, 0x96, 0x35, 0x64, 0x40, 0x90, 0xae, 0x4c, 0x80, 0xf8, 0x21,
+  0xf0, 0x03, 0xd5, 0x09, 0x13, 0x92, 0x6a, 0xaf, 0xb7, 0xff, 0xad, 0x6e,
+  0xd4, 0x73, 0xd0, 0x36, 0x51, 0xc2, 0xd0, 0xb4, 0x29, 0x35, 0x85, 0xa5,
+  0x5a, 0x36, 0x47, 0xa1, 0x21, 0x30, 0x0e, 0x1e, 0x0f, 0x63, 0x29, 0x44,
+  0xb9, 0xf5, 0x78, 0x97, 0xdf, 0x1c, 0x71, 0xbd, 0x9a, 0xdb, 0x32, 0x45,
+  0x3f, 0xed, 0xd2, 0xcc, 0xcc, 0x52, 0x2c, 0x5d, 0x21, 0x7a, 0x9f, 0x24,
+  0xc1, 0xb7, 0xd3, 0xb5, 0x3f, 0xbd, 0x46, 0xb7, 0x25, 0x96, 0x06, 0xb4,
+  0x12, 0x5d, 0xb2, 0xb3, 0xb5, 0xb1, 0x69, 0x67, 0x96, 0x53, 0x27, 0x77,
+  0xa0, 0x8d, 0xc2, 0x22, 0x6a, 0x32, 0x25, 0xcf, 0x4e, 0x4e, 0x0f, 0xcb,
+  0x0d, 0xe4, 0xc9, 0x29, 0x60, 0x30, 0x9d, 0x54, 0x56, 0xc2, 0xa5, 0x32,
+  0x49, 0xce, 0xf6, 0xce, 0xa2, 0xe8, 0x2d, 0x3e, 0xf8, 0x70, 0x3f, 0xcf,
+  0x2f, 0x41, 0xc5, 0xfe, 0x57, 0x56, 0x40, 0x38, 0xbe, 0xa0, 0xfa, 0xdf,
+  0xfe, 0x8e, 0x7d, 0xf0, 0x02, 0xec, 0xd2, 0xbf, 0x46, 0x58, 0x1d, 0x81,
+  0x91, 0xc5, 0x6c, 0x7b, 0xe6, 0x09, 0x26, 0xb1, 0x3d, 0x7d, 0x65, 0x0d,
+  0x4b, 0x31, 0x40, 0xac, 0xbb, 0x7f, 0xe0, 0xed, 0xa4, 0x96, 0x03, 0x15,
+  0x32, 0x5d, 0x4a, 0xea, 0x2a, 0xaf, 0xd6, 0xe7, 0xc2, 0x98, 0x67, 0xd8,
+  0x0d, 0xcd, 0x4a, 0xbc, 0x98, 0x3f, 0x65, 0x3b, 0x38, 0xa1, 0x6d, 0xf0,
+  0x7e, 0x59, 0x7d, 0x43, 0x75, 0xbc, 0x05, 0x01, 0x28, 0xc8, 0x93, 0x41,
+  0x97, 0x10, 0x93, 0xe5, 0x9f, 0x06, 0x5f, 0xec, 0x55, 0x08, 0xda, 0xf3,
+  0x2d, 0x76, 0x5b, 0x04, 0x45, 0x07, 0xb5, 0x2f, 0xb4, 0x0c, 0x8b, 0x5a,
+  0xe7, 0x0b, 0x31, 0x45, 0x81, 0x92, 0xe2, 0x61, 0x9b, 0x17, 0x66, 0xa7,
+  0xdc, 0x47, 0x7e, 0x59, 0x72, 0x2d, 0x2e, 0xf6, 0x55, 0xe8, 0x72, 0x46,
+  0x8c, 0x6f, 0x2d, 0x67, 0x7d, 0xf1, 0xcc, 0xdc, 0x50, 0xb1, 0x5e, 0x77,
+  0xdc, 0x94, 0x18, 0x4e, 0x92, 0xa0, 0x61, 0xba, 0x71, 0x11, 0x4e, 0xc2,
+  0xaa, 0x6d, 0x0b, 0xf3, 0x1f, 0x62, 0xff, 0x77, 0xbf, 0x5d, 0x7e, 0x8b,
+  0x8d, 0x74, 0x16, 0xb7, 0xa8, 0x9f, 0xd7, 0xcf, 0xde, 0x5a, 0xa7, 0xaa,
+  0x51, 0xf2, 0x72, 0xce, 0x9e, 0xbd, 0xdf, 0x7f, 0x23, 0x70, 0xa8, 0xae,
+  0x4d, 0xf0, 0x8b, 0x9b, 0x50, 0x3f, 0x97, 0x95, 0x64, 0x51, 0x2a, 0x25,
+  0x3d, 0x50, 0x6a, 0x48, 0x43, 0x73, 0x56, 0xec, 0x0d, 0x0a, 0x60, 0xaf,
+  0xd2, 0xb6, 0x25, 0xcf, 0x96, 0x69, 0x5e, 0x45, 0xbb, 0x22, 0xfc, 0x22,
+  0x94, 0xc3, 0x65, 0x17, 0x9d, 0xbd, 0x84, 0x8a, 0x79, 0x29, 0xfe, 0xb6,
+  0x18, 0x81, 0x46, 0x0d, 0x5a, 0x04, 0x26, 0x20, 0xe5, 0xaa, 0xde, 0xa5,
+  0x6d, 0x98, 0xd7, 0xa7, 0x20, 0x32, 0x2f, 0x45, 0xe8, 0x6c, 0xa7, 0x98,
+  0x0c, 0x27, 0x0e, 0x00, 0xc1, 0x08, 0x4b, 0x56, 0x3f, 0x00, 0xf1, 0x27,
+  0xea, 0xdb, 0xbb, 0xa9, 0xda, 0x03, 0x7b, 0x28, 0xdb, 0xb1, 0x5e, 0x45,
+  0x83, 0x85, 0x05, 0xa1, 0x60, 0x30, 0x81, 0x82, 0x19, 0x78, 0x22, 0x84,
+  0x36, 0x58, 0xff, 0x71, 0xb2, 0xe6, 0xea, 0xac, 0xca, 0xb4, 0x2c, 0x5a,
+  0xdd, 0x80, 0xaf, 0xda, 0xa4, 0x4c, 0x4c, 0x46, 0x05, 0x18, 0x1c, 0x05,
+  0x00, 0xf9, 0x52, 0xa1, 0xe3, 0x1f, 0x4e, 0x3f, 0x6e, 0xfb, 0x44, 0xb4,
+  0xab, 0x7b, 0xdc, 0x02, 0xbe, 0xf5, 0xd2, 0xb6, 0xd4, 0x40, 0xeb, 0x0b,
+  0x33, 0xc0, 0xc2, 0xbe, 0xde, 0xd9, 0x10, 0x18, 0x69, 0x48, 0x9b, 0x08,
+  0x62, 0x48, 0x07, 0x97, 0x01, 0xc6, 0x23, 0x23, 0xff, 0xdc, 0xcb, 0xfc,
+  0xf6, 0x49, 0x8a, 0x77, 0x76, 0xf6, 0xc2, 0xc8, 0x22, 0xe2, 0x89, 0x4b,
+  0x41, 0xc6, 0x21, 0x30, 0x92, 0x98, 0x49, 0xc0, 0xfc, 0xb9, 0x96, 0x95,
+  0xb5, 0xdb, 0x14, 0xfa, 0xf7, 0x9a, 0xb5, 0xe5, 0x0d, 0xd7, 0x70, 0x39,
+  0x00, 0x3c, 0x43, 0x6c, 0x20, 0x89, 0x7f, 0x2f, 0x6e, 0xd9, 0xe5, 0x20,
+  0x61, 0xa4, 0x73, 0xd8, 0x88, 0x11, 0xd6, 0x52, 0x2d, 0x09, 0xc0, 0xc0,
+  0x18, 0x3d, 0x68, 0x0d, 0x25, 0x1d, 0x03, 0x21, 0x8c, 0xd5, 0x78, 0x81,
+  0x4f, 0xac, 0x92, 0xac, 0x1b, 0x16, 0x03, 0x05, 0x77, 0x2f, 0x6b, 0xdf,
+  0x0c, 0xa6, 0x16, 0x32, 0xf3, 0xbb, 0x51, 0x40, 0xa4, 0xc9, 0x72, 0xad,
+  0xd0, 0x51, 0xe0, 0x96, 0xa7, 0x26, 0x03, 0x0e, 0x28, 0xfa, 0xe7, 0x17,
+  0x52, 0x1f, 0xc6, 0x6f, 0xe0, 0x2d, 0x85, 0xc2, 0x38, 0x1f, 0x83, 0xa0,
+  0x0d, 0x49, 0xa9, 0xcb, 0xc0, 0xd0, 0xf1, 0x81, 0xf7, 0xf5, 0xbf, 0x2f,
+  0xba, 0xaf, 0x59, 0xfd, 0xe4, 0xf7, 0xb0, 0x6f, 0xb9, 0xbe, 0x1b, 0xe8,
+  0x2b, 0x8b, 0x41, 0x8e, 0x8b, 0x13, 0x82, 0x95, 0x30, 0x8c, 0x91, 0x50,
+  0x87, 0xaa, 0x77, 0xcd, 0xea, 0x65, 0x0a, 0x16, 0xda, 0x20, 0xce, 0xdb,
+  0xc0, 0xdb, 0x3b, 0xaa, 0x01, 0x6c, 0x9a, 0x44, 0xa9, 0xa0, 0xc9, 0x53,
+  0x14, 0xdf, 0xc1, 0x81, 0x34, 0x42, 0x9e, 0xe0, 0x32, 0x8b, 0x28, 0x8a,
+  0x19, 0xcb, 0xd0, 0xc1, 0xe6, 0x9a, 0x1f, 0xf8, 0x49, 0x4c, 0x98, 0xbd,
+  0x37, 0xe7, 0xd8, 0x67, 0x25, 0x86, 0xe2, 0xc8, 0xac, 0x0e, 0x44, 0x41,
+  0x68, 0x61, 0x05, 0x08, 0x29, 0x4b, 0x84, 0xa6, 0x2f, 0xb7, 0xfd, 0xd8,
+  0xa4, 0xa9, 0x15, 0x52, 0xba, 0xd2, 0x08, 0xa1, 0xc0, 0x5b, 0x7d, 0x9d,
+  0x33, 0x53, 0x0f, 0x20, 0x1a, 0x59, 0x8d, 0x81, 0xc9, 0x6c, 0xac, 0x41,
+  0xdd, 0x2d, 0x88, 0xb3, 0x3f, 0x7d, 0x79, 0xfb, 0x43, 0xd1, 0x16, 0x82,
+  0x41, 0x4f, 0x88, 0xe5, 0xc1, 0xff, 0x8b, 0xaa, 0x76, 0xb5, 0x5e, 0xe0,
+  0x74, 0x39, 0xf5, 0xfd, 0xd4, 0x2b, 0x66, 0x8a, 0x8f, 0x17, 0x01, 0xb0,
+  0x0f, 0x4c, 0x0d, 0xd2, 0xf2, 0xa2, 0xe2, 0xda, 0x58, 0xaa, 0xf0, 0xae,
+  0xf2, 0xae, 0x1b, 0x28, 0xe8, 0x24, 0x86, 0xf1, 0xd3, 0x40, 0xc0, 0x88,
+  0xac, 0x3a, 0x49, 0xff, 0x27, 0x6c, 0x18, 0x6f, 0xbe, 0x07, 0x25, 0x10,
+  0x7f, 0x41, 0x83, 0x90, 0xf7, 0x54, 0x28, 0xe8, 0x08, 0x2b, 0x5a, 0xe8,
+  0x6e, 0xa0, 0x58, 0xad, 0x85, 0x4c, 0x2c, 0xeb, 0x7b, 0xc0, 0x64, 0x7c,
+  0xa8, 0x79, 0xc9, 0x16, 0x38, 0x0c, 0xe5, 0x6a, 0x87, 0x40, 0xab, 0x10,
+  0xf9, 0xef, 0x6b, 0x3e, 0x2f, 0x4f, 0xad, 0x29, 0xb4, 0x71, 0x9c, 0xfd,
+  0xec, 0xf8, 0x38, 0xc0, 0x51, 0x45, 0xda, 0x8c, 0x3c, 0x18, 0xde, 0xca,
+  0xec, 0x01, 0xe2, 0x47, 0xea, 0x7d, 0xdf, 0xa9, 0xb2, 0xb6, 0xcd, 0xd9,
+  0xe5, 0xe8, 0x83, 0xf5, 0xa7, 0xc3, 0x40, 0x4a, 0xd5, 0x77, 0x9f, 0x58,
+  0x2d, 0xf4, 0xc3, 0x67, 0x7c, 0xdb, 0x4a, 0xdb, 0x9d, 0xcf, 0x7b, 0x2c,
+  0x03, 0x33, 0xd3, 0x96, 0xd0, 0x28, 0x58, 0xa7, 0x4a, 0xb0, 0x44, 0x52,
+  0x5a, 0x58, 0x59, 0xa0, 0xc4, 0x50, 0x10, 0x07, 0x4a, 0x82, 0x00, 0x95,
+  0x14, 0xfe, 0x29, 0x4f, 0xb8, 0xad, 0x46, 0x7e, 0x37, 0xe5, 0xfd, 0x27,
+  0x3d, 0x60, 0xdf, 0x30, 0x39, 0x06, 0x21, 0x16, 0x81, 0xe6, 0x47, 0x80,
+  0xdd, 0xd2, 0xe5, 0x79, 0x38, 0x38, 0xac, 0x51, 0xcf, 0x5b, 0x53, 0xf9,
+  0x11, 0x79, 0x9d, 0x2c, 0x1c, 0x66, 0xf2, 0x83, 0x10, 0x07, 0xf0, 0x86,
+  0x25, 0xab, 0xd6, 0x9b, 0x63, 0x14, 0xa6, 0x2e, 0x8d, 0xcf, 0x34, 0xa8,
+  0x0a, 0xef, 0xb9, 0x65, 0x9d, 0xc2, 0xac, 0xc5, 0x83, 0xdc, 0x02, 0x26,
+  0x4b, 0xff, 0x36, 0x23, 0x04, 0x83, 0x7a, 0x46
+};
+
+void
+mpeg4_get_video_info (VideoDecodeInfo * info)
+{
+  info->profile = GST_VAAPI_PROFILE_MPEG4_SIMPLE;
+  info->width = MPEG4_CLIP_WIDTH;
+  info->height = MPEG4_CLIP_HEIGHT;
+  info->data = mpeg4_clip;
+  info->data_size = MPEG4_CLIP_DATA_SIZE;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-mpeg4.h b/subprojects/gstreamer-vaapi/tests/internal/test-mpeg4.h
new file mode 100644 (file)
index 0000000..aaa613d
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  test-mpeg4.h - MPEG-4 test data
+ *
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_MPEG4_H
+#define TEST_MPEG4_H
+
+#include <glib.h>
+#include "test-decode.h"
+
+void mpeg4_get_video_info(VideoDecodeInfo *info);
+
+#endif /* TEST_MPEG4_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-subpicture-data.c b/subprojects/gstreamer-vaapi/tests/internal/test-subpicture-data.c
new file mode 100644 (file)
index 0000000..0bd2133
--- /dev/null
@@ -0,0 +1,1431 @@
+/*
+ *  test-subpicture-data.c - subpicture data
+ *
+ *  Copyright (C) <2011> Intel Corporation
+ *  Copyright (C) <2011> Collabora Ltd.
+ *  Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include "test-subpicture-data.h"
+
+#define SUBPICTURE_WIDTH           184
+#define SUBPICTURE_HEIGHT          38
+#define SUBPICTURE_DATA_SIZE     27968
+
+/* Raw RGBA data */
+static const guint32 text[] = {
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x09000000, 0x63000000, 0x08000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x44000000, 0x88000000, 0x88000000, 0x88000000, 0x88000000,
+  0x88000000, 0x88000000, 0x88000000, 0x88000000, 0x88000000,
+  0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x44000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x44000000, 0x88000000,
+  0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x69000000, 0xff0000b4, 0x65000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0x80000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0x80000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x6a000000,
+  0xff0000b6, 0x9c000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x3c000000, 0xbb000000,
+  0xff0000ff, 0xdd000000, 0xbb000000, 0xbb000000, 0xbb000000,
+  0xbb000000, 0xdd000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x08000000, 0x61000000,
+  0x60000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x1f000000, 0x5c000000, 0x78000000, 0x60000000,
+  0x27000000, 0x00000000, 0x00000000, 0x44000000, 0xc4000000,
+  0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, 0x88000000,
+  0x0f000000, 0x00000000, 0x00000000, 0x42000000, 0x78000000,
+  0x78000000, 0x41000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x1f000000, 0x5c000000, 0x78000000,
+  0x60000000, 0x27000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x1f000000, 0x5c000000, 0x78000000, 0x60000000,
+  0x27000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x42000000, 0x78000000, 0x78000000, 0x41000000,
+  0x00000000, 0x00000000, 0x00000000, 0x44000000, 0x88000000,
+  0x88000000, 0x45000000, 0x3d000000, 0x73000000, 0x6c000000,
+  0x37000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000,
+  0xc4000000, 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000,
+  0x88000000, 0x53000000, 0x88000000, 0x88000000, 0x44000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x41000000,
+  0x78000000, 0x78000000, 0x46000000, 0x01000000, 0x00000000,
+  0x00000000, 0x44000000, 0x88000000, 0x88000000, 0x49000000,
+  0x55000000, 0x78000000, 0x4a000000, 0x02000000, 0x02000000,
+  0x4f000000, 0x78000000, 0x4d000000, 0x01000000, 0x00000000,
+  0x00000000, 0x44000000, 0x88000000, 0x88000000, 0x45000000,
+  0x3e000000, 0x77000000, 0x78000000, 0x43000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x42000000, 0x78000000, 0x78000000, 0x41000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x1f000000,
+  0x5c000000, 0x78000000, 0x60000000, 0x27000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x80000000,
+  0x77000000, 0x9e000000, 0x00000000, 0x00000000, 0x9000000a,
+  0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0,
+  0xc8000036, 0x35000000, 0x80000000, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff00009c, 0x1c000000,
+  0x10000000, 0xc900001f, 0xff0000ad, 0xff0000e7, 0xff0000e7,
+  0xff0000ad, 0xc900001f, 0x13000000, 0x00000000, 0x00000000,
+  0x9000000a, 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc,
+  0xf50000a0, 0xc8000036, 0x35000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x9000000a,
+  0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0,
+  0xc8000036, 0x35000000, 0x00000000, 0x10000000, 0xc900001f,
+  0xff0000ad, 0xff0000e7, 0xff0000e7, 0xff0000ad, 0xc900001f,
+  0x13000000, 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff,
+  0xee000011, 0xff0000a3, 0xff0000e5, 0xff0000ca, 0xfc000072,
+  0x94000010, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff00009c,
+  0x9b000000, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000,
+  0x00000000, 0x10000000, 0xc900001f, 0xff0000ad, 0xfe0000e7,
+  0xff0000e7, 0xff0000af, 0xc600001f, 0x11000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xff0000ff, 0xf700001f, 0xff0000b6,
+  0xff0000eb, 0xf80000ac, 0xbb00001a, 0xc8000022, 0xff0000b3,
+  0xff0000e6, 0xf900008a, 0xad000017, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xff0000ff, 0xf300001b, 0xff0000ad,
+  0xfe0000e3, 0xff0000e9, 0xff0000ad, 0xc100001d, 0x0f000000,
+  0x00000000, 0x00000000, 0x10000000, 0xc900001f, 0xff0000ad,
+  0xff0000e7, 0xff0000e7, 0xff0000ad, 0xc900001f, 0x13000000,
+  0x00000000, 0x00000000, 0x9000000a, 0xfd000076, 0xff0000b6,
+  0xff0000ef, 0xfe0000dc, 0xf50000a0, 0xc8000036, 0x35000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xe2000000, 0x88000000,
+  0x88000000, 0xc4000000, 0xff0000ff, 0x80000000, 0x00000000,
+  0x00000000, 0x00000000, 0x43000000, 0xff000078, 0xf8000096,
+  0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff,
+  0x8d000000, 0x3c000000, 0xbb000000, 0xff0000ff, 0xdd000000,
+  0xbb000000, 0xbb000000, 0xbb000000, 0x57000000, 0xbc00001a,
+  0xff0000e4, 0xf5000098, 0xc8000033, 0xd1000033, 0xf900009a,
+  0xff0000e4, 0xbe00001a, 0x00000000, 0x43000000, 0xff000078,
+  0xf8000096, 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf,
+  0xff0000ff, 0x8d000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x43000000, 0xff000078, 0xf8000096,
+  0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff,
+  0x8d000000, 0x00000000, 0xbc00001a, 0xff0000e4, 0xf5000098,
+  0xc8000033, 0xd1000033, 0xf900009a, 0xff0000e4, 0xbe00001a,
+  0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, 0xff0000b1,
+  0xea000077, 0xbd00001d, 0xda000042, 0xfd0000bc, 0xfa000074,
+  0x36000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff,
+  0xdd000000, 0xbb000000, 0xbb000000, 0xbb000000, 0x81000000,
+  0xbb000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0xb700001a, 0xff0000e6, 0xf500008e, 0xc9000031, 0xd000002c,
+  0xf8000087, 0xff0000dd, 0xb1000014, 0x00000000, 0x3c000000,
+  0xbb000000, 0xff0000ff, 0xff0000a9, 0xd4000054, 0xc5000024,
+  0xfc0000a8, 0xfa0000b4, 0xff0000a7, 0xd5000054, 0xc4000024,
+  0xfc0000aa, 0xfc000088, 0x3e000000, 0x00000000, 0x3c000000,
+  0xbb000000, 0xff0000ff, 0xff0000cf, 0xf2000087, 0xc600002d,
+  0xd1000033, 0xf900009a, 0xff0000e1, 0xb6000017, 0x00000000,
+  0x00000000, 0xbc00001a, 0xff0000e4, 0xf5000098, 0xc8000033,
+  0xd1000033, 0xf900009a, 0xff0000e4, 0xbe00001a, 0x00000000,
+  0x43000000, 0xff000078, 0xf8000096, 0xbe00002c, 0xb9000011,
+  0xe5000051, 0xfa0000cf, 0xff0000ff, 0x8d000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000,
+  0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x2e000000, 0xff00009c, 0xf8000092,
+  0x7e000000, 0x4c000000, 0x1a000000, 0x30000000, 0xfa000096,
+  0xff00009b, 0x37000000, 0x75000000, 0xfe0000e4, 0xc5000025,
+  0x4c000000, 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000,
+  0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000,
+  0x2e000000, 0xff00009c, 0xf8000092, 0x7e000000, 0x4c000000,
+  0x1a000000, 0x30000000, 0xfa000096, 0xff00009b, 0x37000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xf5000078, 0x5e000000,
+  0x3c000000, 0x0f000000, 0xcd00004b, 0xfe0000c1, 0x89000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x2e000000, 0xff00009b,
+  0xf900009e, 0x82000000, 0x47000000, 0x19000000, 0x25000000,
+  0xf700008e, 0xfe000086, 0x25000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xee000060, 0x56000000, 0x2a000000, 0xb9000036,
+  0xff0000ff, 0xe9000060, 0x55000000, 0x2a000000, 0xba000038,
+  0xff0000ca, 0x91000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xf7000084, 0x70000000, 0x44000000, 0x17000000,
+  0x30000000, 0xfb000096, 0xff000098, 0x32000000, 0x2e000000,
+  0xff00009c, 0xf8000092, 0x7e000000, 0x4c000000, 0x1a000000,
+  0x30000000, 0xfa000096, 0xff00009b, 0x37000000, 0x75000000,
+  0xfe0000e4, 0xc5000025, 0x4c000000, 0x16000000, 0x09000000,
+  0xcd000040, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xdd000000, 0xbb000000, 0xbb000000, 0xdd000000,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000,
+  0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005,
+  0x48000000, 0x44000000, 0x88000000, 0x9e000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x5d000000, 0xff0000da, 0xd0000049, 0x49000000,
+  0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9,
+  0x96000000, 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055,
+  0x82000005, 0x48000000, 0x44000000, 0x88000000, 0x9e000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005,
+  0x48000000, 0x44000000, 0x88000000, 0x9e000000, 0x5d000000,
+  0xff0000da, 0xd0000049, 0x49000000, 0x00000000, 0x00000000,
+  0x00000000, 0xbe00004b, 0xfe0000d9, 0x96000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xd1000028, 0x3c000000, 0x00000000,
+  0x00000000, 0x90000011, 0xff0000fc, 0xaf000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x5d000000, 0xff0000da, 0xeb000034,
+  0xad000000, 0x88000000, 0x88000000, 0x88000000, 0xde00002f,
+  0xff0000cb, 0x7b000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xcd000020, 0x30000000, 0x00000000, 0x84000005, 0xff0000ff,
+  0xcd000020, 0x30000000, 0x00000000, 0x85000006, 0xff0000fc,
+  0xb1000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xd300002c, 0x42000000, 0x00000000, 0x00000000, 0x00000000,
+  0xbe00004b, 0xfe0000d8, 0x95000000, 0x5d000000, 0xff0000da,
+  0xd0000049, 0x49000000, 0x00000000, 0x00000000, 0x00000000,
+  0xbe00004b, 0xfe0000d9, 0x96000000, 0x49000000, 0xf70000a8,
+  0xfb0000cb, 0xea000055, 0x82000005, 0x48000000, 0x44000000,
+  0x88000000, 0x9e000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x3c000000, 0x77000000,
+  0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2,
+  0xf200005c, 0x72000001, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000,
+  0x78000000, 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000,
+  0x00000000, 0x00000000, 0x92000013, 0xff0000f6, 0xb4000000,
+  0x00000000, 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2,
+  0xfb0000c2, 0xf200005c, 0x72000001, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2,
+  0xf200005c, 0x72000001, 0x00000000, 0x78000000, 0xff0000f6,
+  0xc0000012, 0x25000000, 0x00000000, 0x00000000, 0x00000000,
+  0x92000013, 0xff0000f6, 0xb4000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xc0000000, 0x14000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xbf000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x7a000000, 0xff0000f6, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ee,
+  0xa8000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x10000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x10000000, 0x00000000, 0x80000000, 0xff0000ff, 0xbf000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x16000000, 0x00000000, 0x00000000, 0x00000000, 0x92000013,
+  0xff0000f6, 0xb3000000, 0x78000000, 0xff0000f6, 0xc0000012,
+  0x25000000, 0x00000000, 0x00000000, 0x00000000, 0x92000013,
+  0xff0000f6, 0xb4000000, 0x00000000, 0x8f000007, 0xf900007e,
+  0xfc0000dd, 0xff0000f2, 0xfb0000c2, 0xf200005c, 0x72000001,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000,
+  0x88000000, 0x44000000, 0x00000000, 0x44000000, 0x88000000,
+  0x65000000, 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc,
+  0xfb000098, 0x40000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x5d000000,
+  0xff0000da, 0xdc00004a, 0x09000000, 0x00000000, 0x00000000,
+  0x00000000, 0xbe00004b, 0xfe0000d9, 0xb1000000, 0x44000000,
+  0x88000000, 0x65000000, 0x84000000, 0xc8000014, 0xf4000059,
+  0xfc0000cc, 0xfb000098, 0x40000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x44000000, 0x88000000,
+  0x65000000, 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc,
+  0xfb000098, 0x40000000, 0x5d000000, 0xff0000da, 0xdc00004a,
+  0x09000000, 0x00000000, 0x00000000, 0x00000000, 0xbe00004b,
+  0xfe0000d9, 0xb1000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x69000000, 0xff0000d9, 0xe8000028, 0xbb000000, 0xbb000000,
+  0xbb000000, 0xbb000000, 0xda000000, 0xff000000, 0xc1000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xd6000036, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d8,
+  0xb1000000, 0x5d000000, 0xff0000da, 0xdc00004a, 0x09000000,
+  0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9,
+  0xb1000000, 0x44000000, 0x88000000, 0x65000000, 0x84000000,
+  0xc8000014, 0xf4000059, 0xfc0000cc, 0xfb000098, 0x40000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0x80000000, 0x00000000, 0x80000000, 0xff0000ff, 0xba00003a,
+  0x00000000, 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2,
+  0x9d000000, 0x00000000, 0x7f000000, 0xff0000fd, 0xc0000002,
+  0x00000000, 0x43000000, 0x88000000, 0x71000000, 0xff00009b,
+  0xfb000095, 0x39000000, 0x00000000, 0x00000000, 0x18000000,
+  0xf9000096, 0xff00009b, 0x85000000, 0x80000000, 0xff0000ff,
+  0xba00003a, 0x00000000, 0x00000000, 0x0b000000, 0xc1000027,
+  0xff0000e2, 0x9d000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xba00003a,
+  0x00000000, 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2,
+  0x9d000000, 0x2b000000, 0xff00009b, 0xfb000095, 0x39000000,
+  0x00000000, 0x00000000, 0x18000000, 0xf9000096, 0xff00009b,
+  0x85000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x7f000000, 0xff0000fd,
+  0xc0000002, 0x00000000, 0x43000000, 0x88000000, 0x46000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x2b000000,
+  0xff000097, 0xf4000080, 0x1b000000, 0x00000000, 0x00000000,
+  0x08000000, 0xe0000059, 0xff0000b5, 0x55000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xf9000089, 0x28000000, 0x00000000,
+  0x00000000, 0x18000000, 0xf9000096, 0xff000097, 0x83000000,
+  0x2b000000, 0xff00009b, 0xfb000095, 0x39000000, 0x00000000,
+  0x00000000, 0x18000000, 0xf9000096, 0xff00009b, 0x85000000,
+  0x80000000, 0xff0000ff, 0xba00003a, 0x00000000, 0x00000000,
+  0x0b000000, 0xc1000027, 0xff0000e2, 0x9d000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000,
+  0xc4000000, 0xff0000ff, 0xe2000000, 0x88000000, 0x88000000,
+  0x88000000, 0x88000000, 0xc4000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a,
+  0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000,
+  0x00000000, 0x66000000, 0xff0000c1, 0xee000050, 0x8e00000d,
+  0xe400005a, 0xfe0000c7, 0x66000000, 0xb800001a, 0xff0000e4,
+  0xf8000099, 0xac000033, 0xac000033, 0xf5000099, 0xff0000e4,
+  0xcc00001a, 0x4e000000, 0x80000000, 0xff0000ff, 0xfc0000c5,
+  0xcf00004a, 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074,
+  0x95000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a,
+  0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000,
+  0x00000000, 0xb800001a, 0xff0000e4, 0xf8000099, 0xac000033,
+  0xac000033, 0xf5000099, 0xff0000e4, 0xcc00001a, 0x4e000000,
+  0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000,
+  0x00000000, 0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000,
+  0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x66000000, 0xff0000c1, 0xee000050,
+  0x8e00000d, 0xe400005a, 0xfe0000c7, 0xaa000000, 0xc4000000,
+  0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0xad000015,
+  0xff0000d3, 0xf200007f, 0xaa00002d, 0x9d00001d, 0xe6000061,
+  0xff0000e9, 0xe9000025, 0x60000000, 0x44000000, 0xc4000000,
+  0xff0000ff, 0xe2000000, 0x44000000, 0x44000000, 0xc4000000,
+  0xff0000ff, 0xe2000000, 0x44000000, 0x44000000, 0xc4000000,
+  0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xff0000bc, 0xf5000088, 0xa900002d, 0xac000033,
+  0xf5000099, 0xff0000e1, 0xc9000017, 0x4c000000, 0x00000000,
+  0xb800001a, 0xff0000e4, 0xf8000099, 0xac000033, 0xac000033,
+  0xf5000099, 0xff0000e4, 0xcc00001a, 0x4e000000, 0x80000000,
+  0xff0000ff, 0xfc0000c5, 0xcf00004a, 0x91000010, 0xab00002c,
+  0xfa00009d, 0xff000074, 0x95000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0,
+  0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, 0x00000000,
+  0x15000000, 0xee000046, 0xff0000bd, 0xff0000ef, 0xfd0000be,
+  0xeb00003f, 0x6f000000, 0x13000000, 0xcd00001f, 0xff0000ae,
+  0xff0000e8, 0xff0000e8, 0xff0000ae, 0xd900001f, 0x7d000000,
+  0x0d000000, 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1,
+  0xff0000f0, 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0,
+  0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, 0x00000000,
+  0x13000000, 0xcd00001f, 0xff0000ae, 0xff0000e8, 0xff0000e8,
+  0xff0000ae, 0xd900001f, 0x7d000000, 0x0d000000, 0x80000000,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x15000000, 0xee000046, 0xff0000bd, 0xff0000ef,
+  0xfd0000be, 0xeb00003f, 0xbc000000, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x00000000, 0x0e000000, 0xc0000018,
+  0xff0000a4, 0xff0000e1, 0xff0000e5, 0xfc00009b, 0xec000042,
+  0x8d000000, 0x13000000, 0x80000000, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x80000000, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x80000000, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xf8000012, 0xff0000a6, 0xff0000e2, 0xff0000e9, 0xff0000ad,
+  0xd100001d, 0x78000000, 0x0c000000, 0x00000000, 0x13000000,
+  0xcd00001f, 0xff0000ae, 0xff0000e8, 0xff0000e8, 0xff0000ae,
+  0xd900001f, 0x7d000000, 0x0d000000, 0x36000000, 0xd300003b,
+  0xfb0000aa, 0xff0000e1, 0xff0000f0, 0xff0000b6, 0xfc000076,
+  0xae000008, 0x3a000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x3c000000, 0x77000000, 0xbb000000,
+  0xbb000000, 0xbb000000, 0xbb000000, 0xbb000000, 0xbb000000,
+  0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000,
+  0x00000000, 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000,
+  0x6e000000, 0x3b000000, 0x04000000, 0x00000000, 0x00000000,
+  0x0f000000, 0x78000000, 0xaa000000, 0xaa000000, 0x68000000,
+  0x20000000, 0x00000000, 0x00000000, 0x47000000, 0xa5000000,
+  0xb4000000, 0x94000000, 0x57000000, 0x10000000, 0x00000000,
+  0x00000000, 0x00000000, 0x4a000000, 0x96000000, 0xb2000000,
+  0xa8000000, 0x6e000000, 0x3b000000, 0x04000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000,
+  0x6e000000, 0x3b000000, 0x04000000, 0x00000000, 0x00000000,
+  0x00000000, 0x47000000, 0xa5000000, 0xb4000000, 0x94000000,
+  0x57000000, 0x10000000, 0x00000000, 0x3c000000, 0x77000000,
+  0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x3c000000,
+  0x77000000, 0xbb000000, 0xbb000000, 0x9e000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x0f000000, 0x78000000, 0xaa000000, 0xaa000000,
+  0x68000000, 0x54000000, 0x77000000, 0xbb000000, 0xbb000000,
+  0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x3b000000,
+  0x9f000000, 0xb0000000, 0x9e000000, 0x51000000, 0x21000000,
+  0x00000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000,
+  0x9e000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000,
+  0x9e000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000,
+  0x9e000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x43000000, 0x9d000000, 0xb3000000, 0x95000000, 0x57000000,
+  0x0f000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x47000000, 0xa5000000, 0xb4000000, 0x94000000, 0x57000000,
+  0x10000000, 0x00000000, 0x00000000, 0x00000000, 0x4a000000,
+  0x96000000, 0xb2000000, 0xa8000000, 0x6e000000, 0x3b000000,
+  0x04000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x3c000000, 0x77000000,
+  0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x09000000, 0x63000000, 0x08000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x44000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000,
+  0x88000000, 0x88000000, 0x44000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x69000000, 0xff0000b4, 0x65000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000,
+  0x44000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x44000000,
+  0x88000000, 0x88000000, 0x44000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0x80000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x6a000000, 0xff0000b6, 0x9c000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0x80000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x08000000,
+  0x61000000, 0x60000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x3c000000, 0xbb000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x44000000, 0xc4000000,
+  0xff0000ff, 0xe2000000, 0x88000000, 0x88000000, 0x88000000,
+  0x0f000000, 0x00000000, 0x00000000, 0x41000000, 0x78000000,
+  0x78000000, 0x46000000, 0x01000000, 0x00000000, 0x00000000,
+  0x44000000, 0x88000000, 0x88000000, 0x45000000, 0x3d000000,
+  0x73000000, 0x6c000000, 0x37000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x41000000,
+  0x78000000, 0x78000000, 0x46000000, 0x01000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x38000000, 0x6e000000, 0x79000000, 0x43000000, 0x00000000,
+  0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000,
+  0x44000000, 0x38000000, 0x75000000, 0x86000000, 0x88000000,
+  0x44000000, 0x00000000, 0x00000000, 0x42000000, 0x78000000,
+  0x78000000, 0x41000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x1f000000, 0x5c000000, 0x78000000,
+  0x60000000, 0x27000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x42000000, 0x78000000, 0x78000000,
+  0x41000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x1f000000, 0x5c000000, 0x78000000, 0x60000000,
+  0x27000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x1f000000, 0x5c000000, 0x78000000, 0x60000000, 0x27000000,
+  0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000,
+  0x44000000, 0x00000000, 0x44000000, 0x88000000, 0x88000000,
+  0x45000000, 0x3d000000, 0x73000000, 0x6c000000, 0x37000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x43000000, 0x79000000, 0x6f000000, 0x38000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x44000000,
+  0x88000000, 0x88000000, 0x44000000, 0x00000000, 0x00000000,
+  0x44000000, 0x88000000, 0x88000000, 0x44000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x43000000, 0x79000000,
+  0x6f000000, 0x38000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x00000000, 0x02000000, 0x46000000,
+  0x76000000, 0x65000000, 0x27000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff00009c, 0x1c000000,
+  0x10000000, 0xc900001f, 0xff0000ad, 0xfe0000e7, 0xff0000e7,
+  0xff0000af, 0xc600001f, 0x11000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xff0000ff, 0xee000011, 0xff0000a3, 0xff0000e5,
+  0xff0000ca, 0xfc000072, 0x94000010, 0x00000000, 0x00000000,
+  0x00000000, 0x10000000, 0xc900001f, 0xff0000ad, 0xfe0000e7,
+  0xff0000e7, 0xff0000af, 0xc600001f, 0x11000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xf7000011, 0xff0000a2,
+  0xfe0000e0, 0xff0000e9, 0xff0000ad, 0xc100001d, 0x0f000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0xef000014,
+  0xff0000a3, 0xff0000dd, 0xff0000ff, 0xff0000ff, 0x80000000,
+  0x10000000, 0xc900001f, 0xff0000ad, 0xff0000e7, 0xff0000e7,
+  0xff0000ad, 0xc900001f, 0x13000000, 0x00000000, 0x00000000,
+  0x9000000a, 0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc,
+  0xf50000a0, 0xc8000036, 0x35000000, 0x00000000, 0x10000000,
+  0xc900001f, 0xff0000ad, 0xff0000e7, 0xff0000e7, 0xff0000ad,
+  0xc900001f, 0x13000000, 0x00000000, 0x00000000, 0x9000000a,
+  0xfd000076, 0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0,
+  0xc8000036, 0x35000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x9000000a, 0xfd000076,
+  0xff0000b6, 0xff0000ef, 0xfe0000dc, 0xf50000a0, 0xc8000036,
+  0x35000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0x80000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0xee000011,
+  0xff0000a3, 0xff0000e5, 0xff0000ca, 0xfc000072, 0x94000010,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x10000000, 0xc900001e,
+  0xff0000ad, 0xff0000e9, 0xfe0000e0, 0xff0000a2, 0xed000011,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, 0x00000000,
+  0x10000000, 0xc900001e, 0xff0000ad, 0xff0000e9, 0xfe0000e0,
+  0xff0000a2, 0xed000011, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x36000000, 0xdd000045, 0xff0000bf, 0xff0000ef,
+  0xff0000b9, 0xfc000063, 0x7e00000b, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff, 0xdd000000,
+  0xbb000000, 0xbb000000, 0xbb000000, 0x57000000, 0xb700001a,
+  0xff0000e6, 0xf500008e, 0xc9000031, 0xd000002c, 0xf8000087,
+  0xff0000dd, 0xb1000014, 0x00000000, 0x3c000000, 0xbb000000,
+  0xff0000ff, 0xff0000b1, 0xea000077, 0xbd00001d, 0xda000042,
+  0xfd0000bc, 0xfa000074, 0x36000000, 0x00000000, 0x00000000,
+  0xb700001a, 0xff0000e6, 0xf500008e, 0xc9000031, 0xd000002c,
+  0xf8000087, 0xff0000dd, 0xb1000014, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xff0000bd, 0xf200008c, 0xc500002f,
+  0xd1000033, 0xf900009a, 0xff0000e1, 0xb6000017, 0x00000000,
+  0x3c000000, 0xbb000000, 0xff0000ff, 0xff0000b8, 0xe0000067,
+  0xb8000015, 0xf000005c, 0xff0000ff, 0xc0000000, 0xbc00001a,
+  0xff0000e4, 0xf5000098, 0xc8000033, 0xd1000033, 0xf900009a,
+  0xff0000e4, 0xbe00001a, 0x00000000, 0x43000000, 0xff000078,
+  0xf8000096, 0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf,
+  0xff0000ff, 0x8d000000, 0x00000000, 0xbc00001a, 0xff0000e4,
+  0xf5000098, 0xc8000033, 0xd1000033, 0xf900009a, 0xff0000e4,
+  0xbe00001a, 0x00000000, 0x43000000, 0xff000078, 0xf8000096,
+  0xbe00002c, 0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff,
+  0x8d000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x43000000, 0xff000078, 0xf8000096, 0xbe00002c,
+  0xb9000011, 0xe5000051, 0xfa0000cf, 0xff0000ff, 0x8d000000,
+  0x3c000000, 0xbb000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x3c000000, 0xbb000000, 0xff0000ff, 0xff0000b1, 0xea000077,
+  0xbd00001d, 0xda000042, 0xfd0000bc, 0xfa000074, 0x36000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0xb7000019, 0xff0000e2, 0xf5000098,
+  0xc8000033, 0xd100002f, 0xf800008c, 0xff0000bc, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x3c000000, 0xbb000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x3c000000, 0xbb000000,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0xb7000019,
+  0xff0000e2, 0xf5000098, 0xc8000033, 0xd100002f, 0xf800008c,
+  0xff0000bc, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xf2000076, 0xbe000014, 0xd7000031,
+  0xfe0000b1, 0xff00008e, 0x33000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x2e000000, 0xff00009b, 0xf900009e,
+  0x82000000, 0x47000000, 0x19000000, 0x25000000, 0xf700008e,
+  0xfe000086, 0x25000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xf5000078, 0x5e000000, 0x3c000000, 0x0f000000, 0xcd00004b,
+  0xfe0000c1, 0x89000000, 0x00000000, 0x2e000000, 0xff00009b,
+  0xf900009e, 0x82000000, 0x47000000, 0x19000000, 0x25000000,
+  0xf700008e, 0xfe000086, 0x25000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xf900008a, 0x68000000, 0x46000000, 0x18000000,
+  0x30000000, 0xfb000096, 0xff000098, 0x32000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xf0000068, 0x5d000000, 0x34000000,
+  0x42000000, 0x90000000, 0xb4000000, 0xff00009c, 0xf8000092,
+  0x7e000000, 0x4c000000, 0x1a000000, 0x30000000, 0xfa000096,
+  0xff00009b, 0x37000000, 0x75000000, 0xfe0000e4, 0xc5000025,
+  0x4c000000, 0x16000000, 0x09000000, 0xcd000040, 0xff0000ff,
+  0xc0000000, 0x2e000000, 0xff00009c, 0xf8000092, 0x7e000000,
+  0x4c000000, 0x1a000000, 0x30000000, 0xfa000096, 0xff00009b,
+  0x37000000, 0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000,
+  0x16000000, 0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x75000000, 0xfe0000e4, 0xc5000025, 0x4c000000, 0x16000000,
+  0x09000000, 0xcd000040, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xf5000078, 0x5e000000, 0x3c000000,
+  0x0f000000, 0xcd00004b, 0xfe0000c1, 0x89000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x2a000000, 0xff00009a, 0xf9000092, 0x7d000000, 0x4c000000,
+  0x1a000000, 0x26000000, 0xf600008b, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x2a000000, 0xff00009a, 0xf9000092,
+  0x7d000000, 0x4c000000, 0x1a000000, 0x26000000, 0xf600008b,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x3c000000,
+  0x77000000, 0x9b000000, 0x3b000000, 0x0a000000, 0xaf000027,
+  0xff0000e4, 0x8f000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x5d000000, 0xff0000da, 0xeb000034, 0xad000000,
+  0x88000000, 0x88000000, 0x88000000, 0xde00002f, 0xff0000cb,
+  0x7b000000, 0x00000000, 0x80000000, 0xff0000ff, 0xd1000028,
+  0x3c000000, 0x00000000, 0x00000000, 0x90000011, 0xff0000fc,
+  0xaf000000, 0x00000000, 0x5d000000, 0xff0000da, 0xeb000034,
+  0xad000000, 0x88000000, 0x88000000, 0x88000000, 0xde00002f,
+  0xff0000cb, 0x7b000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xd7000036, 0x45000000, 0x00000000, 0x00000000, 0x00000000,
+  0xbe00004b, 0xfe0000d8, 0x95000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xcb000019, 0x34000000, 0x00000000, 0x00000000,
+  0x00000000, 0x5d000000, 0xff0000da, 0xd0000049, 0x49000000,
+  0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9,
+  0x96000000, 0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055,
+  0x82000005, 0x48000000, 0x44000000, 0x88000000, 0x9e000000,
+  0x5d000000, 0xff0000da, 0xd0000049, 0x49000000, 0x00000000,
+  0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d9, 0x96000000,
+  0x49000000, 0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005,
+  0x48000000, 0x44000000, 0x88000000, 0x9e000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x49000000,
+  0xf70000a8, 0xfb0000cb, 0xea000055, 0x82000005, 0x48000000,
+  0x44000000, 0x88000000, 0x9e000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xd1000028, 0x3c000000, 0x00000000, 0x00000000,
+  0x90000011, 0xff0000fc, 0xaf000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5b000000,
+  0xff0000da, 0xd0000049, 0x49000000, 0x00000000, 0x00000000,
+  0x00000000, 0xb0000037, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x5b000000, 0xff0000da, 0xd0000049, 0x49000000,
+  0x00000000, 0x00000000, 0x00000000, 0xb0000037, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x2d000000,
+  0x60000000, 0x81000000, 0x88000000, 0xc4000000, 0xff0000f6,
+  0xb3000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000,
+  0x7a000000, 0xff0000f6, 0xff0000ff, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ee, 0xa8000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x14000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xbf000000,
+  0x00000000, 0x7a000000, 0xff0000f6, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xff0000ee,
+  0xa8000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000001,
+  0x1b000000, 0x00000000, 0x00000000, 0x00000000, 0x92000013,
+  0xff0000f6, 0xb3000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x0d000000, 0x00000000, 0x00000000, 0x00000000,
+  0x78000000, 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000,
+  0x00000000, 0x00000000, 0x92000013, 0xff0000f6, 0xb4000000,
+  0x00000000, 0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2,
+  0xfb0000c2, 0xf200005c, 0x72000001, 0x00000000, 0x78000000,
+  0xff0000f6, 0xc0000012, 0x25000000, 0x00000000, 0x00000000,
+  0x00000000, 0x92000013, 0xff0000f6, 0xb4000000, 0x00000000,
+  0x8f000007, 0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2,
+  0xf200005c, 0x72000001, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x8f000007,
+  0xf900007e, 0xfc0000dd, 0xff0000f2, 0xfb0000c2, 0xf200005c,
+  0x72000001, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x14000000, 0x00000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xbf000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x78000000, 0xff0000f6,
+  0xc0000012, 0x25000000, 0x00000000, 0x00000000, 0x00000000,
+  0x80000001, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x78000000, 0xff0000f6, 0xc0000012, 0x25000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000001, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x01000000, 0xa1000010, 0xfe00007f, 0xfe0000c1,
+  0xff0000f9, 0xff0000ff, 0xff0000ff, 0xff0000ff, 0xbd000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x69000000,
+  0xff0000d9, 0xe8000028, 0xbb000000, 0xbb000000, 0xbb000000,
+  0xbb000000, 0xda000000, 0xff000000, 0xc1000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x69000000, 0xff0000d9, 0xe8000028, 0xbb000000, 0xbb000000,
+  0xbb000000, 0xbb000000, 0xda000000, 0xff000000, 0xc1000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xd300002b, 0x01000000,
+  0x00000000, 0x00000000, 0x00000000, 0xbe00004b, 0xfe0000d8,
+  0xb1000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x5d000000,
+  0xff0000da, 0xdc00004a, 0x09000000, 0x00000000, 0x00000000,
+  0x00000000, 0xbe00004b, 0xfe0000d9, 0xb1000000, 0x44000000,
+  0x88000000, 0x65000000, 0x84000000, 0xc8000014, 0xf4000059,
+  0xfc0000cc, 0xfb000098, 0x40000000, 0x5d000000, 0xff0000da,
+  0xdc00004a, 0x09000000, 0x00000000, 0x00000000, 0x00000000,
+  0xbe00004b, 0xfe0000d9, 0xb1000000, 0x44000000, 0x88000000,
+  0x65000000, 0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc,
+  0xfb000098, 0x40000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x44000000, 0x88000000, 0x65000000,
+  0x84000000, 0xc8000014, 0xf4000059, 0xfc0000cc, 0xfb000098,
+  0x40000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x5b000000, 0xff0000da, 0xdc000049,
+  0x09000000, 0x00000000, 0x00000000, 0x00000000, 0xa700002c,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x7e000000,
+  0xff0000fc, 0xc7000011, 0x00000000, 0x00000000, 0x00000000,
+  0xa500002a, 0xff0000ff, 0xc0000000, 0x00000000, 0x5b000000,
+  0xff0000da, 0xdc000049, 0x09000000, 0x00000000, 0x00000000,
+  0x00000000, 0xa700002c, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x48000000, 0xff000083, 0xfb0000a8, 0xc7000038, 0xb500000a,
+  0xba000000, 0xdd000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x7f000000, 0xff0000fd, 0xc0000002,
+  0x00000000, 0x43000000, 0x88000000, 0x71000000, 0xff000097,
+  0xf4000080, 0x1b000000, 0x00000000, 0x00000000, 0x08000000,
+  0xe0000059, 0xff0000b5, 0x55000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xc0000000, 0x00000000, 0x2b000000,
+  0xff000097, 0xf4000080, 0x1b000000, 0x00000000, 0x00000000,
+  0x08000000, 0xe0000059, 0xff0000b5, 0x55000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xf7000083, 0x1f000000, 0x00000000,
+  0x00000000, 0x18000000, 0xf9000096, 0xff000097, 0x83000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x2b000000, 0xff00009b,
+  0xfb000095, 0x39000000, 0x00000000, 0x00000000, 0x18000000,
+  0xf9000096, 0xff00009b, 0x85000000, 0x80000000, 0xff0000ff,
+  0xba00003a, 0x00000000, 0x00000000, 0x0b000000, 0xc1000027,
+  0xff0000e2, 0x9d000000, 0x2b000000, 0xff00009b, 0xfb000095,
+  0x39000000, 0x00000000, 0x00000000, 0x18000000, 0xf9000096,
+  0xff00009b, 0x85000000, 0x80000000, 0xff0000ff, 0xba00003a,
+  0x00000000, 0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2,
+  0x9d000000, 0x00000000, 0x44000000, 0x88000000, 0x45000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xba00003a, 0x00000000,
+  0x00000000, 0x0b000000, 0xc1000027, 0xff0000e2, 0x9d000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x80000000, 0xff0000ff, 0xc0000000, 0x00000000,
+  0x00000000, 0x00000000, 0x80000000, 0xff0000ff, 0xc0000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x2a000000, 0xff000099, 0xfb000092, 0x38000000,
+  0x00000000, 0x00000000, 0x0b000000, 0xf0000084, 0xff0000ff,
+  0xc0000000, 0x00000000, 0x00000000, 0x67000000, 0xfe0000c2,
+  0xdf000048, 0x09000000, 0x00000000, 0x07000000, 0xec00007a,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x2a000000, 0xff000099,
+  0xfb000092, 0x38000000, 0x00000000, 0x00000000, 0x0b000000,
+  0xf0000084, 0xff0000ff, 0xc0000000, 0x00000000, 0x76000000,
+  0xff0000e1, 0xbd000026, 0x54000000, 0x1c000000, 0x05000000,
+  0x98000015, 0xff0000ff, 0xc0000000, 0x00000000, 0x00000000,
+  0x44000000, 0x88000000, 0x88000000, 0x44000000, 0x00000000,
+  0x00000000, 0x66000000, 0xff0000c1, 0xee000050, 0x8e00000d,
+  0xe400005a, 0xfe0000c7, 0x66000000, 0xad000015, 0xff0000d3,
+  0xf200007f, 0xaa00002d, 0x9d00001d, 0xe6000061, 0xff0000e9,
+  0xe9000025, 0x60000000, 0x44000000, 0xc4000000, 0xff0000ff,
+  0xe2000000, 0x44000000, 0x00000000, 0x44000000, 0xc4000000,
+  0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0xad000015,
+  0xff0000d3, 0xf200007f, 0xaa00002d, 0x9d00001d, 0xe6000061,
+  0xff0000e9, 0xe9000025, 0x60000000, 0x44000000, 0xc4000000,
+  0xff0000ff, 0xff0000cc, 0xf3000083, 0xa900002b, 0xac000033,
+  0xf5000099, 0xff0000e1, 0xc9000017, 0x4c000000, 0x44000000,
+  0xc4000000, 0xff0000ff, 0xe2000000, 0x88000000, 0x44000000,
+  0x00000000, 0x00000000, 0x00000000, 0xb800001a, 0xff0000e4,
+  0xf8000099, 0xac000033, 0xac000033, 0xf5000099, 0xff0000e4,
+  0xcc00001a, 0x4e000000, 0x80000000, 0xff0000ff, 0xfc0000c5,
+  0xcf00004a, 0x91000010, 0xab00002c, 0xfa00009d, 0xff000074,
+  0x95000000, 0x00000000, 0xb800001a, 0xff0000e4, 0xf8000099,
+  0xac000033, 0xac000033, 0xf5000099, 0xff0000e4, 0xcc00001a,
+  0x4e000000, 0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a,
+  0x91000010, 0xab00002c, 0xfa00009d, 0xff000074, 0x95000000,
+  0x00000000, 0x8e000009, 0xff0000e8, 0x72000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x80000000, 0xff0000ff, 0xfc0000c5, 0xcf00004a, 0x91000010,
+  0xab00002c, 0xfa00009d, 0xff000074, 0x95000000, 0x44000000,
+  0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, 0x44000000,
+  0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000, 0x00000000,
+  0x44000000, 0xc4000000, 0xff0000ff, 0xe2000000, 0x44000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0xb8000019, 0xff0000e2, 0xf7000097, 0xab000032,
+  0xa900002b, 0xef000083, 0xff0000cc, 0xff0000ff, 0xe2000000,
+  0x44000000, 0x00000000, 0x30000000, 0xf9000076, 0xfd0000ba,
+  0xc4000041, 0x9c00001c, 0xe9000076, 0xff0000b0, 0xff0000ff,
+  0xe2000000, 0x44000000, 0x00000000, 0xb8000019, 0xff0000e2,
+  0xf7000097, 0xab000032, 0xa900002b, 0xef000083, 0xff0000cc,
+  0xff0000ff, 0xe2000000, 0x44000000, 0x47000000, 0xfd000086,
+  0xfd0000af, 0xbd000038, 0x8f00000e, 0xc000003c, 0xfe0000b5,
+  0xff0000ff, 0xe2000000, 0x44000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, 0x00000000,
+  0x15000000, 0xee000046, 0xff0000bd, 0xff0000ef, 0xfd0000be,
+  0xeb00003f, 0x6f000000, 0x0e000000, 0xc0000018, 0xff0000a4,
+  0xff0000e1, 0xff0000e5, 0xfc00009b, 0xec000042, 0x8d000000,
+  0x13000000, 0x80000000, 0xff0000ff, 0xff0000ff, 0xff0000ff,
+  0x80000000, 0x00000000, 0x80000000, 0xff0000ff, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x00000000, 0x0e000000, 0xc0000018,
+  0xff0000a4, 0xff0000e1, 0xff0000e5, 0xfc00009b, 0xec000042,
+  0x8d000000, 0x13000000, 0x80000000, 0xff0000ff, 0xff0000ff,
+  0xfa00001a, 0xff0000ad, 0xff0000e4, 0xff0000e9, 0xff0000ad,
+  0xd100001d, 0x78000000, 0x0c000000, 0x80000000, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000,
+  0x00000000, 0x00000000, 0x13000000, 0xcd00001f, 0xff0000ae,
+  0xff0000e8, 0xff0000e8, 0xff0000ae, 0xd900001f, 0x7d000000,
+  0x0d000000, 0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1,
+  0xff0000f0, 0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000,
+  0x00000000, 0x13000000, 0xcd00001f, 0xff0000ae, 0xff0000e8,
+  0xff0000e8, 0xff0000ae, 0xd900001f, 0x7d000000, 0x0d000000,
+  0x36000000, 0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0,
+  0xff0000b6, 0xfc000076, 0xae000008, 0x3a000000, 0x00000000,
+  0xba00002b, 0xff0000ba, 0x9f000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x36000000,
+  0xd300003b, 0xfb0000aa, 0xff0000e1, 0xff0000f0, 0xff0000b6,
+  0xfc000076, 0xae000008, 0x3a000000, 0x80000000, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0x80000000, 0x80000000, 0xff0000ff,
+  0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000, 0x80000000,
+  0xff0000ff, 0xff0000ff, 0xff0000ff, 0x80000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x0f000000, 0xc300001e, 0xff0000ae, 0xff0000e9, 0xfe0000e5,
+  0xff0000ae, 0xf600001a, 0xff0000ff, 0xff0000ff, 0x80000000,
+  0x00000000, 0x00000000, 0x96000011, 0xfd000075, 0xff0000cc,
+  0xff0000e6, 0xff0000a4, 0xf2000011, 0xff0000ff, 0xff0000ff,
+  0x80000000, 0x00000000, 0x0f000000, 0xc300001e, 0xff0000ae,
+  0xff0000e9, 0xfe0000e5, 0xff0000ae, 0xf600001a, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x00000000, 0x9b000011, 0xfc000082,
+  0xff0000cb, 0xff0000f2, 0xff0000ca, 0xfe000048, 0xff0000ff,
+  0xff0000ff, 0x80000000, 0x00000000, 0x80000000, 0xff0000ff,
+  0xff0000ff, 0xc0000000, 0x00000000, 0x00000000, 0x00000000,
+  0x0f000000, 0x78000000, 0xaa000000, 0xaa000000, 0x68000000,
+  0x20000000, 0x00000000, 0x00000000, 0x3b000000, 0x9f000000,
+  0xb0000000, 0x9e000000, 0x51000000, 0x21000000, 0x00000000,
+  0x3c000000, 0x77000000, 0xbb000000, 0xbb000000, 0x9e000000,
+  0x00000000, 0x3c000000, 0x77000000, 0xbb000000, 0xbb000000,
+  0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x3b000000,
+  0x9f000000, 0xb0000000, 0x9e000000, 0x51000000, 0x21000000,
+  0x00000000, 0x3c000000, 0x77000000, 0xbb000000, 0x9e000000,
+  0x47000000, 0xa5000000, 0xb3000000, 0x95000000, 0x57000000,
+  0x0f000000, 0x00000000, 0x3c000000, 0x77000000, 0xbb000000,
+  0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x47000000, 0xa5000000,
+  0xb4000000, 0x94000000, 0x57000000, 0x10000000, 0x00000000,
+  0x00000000, 0x00000000, 0x4a000000, 0x96000000, 0xb2000000,
+  0xa8000000, 0x6e000000, 0x3b000000, 0x04000000, 0x00000000,
+  0x00000000, 0x00000000, 0x47000000, 0xa5000000, 0xb4000000,
+  0x94000000, 0x57000000, 0x10000000, 0x00000000, 0x00000000,
+  0x00000000, 0x4a000000, 0x96000000, 0xb2000000, 0xa8000000,
+  0x6e000000, 0x3b000000, 0x04000000, 0x13000000, 0xf600007d,
+  0xf900006e, 0x66000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x4a000000, 0x96000000, 0xb2000000, 0xa8000000, 0x6e000000,
+  0x3b000000, 0x04000000, 0x3c000000, 0x77000000, 0xbb000000,
+  0xbb000000, 0x9e000000, 0x3c000000, 0x77000000, 0xbb000000,
+  0xbb000000, 0x9e000000, 0x00000000, 0x3c000000, 0x77000000,
+  0xbb000000, 0xbb000000, 0x9e000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x47000000, 0xa5000000, 0xb5000000, 0x94000000,
+  0x7f000000, 0x7e000000, 0xbb000000, 0x9e000000, 0x00000000,
+  0x00000000, 0x00000000, 0x3d000000, 0x8d000000, 0xaa000000,
+  0x93000000, 0x7b000000, 0x7c000000, 0xbb000000, 0x9e000000,
+  0x00000000, 0x00000000, 0x00000000, 0x47000000, 0xa5000000,
+  0xb5000000, 0x94000000, 0x7f000000, 0x7e000000, 0xbb000000,
+  0x9e000000, 0x00000000, 0x00000000, 0x35000000, 0x8d000000,
+  0xaa000000, 0xa1000000, 0x8e000000, 0x8a000000, 0xbb000000,
+  0x9e000000, 0x00000000, 0x3c000000, 0x77000000, 0xbb000000,
+  0x9e000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x6d000000, 0xff000097, 0x9c000002,
+  0x37000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x06000000, 0x79000000, 0x4d000000, 0x01000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+  0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+void
+subpicture_get_info (VideoSubpictureInfo * info)
+{
+  info->width = SUBPICTURE_WIDTH;
+  info->height = SUBPICTURE_HEIGHT;
+  info->data = text;
+  info->data_size = SUBPICTURE_DATA_SIZE;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-subpicture-data.h b/subprojects/gstreamer-vaapi/tests/internal/test-subpicture-data.h
new file mode 100644 (file)
index 0000000..cc37988
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ *  test-subpicture-data.h - subpicture data
+ *
+ *  Copyright (C) <2011> Intel Corporation
+ *  Copyright (C) <2011> Collabora Ltd.
+ *  Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#ifndef TEST_SUBPICTURE_DATA
+#define TEST_SUBPICTURE_DATA
+
+#include <glib.h>
+#include "test-decode.h"
+
+typedef struct _VideoSubpictureInfo VideoSubpictureInfo;
+
+struct _VideoSubpictureInfo {
+    guint               width;
+    guint               height;
+    const guint32      *data;
+    guint               data_size;
+};
+
+void subpicture_get_info(VideoSubpictureInfo *info);
+
+#endif /* TEST_SUBPICTURE_DATA*/
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-subpicture.c b/subprojects/gstreamer-vaapi/tests/internal/test-subpicture.c
new file mode 100644 (file)
index 0000000..804f0a9
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ *  test-subpicture.c - Test GstVaapiSubpicture
+ *
+ *  Copyright (C) <2011-2013> Intel Corporation
+ *  Copyright (C) <2011> Collabora Ltd.
+ *  Copyright (C) <2011> Thibault Saunier <thibault.saunier@collabora.com>
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/vaapi/gstvaapisurface.h>
+#include "decoder.h"
+#include "output.h"
+#include "test-subpicture-data.h"
+
+static inline void
+pause (void)
+{
+  g_print ("Press any key to continue...\n");
+  getchar ();
+}
+
+static gchar *g_codec_str;
+static gdouble g_global_alpha = 1.0;
+
+static GOptionEntry g_options[] = {
+  {"codec", 'c',
+        0,
+        G_OPTION_ARG_STRING, &g_codec_str,
+      "codec to test", NULL},
+  {"global-alpha", 'g',
+        0,
+        G_OPTION_ARG_DOUBLE, &g_global_alpha,
+      "global-alpha value", NULL},
+  {NULL,}
+};
+
+static void
+upload_subpicture (GstBuffer * buffer, const VideoSubpictureInfo * subinfo)
+{
+  const guint32 *const src = subinfo->data;
+  guint i, len = subinfo->data_size / 4;
+  GstMapInfo map_info;
+  guint32 *dst;
+
+  if (!gst_buffer_map (buffer, &map_info, GST_MAP_WRITE))
+    return;
+  dst = (guint32 *) map_info.data;
+
+  /* Convert from RGBA source to ARGB */
+  for (i = 0; i < len; i++) {
+    const guint32 rgba = src[i];
+    dst[i] = (rgba >> 8) | (rgba << 24);
+  }
+
+  gst_buffer_unmap (buffer, &map_info);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstVaapiDisplay *display;
+  GstVaapiWindow *window;
+  GstVaapiDecoder *decoder;
+  GstVaapiSurfaceProxy *proxy;
+  GstVaapiSurface *surface;
+  GstBuffer *buffer;
+  VideoSubpictureInfo subinfo;
+  GstVaapiRectangle subrect;
+  GstVideoOverlayRectangle *overlay;
+  GstVideoOverlayComposition *compo;
+  guint flags = 0;
+
+  static const guint win_width = 640;
+  static const guint win_height = 480;
+
+  if (!video_output_init (&argc, argv, g_options))
+    g_error ("failed to initialize video output subsystem");
+
+  if (g_global_alpha != 1.0)
+    flags |= GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA;
+
+  g_print ("Test subpicture\n");
+
+  display = video_output_create_display (NULL);
+  if (!display)
+    g_error ("could not create VA display");
+
+  window = video_output_create_window (display, win_width, win_height);
+  if (!window)
+    g_error ("could not create window");
+
+  decoder = decoder_new (display, g_codec_str);
+  if (!decoder)
+    g_error ("could not create decoder");
+
+  if (!decoder_put_buffers (decoder))
+    g_error ("could not fill decoder with sample data");
+
+  proxy = decoder_get_surface (decoder);
+  if (!proxy)
+    g_error ("could not get decoded surface");
+
+  surface = gst_vaapi_surface_proxy_get_surface (proxy);
+
+  subpicture_get_info (&subinfo);
+  buffer = gst_buffer_new_and_alloc (subinfo.data_size);
+  upload_subpicture (buffer, &subinfo);
+
+  /* We position the subpicture at the bottom center */
+  subrect.x = (gst_vaapi_surface_get_width (surface) - subinfo.width) / 2;
+  subrect.y = gst_vaapi_surface_get_height (surface) - subinfo.height - 10;
+  subrect.height = subinfo.height;
+  subrect.width = subinfo.width;
+
+  {
+    GstVideoMeta *const vmeta =
+        gst_buffer_add_video_meta (buffer, GST_VIDEO_FRAME_FLAG_NONE,
+        GST_VIDEO_OVERLAY_COMPOSITION_FORMAT_RGB,
+        subinfo.width, subinfo.height);
+    if (!vmeta)
+      g_error ("could not create video meta");
+
+    overlay = gst_video_overlay_rectangle_new_raw (buffer,
+        subrect.x, subrect.y, subrect.width, subrect.height, flags);
+  }
+  if (!overlay)
+    g_error ("could not create video overlay");
+  gst_buffer_unref (buffer);
+
+  if (flags & GST_VIDEO_OVERLAY_FORMAT_FLAG_GLOBAL_ALPHA)
+    gst_video_overlay_rectangle_set_global_alpha (overlay, g_global_alpha);
+
+  compo = gst_video_overlay_composition_new (overlay);
+  if (!compo)
+    g_error ("could not create video overlay composition");
+  gst_video_overlay_rectangle_unref (overlay);
+
+  if (!gst_vaapi_surface_set_subpictures_from_composition (surface, compo))
+    g_error ("could not create subpictures from video overlay compoition");
+
+  gst_vaapi_window_show (window);
+
+  if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL,
+          GST_VAAPI_PICTURE_STRUCTURE_FRAME))
+    g_error ("could not render surface");
+
+  pause ();
+
+  gst_video_overlay_composition_unref (compo);
+  gst_vaapi_surface_proxy_unref (proxy);
+  gst_object_unref (decoder);
+  gst_object_unref (window);
+  gst_object_unref (display);
+  g_free (g_codec_str);
+  video_output_exit ();
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-surfaces.c b/subprojects/gstreamer-vaapi/tests/internal/test-surfaces.c
new file mode 100644 (file)
index 0000000..9f515ee
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ *  test-surfaces.c - Test GstVaapiSurface and GstVaapiSurfacePool
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapisurfacepool.h>
+#include "output.h"
+
+#define MAX_SURFACES 4
+
+int
+main (int argc, char *argv[])
+{
+  GstVaapiDisplay *display;
+  GstVaapiSurface *surface;
+  GstVaapiID surface_id;
+  GstVaapiSurface *surfaces[MAX_SURFACES];
+  GstVaapiVideoPool *pool;
+  gint i;
+
+  static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+  static const guint width = 320;
+  static const guint height = 240;
+
+  if (!video_output_init (&argc, argv, NULL))
+    g_error ("failed to initialize video output subsystem");
+
+  display = video_output_create_display (NULL);
+  if (!display)
+    g_error ("could not create Gst/VA display");
+
+  surface = gst_vaapi_surface_new (display, chroma_type, width, height);
+  if (!surface)
+    g_error ("could not create Gst/VA surface");
+
+  surface_id = gst_vaapi_surface_get_id (surface);
+  g_print ("created surface %" GST_VAAPI_ID_FORMAT "\n",
+      GST_VAAPI_ID_ARGS (surface_id));
+
+  gst_vaapi_surface_unref (surface);
+
+  pool = gst_vaapi_surface_pool_new (display, GST_VIDEO_FORMAT_ENCODED,
+      width, height, 0);
+  if (!pool)
+    g_error ("could not create Gst/VA surface pool");
+
+  for (i = 0; i < MAX_SURFACES; i++) {
+    surface = gst_vaapi_video_pool_get_object (pool);
+    if (!surface)
+      g_error ("could not allocate Gst/VA surface from pool");
+    g_print ("created surface %" GST_VAAPI_ID_FORMAT " from pool\n",
+        GST_VAAPI_ID_ARGS (gst_vaapi_surface_get_id (surface)));
+    surfaces[i] = surface;
+  }
+
+  /* Check the pool doesn't return the last free'd surface */
+  surface = (GstVaapiSurface *)
+      gst_mini_object_ref (GST_MINI_OBJECT_CAST (surfaces[1]));
+
+  for (i = 0; i < 2; i++)
+    gst_vaapi_video_pool_put_object (pool, surfaces[i]);
+
+  for (i = 0; i < 2; i++) {
+    surfaces[i] = gst_vaapi_video_pool_get_object (pool);
+    if (!surfaces[i])
+      g_error ("could not re-allocate Gst/VA surface%d from pool", i);
+    g_print ("created surface %" GST_VAAPI_ID_FORMAT " from pool (realloc)\n",
+        GST_VAAPI_ID_ARGS (gst_vaapi_surface_get_id (surfaces[i])));
+  }
+
+  if (surface == surfaces[0])
+    g_error ("Gst/VA pool doesn't queue free surfaces");
+
+  for (i = MAX_SURFACES - 1; i >= 0; i--) {
+    if (!surfaces[i])
+      continue;
+    gst_vaapi_video_pool_put_object (pool, surfaces[i]);
+    surfaces[i] = NULL;
+  }
+
+  /* Unref in random order to check objects are correctly refcounted */
+  gst_object_unref (display);
+  gst_vaapi_video_pool_unref (pool);
+  gst_vaapi_surface_unref (surface);
+  video_output_exit ();
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-textures.c b/subprojects/gstreamer-vaapi/tests/internal/test-textures.c
new file mode 100644 (file)
index 0000000..0f7e1e9
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ *  test-textures.c - Test GstVaapiTexture
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/vaapi/gstvaapidisplay_glx.h>
+#include <gst/vaapi/gstvaapiwindow_glx.h>
+#include <gst/vaapi/gstvaapitexture_glx.h>
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapiimage.h>
+#include "image.h"
+
+static inline void
+pause (void)
+{
+  g_print ("Press any key to continue...\n");
+  getchar ();
+}
+
+static inline guint
+gl_get_current_texture_2d (void)
+{
+  GLint texture;
+  glGetIntegerv (GL_TEXTURE_BINDING_2D, &texture);
+  return (guint) texture;
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstVaapiDisplay *display;
+  GstVaapiWindow *window;
+  GstVaapiWindowGLX *glx_window;
+  GstVaapiSurface *surface;
+  GstVaapiImage *image;
+  GstVaapiTexture *textures[2];
+  GstVaapiTexture *texture;
+  GLuint texture_id;
+  GstVaapiRectangle src_rect;
+  GstVaapiRectangle dst_rect;
+  guint flags = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+
+  static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+  static const guint width = 320;
+  static const guint height = 240;
+  static const guint win_width = 640;
+  static const guint win_height = 480;
+
+  gst_init (&argc, &argv);
+
+  display = gst_vaapi_display_glx_new (NULL);
+  if (!display)
+    g_error ("could not create VA display");
+
+  surface = gst_vaapi_surface_new (display, chroma_type, width, height);
+  if (!surface)
+    g_error ("could not create VA surface");
+
+  image = image_generate (display, GST_VIDEO_FORMAT_NV12, width, height);
+  if (!image)
+    g_error ("could not create VA image");
+  if (!image_upload (image, surface))
+    g_error ("could not upload VA image to surface");
+
+  window = gst_vaapi_window_glx_new (display, win_width, win_height);
+  if (!window)
+    g_error ("could not create window");
+  glx_window = GST_VAAPI_WINDOW_GLX (window);
+
+  gst_vaapi_window_show (window);
+
+  if (!gst_vaapi_window_glx_make_current (glx_window))
+    g_error ("coult not bind GL context");
+
+  g_print ("#\n");
+  g_print ("# Create texture with gst_vaapi_texture_glx_new()\n");
+  g_print ("#\n");
+  {
+    texture = gst_vaapi_texture_glx_new (display,
+        GL_TEXTURE_2D, GL_RGBA, width, height);
+    if (!texture)
+      g_error ("could not create VA texture");
+
+    textures[0] = texture;
+    texture_id = gst_vaapi_texture_get_id (texture);
+
+    if (!gst_vaapi_texture_put_surface (texture, surface, NULL, flags))
+      g_error ("could not transfer VA surface to texture");
+
+    if (!gst_vaapi_window_glx_put_texture (glx_window, texture, NULL, NULL))
+      g_error ("could not render texture into the window");
+  }
+
+  g_print ("#\n");
+  g_print ("# Create texture with gst_vaapi_texture_glx_new_wrapped()\n");
+  g_print ("#\n");
+  {
+    const GLenum target = GL_TEXTURE_2D;
+    const GLenum format = GL_BGRA;
+
+    glEnable (target);
+    glGenTextures (1, &texture_id);
+    glBindTexture (target, texture_id);
+    glTexParameteri (target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+    glTexParameteri (target, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+    glTexParameteri (target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+    glTexParameteri (target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+    glPixelStorei (GL_UNPACK_ALIGNMENT, 4);
+    glTexImage2D (target,
+        0, GL_RGBA8, width, height, 0, format, GL_UNSIGNED_BYTE, NULL);
+    glDisable (target);
+
+    texture = gst_vaapi_texture_glx_new_wrapped (display,
+        texture_id, target, format);
+    if (!texture)
+      g_error ("could not create VA texture");
+
+    if (texture_id != gst_vaapi_texture_get_id (texture))
+      g_error ("invalid texture id");
+
+    if (gl_get_current_texture_2d () != texture_id)
+      g_error ("gst_vaapi_texture_glx_new_wrapped() altered texture bindings");
+
+    textures[1] = texture;
+
+    if (!gst_vaapi_texture_put_surface (texture, surface, NULL, flags))
+      g_error ("could not transfer VA surface to texture");
+
+    if (gl_get_current_texture_2d () != texture_id)
+      g_error ("gst_vaapi_texture_put_surface() altered texture bindings");
+
+    src_rect.x = 0;
+    src_rect.y = 0;
+    src_rect.width = width;
+    src_rect.height = height;
+
+    dst_rect.x = win_width / 2;
+    dst_rect.y = win_height / 2;
+    dst_rect.width = win_width / 2;
+    dst_rect.height = win_height / 2;
+
+    if (!gst_vaapi_window_glx_put_texture (glx_window, texture,
+            &src_rect, &dst_rect))
+      g_error ("could not render texture into the window");
+
+    if (gl_get_current_texture_2d () != texture_id)
+      g_error ("gst_vaapi_window_glx_put_texture() altered texture bindings");
+  }
+
+  gst_vaapi_window_glx_swap_buffers (glx_window);
+  pause ();
+
+  gst_mini_object_unref (GST_MINI_OBJECT_CAST (textures[0]));
+  gst_mini_object_unref (GST_MINI_OBJECT_CAST (textures[1]));
+  glDeleteTextures (1, &texture_id);
+
+  gst_object_unref (window);
+  gst_object_unref (display);
+  gst_deinit ();
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-vc1.c b/subprojects/gstreamer-vaapi/tests/internal/test-vc1.c
new file mode 100644 (file)
index 0000000..4a8dc9e
--- /dev/null
@@ -0,0 +1,1780 @@
+/*
+ *  test-vc1.c - VC-1 test data
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "test-vc1.h"
+
+#define VC1_CLIP_WIDTH            293
+#define VC1_CLIP_HEIGHT           240
+#define VC1_CLIP_DATA_SIZE      20864
+
+/* Data dump of a 320x240 VC-1 video clip (vc1.raw), it has a single frame */
+static const guchar vc1_clip[VC1_CLIP_DATA_SIZE] = {
+  0x00, 0x00, 0x01, 0x0f, 0xca, 0x00, 0x09, 0xf0, 0x77, 0x0a, 0x09, 0x20,
+  0x1d, 0xff, 0x0a, 0x0b, 0x80, 0x84, 0x80, 0x00, 0x00, 0x01, 0x0e, 0x4c,
+  0x10, 0x80, 0x00, 0x00, 0x01, 0x0d, 0xc1, 0xd8, 0xd4, 0x47, 0xd0, 0xaa,
+  0xc4, 0x45, 0xaa, 0xb8, 0x01, 0xdf, 0x4c, 0xc1, 0x3a, 0xfa, 0x13, 0x67,
+  0x6a, 0xed, 0x2c, 0x67, 0xbc, 0xef, 0xdc, 0x69, 0x99, 0xf8, 0x53, 0x97,
+  0x01, 0xdc, 0xbe, 0xd8, 0x3b, 0xa2, 0x96, 0xe8, 0xa1, 0x94, 0x02, 0x57,
+  0x82, 0x82, 0xd6, 0x14, 0xc7, 0x61, 0x5a, 0x00, 0x22, 0x81, 0x73, 0x33,
+  0x20, 0x00, 0xa0, 0x09, 0xc0, 0x50, 0xfa, 0x06, 0xce, 0x35, 0x91, 0x8d,
+  0x19, 0x0f, 0x07, 0x1e, 0x84, 0x5b, 0x3a, 0x29, 0x03, 0xad, 0x8f, 0x8a,
+  0xd2, 0x22, 0xf0, 0xfc, 0x28, 0xd2, 0x95, 0x4a, 0xfe, 0x74, 0x4b, 0x23,
+  0xe7, 0xd4, 0x12, 0x1f, 0x37, 0x01, 0x88, 0xf8, 0xa4, 0x09, 0x76, 0x51,
+  0xae, 0xf4, 0x23, 0x6d, 0x29, 0x8c, 0x54, 0xaa, 0x2c, 0x68, 0x10, 0x7e,
+  0x71, 0xbf, 0x10, 0xb4, 0x77, 0x97, 0x8b, 0xa1, 0x54, 0xd1, 0xda, 0xb5,
+  0x5f, 0x61, 0xf0, 0x64, 0x64, 0x29, 0x25, 0x7d, 0x42, 0xe0, 0xff, 0x2a,
+  0x83, 0x29, 0x61, 0xfc, 0xee, 0xe5, 0x11, 0x04, 0xc0, 0x43, 0xc0, 0xc4,
+  0x0e, 0x18, 0x43, 0xb6, 0x08, 0x55, 0xa0, 0x22, 0xf4, 0x58, 0x01, 0xc6,
+  0x43, 0x0d, 0xba, 0x04, 0x3e, 0x8e, 0x5f, 0xc1, 0x11, 0x56, 0xef, 0xd7,
+  0x78, 0xe2, 0xd2, 0xdb, 0x84, 0x16, 0x76, 0xc6, 0x92, 0x15, 0xf6, 0xc2,
+  0x76, 0x2f, 0xd2, 0xef, 0x46, 0x02, 0x60, 0x24, 0xda, 0x16, 0x48, 0x95,
+  0xc4, 0x87, 0x81, 0xa7, 0xdd, 0xd7, 0x77, 0x56, 0xb7, 0xb5, 0x28, 0x9d,
+  0x6b, 0x7b, 0xd6, 0x8b, 0x80, 0x42, 0x28, 0xb0, 0x28, 0x82, 0x50, 0x04,
+  0x65, 0x1a, 0xc3, 0x79, 0x74, 0x6c, 0x3e, 0x9e, 0x69, 0x0e, 0xc1, 0xed,
+  0x8d, 0xe9, 0xf0, 0xf4, 0xf8, 0xde, 0xc1, 0x62, 0x1d, 0x1f, 0x4a, 0x5d,
+  0x02, 0x11, 0xfa, 0xd8, 0x10, 0xb8, 0xa0, 0xc5, 0xf5, 0x85, 0xd1, 0x19,
+  0x14, 0x06, 0x21, 0x5b, 0xa5, 0x37, 0xcd, 0xf2, 0xbc, 0x3b, 0x7f, 0xe3,
+  0x1c, 0x62, 0x51, 0x4b, 0x09, 0x2e, 0x48, 0x1f, 0x4e, 0x19, 0xe4, 0x90,
+  0x22, 0x81, 0xf4, 0xf7, 0x16, 0x4f, 0xe5, 0x97, 0x12, 0x9b, 0x92, 0x6e,
+  0xcc, 0x61, 0xd6, 0x4a, 0x59, 0x66, 0x7d, 0xc2, 0x1d, 0x33, 0x7e, 0x62,
+  0x29, 0x81, 0x80, 0xb7, 0xa4, 0xcb, 0xc4, 0xc3, 0x9b, 0x1d, 0x2b, 0x00,
+  0xc9, 0x78, 0x82, 0xef, 0xd7, 0xa5, 0xad, 0x08, 0x18, 0x7c, 0x97, 0x61,
+  0x3e, 0xaf, 0x4e, 0x21, 0xd6, 0x5a, 0x35, 0xd6, 0xf9, 0xdf, 0x89, 0xe9,
+  0x09, 0x99, 0x3e, 0x53, 0x81, 0x80, 0x21, 0xd9, 0x44, 0x7f, 0xb9, 0xe7,
+  0x7d, 0x1d, 0xa6, 0xd4, 0xb6, 0x60, 0x71, 0xa3, 0x87, 0x13, 0x40, 0x7a,
+  0x50, 0xac, 0x02, 0x87, 0xe3, 0x7a, 0xab, 0xce, 0x11, 0xed, 0x51, 0x97,
+  0xc5, 0xf0, 0x33, 0xf5, 0x3b, 0x7e, 0x05, 0xda, 0x4d, 0x29, 0x23, 0xa7,
+  0xca, 0x43, 0x0e, 0x72, 0xf0, 0x96, 0xe9, 0x95, 0x4a, 0x32, 0xb0, 0xc4,
+  0xe5, 0x65, 0x73, 0xc3, 0x30, 0xea, 0xfb, 0x93, 0x04, 0x64, 0x48, 0x48,
+  0x20, 0x1a, 0x8c, 0xde, 0xb0, 0x24, 0x7d, 0xd6, 0xe9, 0x5b, 0xb9, 0x0b,
+  0x18, 0xb9, 0xc4, 0x4a, 0x81, 0xaa, 0xfb, 0x6b, 0x2f, 0xe6, 0x77, 0x00,
+  0x17, 0xa8, 0x1f, 0x7f, 0x8b, 0xcd, 0xaf, 0xb5, 0xc1, 0x26, 0x99, 0x3f,
+  0x74, 0xd9, 0x69, 0x4c, 0x4c, 0xe5, 0x8a, 0x51, 0x3b, 0x47, 0x18, 0x33,
+  0x1a, 0xc5, 0xc3, 0xe1, 0xeb, 0xc7, 0x80, 0xa4, 0xb3, 0x5f, 0x22, 0x64,
+  0xcc, 0x97, 0xcb, 0xdb, 0xe5, 0xc9, 0x09, 0x89, 0x65, 0xfd, 0x61, 0x76,
+  0xc3, 0xf7, 0xfe, 0x7d, 0xe1, 0x70, 0x07, 0x9a, 0x17, 0x95, 0x08, 0x4d,
+  0xec, 0xfb, 0x38, 0x61, 0x06, 0x1e, 0x96, 0x91, 0x19, 0x42, 0x88, 0xf1,
+  0x45, 0x04, 0x69, 0x63, 0x1c, 0x99, 0xf8, 0x26, 0xf4, 0xfc, 0xf0, 0xeb,
+  0x48, 0x06, 0x9d, 0xef, 0x46, 0x72, 0x41, 0xa9, 0xa5, 0xb8, 0x4a, 0xf0,
+  0xd3, 0x82, 0x65, 0x88, 0x98, 0x40, 0x97, 0x4a, 0x95, 0x10, 0x52, 0xca,
+  0x47, 0xec, 0x14, 0x75, 0x86, 0xd5, 0x7d, 0xf7, 0xda, 0xa5, 0x09, 0xc6,
+  0x50, 0x02, 0x8f, 0xd7, 0x51, 0x42, 0x43, 0x60, 0x27, 0x67, 0xa0, 0xd6,
+  0xd8, 0xcf, 0x58, 0xc5, 0x13, 0x27, 0xa2, 0x4e, 0x4f, 0xc3, 0xc2, 0x50,
+  0xcb, 0x8d, 0x00, 0x53, 0x87, 0x5a, 0x6b, 0x4d, 0xb4, 0x07, 0x0b, 0x40,
+  0xb3, 0xba, 0xc3, 0x14, 0xb8, 0x75, 0xda, 0x84, 0x50, 0x96, 0x12, 0xc6,
+  0xd1, 0x00, 0xa5, 0xa3, 0x4c, 0x11, 0x45, 0x02, 0xc7, 0x2f, 0xe2, 0x8f,
+  0xb7, 0xe9, 0xff, 0xe2, 0x48, 0x8b, 0x28, 0x1c, 0x38, 0x8c, 0x41, 0xc9,
+  0xd0, 0xfa, 0x13, 0x4f, 0xfd, 0x6b, 0x72, 0xa5, 0x0e, 0xd7, 0x2f, 0x2b,
+  0xee, 0x37, 0xe6, 0xb0, 0x41, 0x4d, 0x45, 0x83, 0x88, 0x6d, 0x14, 0x6d,
+  0xa6, 0xb1, 0x59, 0x7d, 0x7e, 0xa7, 0x8d, 0x48, 0xc3, 0x4c, 0x80, 0x91,
+  0xf0, 0x4d, 0xfc, 0xaf, 0xe6, 0xae, 0x9a, 0x24, 0xca, 0x73, 0xc4, 0x13,
+  0xf8, 0x28, 0xd2, 0xbf, 0xdf, 0xc4, 0xd0, 0x4e, 0xf4, 0x3e, 0x2c, 0x60,
+  0x6a, 0xd4, 0x6e, 0x44, 0x8a, 0xae, 0x09, 0x37, 0xb1, 0x98, 0xaf, 0x69,
+  0xf0, 0xee, 0x6f, 0x0a, 0x55, 0x6d, 0x12, 0x7c, 0xf0, 0x08, 0x78, 0xd2,
+  0x98, 0x7c, 0xdf, 0xd7, 0xa0, 0x0d, 0xf3, 0x52, 0x65, 0xf6, 0xb9, 0xfe,
+  0xf3, 0x73, 0x4c, 0xe2, 0x3a, 0x27, 0x64, 0x00, 0x28, 0x54, 0x2d, 0x4a,
+  0x59, 0x42, 0x43, 0xea, 0x26, 0xeb, 0x13, 0x2a, 0x5a, 0x9a, 0x35, 0xe9,
+  0xe3, 0xe0, 0x3d, 0x84, 0xf0, 0x12, 0xbe, 0x84, 0x3f, 0x1c, 0xe6, 0x06,
+  0xab, 0x30, 0x0d, 0xa3, 0xba, 0xe4, 0x24, 0xe0, 0x6f, 0x5c, 0xab, 0x43,
+  0x9a, 0xf6, 0xf4, 0xd9, 0x74, 0x7e, 0x2c, 0x63, 0xf3, 0xd2, 0x17, 0x0b,
+  0x57, 0xda, 0x1d, 0xd0, 0x47, 0x52, 0xc7, 0xc9, 0xb8, 0x14, 0x12, 0x23,
+  0xc1, 0x23, 0x9b, 0x78, 0x51, 0x81, 0x7b, 0x66, 0x48, 0xbb, 0xc8, 0x7a,
+  0x67, 0x84, 0x0a, 0xff, 0x82, 0xe9, 0x7e, 0xea, 0x5f, 0x5b, 0x94, 0xd6,
+  0x24, 0x48, 0x3b, 0xa6, 0x25, 0x29, 0xd1, 0x92, 0x12, 0x9a, 0x5f, 0x84,
+  0x3e, 0xb4, 0xe4, 0x3f, 0x15, 0xad, 0xe9, 0xec, 0xbc, 0x10, 0x7d, 0xc9,
+  0xcd, 0xeb, 0x71, 0xd3, 0x79, 0x1a, 0xc2, 0xf5, 0x0d, 0x31, 0xac, 0x6a,
+  0xac, 0xbc, 0x7f, 0x67, 0x43, 0x78, 0xc5, 0x23, 0x97, 0x56, 0x88, 0x3c,
+  0xb0, 0x8e, 0x2c, 0x8a, 0x2b, 0x63, 0xfe, 0xb2, 0xaa, 0xb1, 0x71, 0x72,
+  0x74, 0x41, 0xc3, 0x78, 0x0c, 0x5f, 0x92, 0x8d, 0x64, 0xe0, 0xf8, 0xde,
+  0x09, 0x8f, 0xcd, 0x39, 0x45, 0x5a, 0x5d, 0x12, 0x6b, 0x26, 0xad, 0xfe,
+  0xc0, 0x51, 0x1e, 0x00, 0xe9, 0x36, 0xf1, 0xb6, 0x74, 0x7b, 0x67, 0x6e,
+  0xe2, 0xe4, 0xf4, 0x8e, 0x40, 0x87, 0xc6, 0x14, 0xcc, 0xa8, 0x25, 0x37,
+  0x72, 0x0c, 0xc0, 0xf4, 0xff, 0xf4, 0x7d, 0xdc, 0xa8, 0xda, 0x68, 0xa5,
+  0xbf, 0x04, 0xa3, 0x2c, 0x9f, 0xc7, 0x0a, 0x7c, 0x37, 0x86, 0xe7, 0x76,
+  0x4e, 0x50, 0x79, 0xa5, 0xd1, 0x5f, 0x2e, 0x6f, 0x9a, 0x5c, 0x75, 0x73,
+  0xd3, 0x7a, 0x10, 0x69, 0x45, 0xf1, 0x99, 0xca, 0x04, 0x24, 0x0a, 0x76,
+  0xf5, 0xb9, 0xf7, 0xca, 0xf3, 0xfe, 0xde, 0x28, 0x70, 0x47, 0x3c, 0x35,
+  0x17, 0x70, 0x21, 0x42, 0x32, 0x81, 0xfb, 0x3d, 0xc8, 0xf0, 0x35, 0xfe,
+  0xe7, 0xee, 0x1b, 0x1e, 0xdd, 0xce, 0x19, 0xa2, 0x95, 0x95, 0x43, 0x2f,
+  0xb2, 0x26, 0xcc, 0xbb, 0xb7, 0x8b, 0x8b, 0xff, 0x1c, 0xeb, 0x82, 0xa9,
+  0x4f, 0x25, 0x58, 0xfa, 0x41, 0x22, 0x4a, 0xcb, 0x38, 0xc4, 0xff, 0x12,
+  0x0d, 0xf7, 0x3b, 0xed, 0x0c, 0x7e, 0x29, 0xd3, 0x19, 0xe2, 0x2c, 0xff,
+  0x8e, 0xbf, 0xe1, 0x1b, 0xc9, 0x6f, 0xac, 0x51, 0x97, 0x49, 0x68, 0x4d,
+  0x20, 0x27, 0x3f, 0x11, 0xfe, 0x1e, 0x7f, 0xef, 0xda, 0x76, 0xba, 0xba,
+  0xf2, 0xdb, 0x60, 0x36, 0x9a, 0xa3, 0x28, 0x89, 0xc8, 0x64, 0xb0, 0x90,
+  0x79, 0xcb, 0x9d, 0x45, 0xcc, 0xdd, 0x6d, 0xf0, 0xd5, 0xb5, 0x8a, 0x64,
+  0x51, 0x96, 0xcb, 0x12, 0x70, 0x0a, 0xca, 0x69, 0x34, 0x20, 0x43, 0x31,
+  0x3c, 0xba, 0xb2, 0x80, 0xe1, 0xb2, 0x65, 0x79, 0x6f, 0x4e, 0x6e, 0x92,
+  0x4b, 0xbf, 0x80, 0x2a, 0xb7, 0x97, 0x7f, 0xc9, 0xf5, 0xbc, 0xef, 0x1e,
+  0x7f, 0xc9, 0xb6, 0x3d, 0x86, 0x4c, 0x89, 0x62, 0xac, 0x2b, 0xd0, 0x26,
+  0x9d, 0xab, 0xeb, 0xfb, 0x5d, 0x4b, 0x6c, 0xe5, 0x58, 0x29, 0xb3, 0x4a,
+  0x09, 0xed, 0x17, 0xf1, 0x00, 0xbb, 0x5c, 0x17, 0xc4, 0x56, 0x3b, 0xfc,
+  0x13, 0x08, 0xc5, 0xcf, 0xc4, 0x14, 0x5f, 0xe2, 0xf8, 0xa5, 0xe2, 0xde,
+  0x2f, 0x85, 0xde, 0xf7, 0xf7, 0x4d, 0xcd, 0x7b, 0xf2, 0xb6, 0x8b, 0x72,
+  0x03, 0x6b, 0x2c, 0x7f, 0xde, 0x40, 0xf4, 0x76, 0x52, 0x2b, 0x61, 0x2d,
+  0x72, 0xa2, 0x21, 0x0c, 0x1b, 0x44, 0x6c, 0x40, 0x04, 0xbc, 0x5e, 0xff,
+  0xcb, 0xb6, 0x65, 0x99, 0xc6, 0xdb, 0xf7, 0x6f, 0xbc, 0x75, 0xd6, 0xcb,
+  0x79, 0x6d, 0xd6, 0x94, 0xbd, 0xb7, 0x47, 0x89, 0xc6, 0xf6, 0xf0, 0xab,
+  0x67, 0x60, 0x37, 0x32, 0x7d, 0x0f, 0x31, 0x08, 0xe2, 0x4e, 0x11, 0x0d,
+  0x64, 0x1e, 0x66, 0xc6, 0xc6, 0xc5, 0x34, 0x56, 0xf8, 0xbf, 0x12, 0x83,
+  0x7a, 0x75, 0xe0, 0x67, 0xae, 0x7b, 0x7e, 0xfb, 0xb6, 0x33, 0x38, 0xaa,
+  0xea, 0x98, 0x9b, 0xfd, 0x36, 0x0d, 0x7e, 0x0f, 0xd4, 0xf9, 0x56, 0x6a,
+  0xd5, 0x40, 0xb4, 0x38, 0xae, 0x6a, 0x7a, 0xc5, 0x40, 0x2c, 0x87, 0x72,
+  0x80, 0x3e, 0x20, 0xf3, 0x48, 0xed, 0xbd, 0xb8, 0x13, 0xdf, 0xb7, 0xae,
+  0x6a, 0xe6, 0x62, 0x6e, 0x73, 0x4c, 0xf0, 0x06, 0xba, 0x6c, 0xb2, 0xed,
+  0xb6, 0x83, 0x32, 0x77, 0x63, 0xff, 0x84, 0x7e, 0xca, 0x91, 0xd7, 0x14,
+  0xc7, 0xae, 0x12, 0x91, 0x49, 0xb6, 0x32, 0x92, 0x97, 0x5e, 0x39, 0x5a,
+  0x71, 0x86, 0xdc, 0x92, 0xbb, 0x47, 0x8c, 0x3e, 0x24, 0xfc, 0x05, 0xf2,
+  0x38, 0x7b, 0xdd, 0x4c, 0xec, 0x52, 0x8f, 0x80, 0x57, 0xd1, 0x52, 0x6b,
+  0x0a, 0xb9, 0x81, 0xfd, 0x6b, 0xd2, 0x43, 0x58, 0x2c, 0x2a, 0xb8, 0x3d,
+  0x66, 0xb0, 0x61, 0x9b, 0x3e, 0x7a, 0xc9, 0x38, 0x62, 0xc8, 0x6b, 0x4f,
+  0xa0, 0xe3, 0xed, 0x13, 0x7b, 0xd6, 0x7c, 0xbb, 0x35, 0xaf, 0x81, 0xed,
+  0x88, 0x91, 0x35, 0x2a, 0x5c, 0x5f, 0x47, 0xa7, 0x2f, 0x6f, 0xf5, 0x23,
+  0x38, 0x20, 0x87, 0x5f, 0x65, 0x81, 0xfa, 0x44, 0x88, 0xd4, 0x96, 0x5e,
+  0xc2, 0x84, 0xca, 0x39, 0x20, 0x28, 0x93, 0x94, 0x06, 0x4f, 0xc5, 0x41,
+  0xff, 0x4e, 0x9d, 0xe6, 0xdb, 0x29, 0x50, 0xaf, 0x46, 0x49, 0x00, 0x24,
+  0x04, 0xf2, 0xcd, 0x13, 0x84, 0x82, 0xa3, 0xc9, 0x21, 0x36, 0x26, 0x6f,
+  0xad, 0xff, 0xb7, 0x6f, 0xf2, 0x6e, 0x15, 0x83, 0xa8, 0xb5, 0x2e, 0x89,
+  0xfb, 0xca, 0xfe, 0xfa, 0x80, 0x2d, 0xc7, 0x43, 0xfe, 0xbe, 0xd5, 0x1b,
+  0x8a, 0x4d, 0x08, 0xed, 0x55, 0x2c, 0x83, 0xc1, 0xe5, 0x7b, 0xc5, 0x1b,
+  0x5d, 0xdd, 0xb7, 0x53, 0xf1, 0x3b, 0xd7, 0x7d, 0xed, 0xe6, 0x11, 0xbe,
+  0x75, 0xb5, 0xb4, 0x22, 0x42, 0x53, 0x10, 0x81, 0x34, 0x7b, 0x81, 0x3c,
+  0x94, 0x13, 0xc7, 0x2c, 0xed, 0xa1, 0xa3, 0x0a, 0x15, 0x7a, 0xb0, 0x26,
+  0x69, 0xe0, 0x45, 0x19, 0xb1, 0x9c, 0x88, 0x9d, 0xe1, 0x61, 0x20, 0xee,
+  0x3f, 0xe6, 0xa3, 0x8c, 0x61, 0x85, 0xa7, 0x28, 0xd2, 0x09, 0x7b, 0x69,
+  0xb0, 0x95, 0x37, 0xd8, 0x96, 0x3c, 0xcc, 0x2c, 0x90, 0x83, 0x28, 0x8c,
+  0x8b, 0x3b, 0xfe, 0xb7, 0xb5, 0x19, 0x15, 0x5e, 0xcf, 0x5f, 0xaf, 0x8c,
+  0x76, 0x95, 0x02, 0x97, 0xe9, 0xac, 0x02, 0xb2, 0xee, 0x82, 0xe7, 0x16,
+  0xca, 0x5b, 0x08, 0x22, 0xc6, 0x4e, 0xd2, 0xab, 0x10, 0x0f, 0x68, 0x5c,
+  0xc2, 0x3d, 0x16, 0xf8, 0x74, 0x11, 0xd6, 0x4c, 0x65, 0xe1, 0x26, 0x9a,
+  0x2d, 0xb0, 0x20, 0x66, 0xd2, 0xed, 0x60, 0xf4, 0xd1, 0xc2, 0x7d, 0x44,
+  0xd7, 0xbd, 0x45, 0x36, 0x7b, 0xdc, 0xef, 0x87, 0xba, 0xbe, 0x16, 0x40,
+  0x13, 0xa3, 0x3a, 0x6e, 0x12, 0xc0, 0xa3, 0xe2, 0x01, 0xfa, 0xde, 0xe5,
+  0x75, 0xb9, 0x8a, 0x12, 0x19, 0x44, 0x8a, 0x12, 0xc9, 0x51, 0x84, 0xa5,
+  0xcb, 0xc0, 0xec, 0xee, 0xd3, 0xaf, 0x34, 0xa4, 0x91, 0x34, 0x52, 0x01,
+  0xeb, 0x00, 0x8e, 0x62, 0x71, 0x6f, 0x32, 0x80, 0x3e, 0xdc, 0x17, 0x3b,
+  0x7d, 0x4b, 0x50, 0x4e, 0x81, 0x90, 0x98, 0xde, 0x4c, 0xc6, 0x90, 0x09,
+  0x6e, 0xbb, 0x4e, 0x1f, 0x87, 0x0b, 0x2e, 0x1f, 0xed, 0x42, 0x0e, 0x2d,
+  0x04, 0x24, 0xb0, 0x40, 0xc3, 0xde, 0x12, 0x24, 0x15, 0x2a, 0x68, 0x09,
+  0xf8, 0xf8, 0x71, 0xf1, 0x85, 0x16, 0x12, 0xa4, 0x58, 0xc1, 0xa6, 0x19,
+  0x1a, 0x68, 0x9d, 0xa1, 0x94, 0x32, 0x08, 0x11, 0x51, 0x14, 0xb1, 0xa4,
+  0x24, 0x0c, 0xdd, 0x2c, 0x04, 0x20, 0x19, 0x72, 0x35, 0x60, 0xda, 0x79,
+  0x84, 0x11, 0x05, 0xf0, 0xe6, 0x52, 0xf8, 0x9f, 0x3a, 0xd0, 0x9e, 0xe1,
+  0xe4, 0x50, 0x99, 0x8c, 0xb4, 0xba, 0x33, 0xc7, 0xc0, 0x33, 0x00, 0x76,
+  0x0e, 0x10, 0x19, 0x31, 0x23, 0x8d, 0x34, 0x96, 0xdf, 0xd8, 0x6b, 0x24,
+  0x65, 0x3f, 0x4d, 0x1c, 0x95, 0x5a, 0x79, 0xc2, 0xe5, 0xb2, 0x36, 0xc5,
+  0xa6, 0x8b, 0x28, 0x03, 0x95, 0xda, 0x51, 0xa3, 0x96, 0x00, 0xf9, 0xe0,
+  0xbc, 0x7e, 0xc5, 0xab, 0x8a, 0x64, 0xa5, 0x7c, 0xf3, 0x65, 0x98, 0xc1,
+  0x92, 0x4b, 0x9f, 0xa6, 0x87, 0x8a, 0x35, 0xa5, 0x35, 0x14, 0x93, 0x26,
+  0x05, 0xfe, 0xec, 0x4b, 0xdc, 0xea, 0xd6, 0xb6, 0x54, 0x23, 0x2c, 0x24,
+  0x72, 0xfe, 0x71, 0x90, 0x31, 0xfd, 0x00, 0x84, 0xc2, 0xc8, 0x63, 0x8a,
+  0x88, 0xcb, 0x27, 0xf0, 0x7e, 0x05, 0x1e, 0xf3, 0xb4, 0xfa, 0x7e, 0xe1,
+  0x77, 0x67, 0xe3, 0xa6, 0x28, 0x11, 0x48, 0xe3, 0xbd, 0x00, 0x25, 0x7b,
+  0x30, 0xcb, 0xec, 0x27, 0xc1, 0x61, 0x28, 0x1c, 0x56, 0x66, 0x12, 0x10,
+  0xba, 0x08, 0x03, 0x91, 0x43, 0xd3, 0x6d, 0x2a, 0xcd, 0x2a, 0x58, 0x64,
+  0x68, 0x24, 0x4f, 0xc7, 0x47, 0xf1, 0x7c, 0x69, 0x9a, 0x14, 0x64, 0x5e,
+  0x53, 0xbd, 0x74, 0x85, 0xa9, 0x29, 0xa6, 0x7e, 0xae, 0x39, 0x35, 0x40,
+  0x8c, 0xe5, 0x59, 0x30, 0x5c, 0x7f, 0x46, 0xa1, 0x37, 0x29, 0x04, 0x07,
+  0xc5, 0xf1, 0xcf, 0x30, 0x0f, 0x89, 0x87, 0x31, 0x4f, 0x33, 0xa2, 0x04,
+  0xb2, 0x9b, 0x30, 0x55, 0x14, 0xb1, 0x82, 0xac, 0x3e, 0xb8, 0x1a, 0xb9,
+  0xca, 0xa5, 0xe9, 0x4b, 0x28, 0x77, 0x3a, 0x63, 0xe8, 0xad, 0xbe, 0x98,
+  0xd2, 0x2d, 0x32, 0xc6, 0x30, 0x82, 0x0e, 0xc1, 0x8f, 0xb9, 0x70, 0x13,
+  0xca, 0x42, 0xd8, 0x07, 0x0f, 0x23, 0xd9, 0x5a, 0xed, 0x92, 0x9b, 0x38,
+  0xc5, 0xa0, 0x65, 0xb1, 0x08, 0x90, 0xcb, 0x61, 0x2c, 0x05, 0x1f, 0xa6,
+  0x2a, 0x55, 0x24, 0x2f, 0x40, 0xc2, 0x4f, 0x5c, 0xb3, 0xcc, 0xd5, 0xfb,
+  0x57, 0xda, 0x92, 0x08, 0xed, 0x0e, 0x56, 0x4e, 0x55, 0x6d, 0xfc, 0xc3,
+  0x66, 0x95, 0x9c, 0x81, 0x27, 0xe5, 0x6c, 0x9d, 0x42, 0x94, 0x38, 0x68,
+  0x48, 0x22, 0x58, 0x48, 0x86, 0xfa, 0x83, 0x66, 0xb6, 0xbd, 0xca, 0x0d,
+  0x0c, 0x72, 0x68, 0xd6, 0x07, 0xe4, 0xcc, 0x84, 0x76, 0x85, 0x0f, 0x9c,
+  0x7a, 0x2d, 0x6a, 0xed, 0x3e, 0x34, 0xda, 0x2b, 0xf2, 0xf4, 0x67, 0xa6,
+  0x00, 0xd1, 0x64, 0x5e, 0x45, 0x12, 0x82, 0x2d, 0x95, 0x2f, 0xac, 0x58,
+  0xf9, 0xea, 0x65, 0x4b, 0x27, 0xdb, 0x3d, 0xdd, 0x8d, 0x8a, 0x5e, 0xda,
+  0xb5, 0xd6, 0x05, 0x88, 0x64, 0x1c, 0x84, 0x7f, 0x69, 0x12, 0x11, 0x2f,
+  0x80, 0x7d, 0x12, 0xbb, 0xaa, 0x50, 0x71, 0x9b, 0x4c, 0xba, 0xdf, 0xaa,
+  0x5e, 0xf6, 0x34, 0x1f, 0xef, 0xa5, 0x4f, 0xfa, 0x95, 0x34, 0xef, 0x84,
+  0xed, 0xd9, 0x2f, 0x1c, 0xcd, 0xc6, 0x5e, 0x90, 0xfb, 0x13, 0xf3, 0xf0,
+  0xfa, 0x3f, 0x7f, 0x77, 0xca, 0x76, 0x12, 0x9a, 0x3c, 0x92, 0x86, 0xed,
+  0xcb, 0xe0, 0x22, 0x84, 0x86, 0x5d, 0x02, 0xf2, 0xfa, 0x37, 0x83, 0x64,
+  0xad, 0x1f, 0x0d, 0xdb, 0x95, 0x8f, 0x3d, 0x70, 0xbe, 0xff, 0xfb, 0x5d,
+  0xfd, 0xbe, 0x1b, 0x92, 0xcc, 0xb6, 0x95, 0xef, 0x63, 0x8a, 0x72, 0xc8,
+  0x4e, 0x88, 0xf9, 0xa3, 0xb9, 0x07, 0x9c, 0xb3, 0x3f, 0xad, 0xca, 0x84,
+  0xb2, 0x06, 0x42, 0x28, 0xb7, 0xc4, 0xf1, 0x07, 0x9c, 0xcf, 0x8e, 0xe7,
+  0xd9, 0xc9, 0xa8, 0xf8, 0x9e, 0x1b, 0x96, 0x48, 0xf6, 0xa9, 0x55, 0x5d,
+  0x6d, 0xff, 0xff, 0xed, 0x49, 0xc8, 0x82, 0x8e, 0x33, 0x09, 0x78, 0x68,
+  0x44, 0x2c, 0xd9, 0xbf, 0xd4, 0x22, 0x03, 0xad, 0x38, 0x01, 0x7b, 0xeb,
+  0x1b, 0x8b, 0x6c, 0x94, 0xda, 0x81, 0x6e, 0xd8, 0x6a, 0x26, 0x02, 0x28,
+  0xa3, 0x2f, 0xa8, 0x0f, 0xef, 0x0d, 0xbc, 0xb9, 0xa2, 0x57, 0xb2, 0x72,
+  0x28, 0x81, 0x9b, 0x5d, 0x54, 0x86, 0x7b, 0xf9, 0xed, 0x13, 0xe1, 0x8c,
+  0xa4, 0x32, 0x35, 0xe4, 0x8e, 0x01, 0xe1, 0xdd, 0x71, 0xc5, 0xfe, 0x50,
+  0x53, 0xdf, 0xef, 0x6b, 0x69, 0x81, 0x35, 0x5a, 0x65, 0x16, 0x87, 0xce,
+  0x42, 0x86, 0x32, 0xd4, 0x48, 0x97, 0x3f, 0x10, 0x39, 0xa3, 0xf6, 0x03,
+  0xc1, 0xb2, 0xe7, 0xe3, 0xed, 0xae, 0x92, 0x06, 0xca, 0xd0, 0xd0, 0x96,
+  0x51, 0xd2, 0x4b, 0x9f, 0xef, 0x5a, 0xdc, 0x66, 0x2b, 0x56, 0xa3, 0x5f,
+  0xe3, 0x4b, 0x67, 0x39, 0x09, 0x6f, 0x27, 0x68, 0xd0, 0x75, 0x66, 0xf3,
+  0x5c, 0x7c, 0x99, 0x97, 0xbe, 0x95, 0xb7, 0x22, 0xde, 0x54, 0x77, 0x8e,
+  0x97, 0x05, 0x21, 0xa4, 0x00, 0x9a, 0x1d, 0xcc, 0xf5, 0x5e, 0xc6, 0xcf,
+  0x48, 0x84, 0xab, 0x80, 0xe4, 0x3d, 0x25, 0xc0, 0x88, 0xc7, 0x62, 0xce,
+  0x40, 0x32, 0x45, 0xc4, 0x89, 0x44, 0x64, 0xeb, 0x20, 0xe7, 0xba, 0x5a,
+  0x97, 0xe7, 0xb1, 0x1a, 0xa6, 0xeb, 0xe2, 0x4f, 0x30, 0x03, 0x60, 0xc2,
+  0x84, 0xcc, 0xf0, 0x0a, 0xa8, 0xb0, 0x97, 0x22, 0x48, 0x78, 0x40, 0x46,
+  0x9f, 0xc4, 0x83, 0xfe, 0x62, 0x7b, 0xfe, 0xbb, 0xfb, 0x3d, 0x36, 0x2a,
+  0xf5, 0xde, 0xb3, 0xbd, 0xf9, 0x4f, 0xcb, 0x1e, 0xbf, 0xcd, 0xe0, 0xef,
+  0x3f, 0x34, 0x9b, 0xf3, 0x96, 0xd1, 0x30, 0x84, 0x69, 0x8d, 0x00, 0xf3,
+  0x77, 0x1e, 0x06, 0x66, 0x09, 0x3d, 0xd2, 0xeb, 0x76, 0x2f, 0x96, 0xba,
+  0x56, 0x73, 0x18, 0x6b, 0x5b, 0x89, 0xef, 0x1e, 0x9f, 0x4e, 0x5c, 0x62,
+  0x73, 0xa5, 0x71, 0x7f, 0xa6, 0xb6, 0x27, 0x05, 0x89, 0xa6, 0x34, 0x6f,
+  0xb8, 0x6a, 0x5c, 0xb3, 0x72, 0xe7, 0xc1, 0x2a, 0x9e, 0xc1, 0x3f, 0xbf,
+  0x7f, 0x71, 0x7f, 0x6f, 0x3b, 0xfd, 0xf7, 0xbf, 0xb1, 0xfd, 0xaa, 0xdf,
+  0x4b, 0x7f, 0x73, 0x6d, 0x7a, 0x2e, 0x2f, 0x95, 0xb6, 0xe6, 0xe5, 0xbc,
+  0x18, 0x58, 0xcc, 0x4c, 0x3b, 0x49, 0x10, 0x88, 0x3e, 0x20, 0xe6, 0xfe,
+  0x33, 0x5c, 0xc2, 0xc7, 0x6e, 0xbe, 0x7a, 0xbb, 0xaa, 0xd6, 0xd7, 0x13,
+  0x81, 0xfb, 0xfd, 0xfe, 0x76, 0xfa, 0x26, 0xb9, 0x01, 0x87, 0x3d, 0x8f,
+  0x5d, 0xe2, 0xa1, 0xc6, 0xa9, 0x2a, 0x26, 0xf7, 0x8f, 0x04, 0x23, 0x0c,
+  0xd5, 0x49, 0x36, 0x72, 0x25, 0x74, 0x12, 0x66, 0xee, 0x7b, 0xe6, 0x2f,
+  0xbf, 0x1f, 0xdf, 0xcc, 0xd2, 0x7d, 0xfd, 0xd5, 0x0b, 0x2d, 0xf7, 0xe3,
+  0x37, 0x5b, 0xf7, 0xe3, 0xf7, 0xe5, 0x09, 0xfe, 0x7b, 0xca, 0xc7, 0x68,
+  0xa7, 0xcb, 0x9d, 0xec, 0x38, 0xe4, 0x5e, 0xec, 0x02, 0x87, 0xd4, 0xc3,
+  0xd9, 0x51, 0x5f, 0x3b, 0xef, 0xed, 0x78, 0x14, 0xe9, 0xde, 0xb7, 0xff,
+  0x4f, 0x6d, 0x5d, 0x1c, 0x36, 0xed, 0xe5, 0x57, 0xe5, 0xd8, 0x39, 0x87,
+  0x8b, 0x8e, 0xc7, 0x57, 0x97, 0xdd, 0x8a, 0x76, 0x40, 0xba, 0x23, 0xee,
+  0x4d, 0x7c, 0x65, 0x72, 0xc8, 0x9d, 0x2f, 0xee, 0x36, 0xd4, 0xfb, 0xd6,
+  0xff, 0x49, 0x7a, 0x7f, 0x93, 0xfa, 0x7b, 0x3f, 0x5a, 0x79, 0xf9, 0x85,
+  0xd6, 0xeb, 0x7b, 0xf5, 0xd1, 0x64, 0x2e, 0x72, 0xf0, 0x98, 0x36, 0x03,
+  0xed, 0xfe, 0xc0, 0x4e, 0x06, 0xec, 0x09, 0x8b, 0x83, 0x8d, 0x7f, 0x7b,
+  0xa6, 0x75, 0xd7, 0x6e, 0xf3, 0xa8, 0xdb, 0xd2, 0xb6, 0x5b, 0xf8, 0xc5,
+  0xe3, 0x86, 0xd1, 0x5a, 0xf9, 0xe7, 0x4e, 0x7a, 0x69, 0xb1, 0x65, 0xc3,
+  0xc9, 0xb0, 0xfb, 0xbd, 0xea, 0xb7, 0x05, 0xd2, 0x73, 0x9a, 0x39, 0xdc,
+  0xde, 0x2a, 0xef, 0xdf, 0x8c, 0xc3, 0xcd, 0xdf, 0x85, 0xf4, 0x89, 0xae,
+  0xbc, 0xeb, 0xbf, 0xe7, 0xad, 0xe6, 0x9c, 0x6a, 0x60, 0xef, 0x5a, 0xff,
+  0x4e, 0x95, 0xa6, 0x96, 0x2f, 0x3f, 0x97, 0x2c, 0x4d, 0x96, 0xd6, 0xe7,
+  0xf4, 0x11, 0xe9, 0x5d, 0x5e, 0x28, 0x9c, 0x75, 0x55, 0xcc, 0xef, 0x65,
+  0x6a, 0x2b, 0x29, 0xb7, 0xff, 0x43, 0x9d, 0xcb, 0x91, 0x60, 0x58, 0x50,
+  0x79, 0xef, 0xb4, 0xd8, 0x7a, 0x1d, 0x94, 0x2a, 0xe4, 0x54, 0x74, 0x4c,
+  0xe5, 0x8c, 0xeb, 0xfb, 0x13, 0xfd, 0x4a, 0xc3, 0xee, 0x3f, 0x71, 0x33,
+  0xf9, 0xba, 0xa5, 0x17, 0xde, 0xcf, 0x45, 0x28, 0x75, 0xfe, 0xb8, 0x35,
+  0xa5, 0x79, 0x9b, 0x54, 0x37, 0xc8, 0xa7, 0x8b, 0x0d, 0x56, 0x92, 0x3f,
+  0xd8, 0xc8, 0x68, 0xf4, 0xe2, 0x1c, 0xbc, 0x4a, 0x5a, 0x9d, 0xea, 0x85,
+  0x57, 0xa1, 0x45, 0x58, 0xb9, 0xc8, 0x23, 0x7a, 0xc5, 0xfe, 0x2f, 0xbd,
+  0x9d, 0xe9, 0xbf, 0x19, 0x2a, 0x14, 0x0d, 0x78, 0xa4, 0x01, 0x03, 0x0e,
+  0x97, 0x91, 0x0c, 0x5c, 0x6b, 0x9d, 0x29, 0x50, 0x5e, 0xfc, 0x18, 0x51,
+  0x91, 0x9b, 0x03, 0x41, 0x1c, 0xb9, 0xe4, 0x42, 0x59, 0xcf, 0x3b, 0xd6,
+  0xe9, 0xe3, 0x19, 0xc0, 0x82, 0x28, 0x60, 0x3f, 0x1e, 0x32, 0xe0, 0x05,
+  0xca, 0x07, 0x5c, 0x8e, 0x37, 0xb0, 0xcb, 0x0d, 0xf1, 0x21, 0x91, 0x96,
+  0x41, 0xb4, 0x67, 0x56, 0xab, 0x7d, 0x75, 0x02, 0x86, 0x83, 0xbf, 0x39,
+  0x7b, 0x9d, 0x0c, 0x7c, 0xb0, 0x7d, 0x38, 0x4f, 0x9c, 0xf2, 0xe6, 0x52,
+  0xdd, 0x2f, 0xc4, 0x3d, 0x75, 0x5e, 0xbb, 0x53, 0x7a, 0x4f, 0xa6, 0xf5,
+  0x3a, 0xdb, 0xa1, 0xc0, 0x02, 0x62, 0xf2, 0xe6, 0x90, 0xca, 0x92, 0x3e,
+  0x9c, 0x9f, 0x72, 0x0b, 0x7f, 0x63, 0xa7, 0x5f, 0x07, 0x2a, 0x62, 0xa9,
+  0xe6, 0x22, 0x25, 0xb7, 0x96, 0xad, 0x51, 0x0b, 0xc6, 0x47, 0x9d, 0x76,
+  0xbc, 0x1f, 0x83, 0x2c, 0x65, 0xd9, 0x15, 0xfb, 0x7c, 0x85, 0x6a, 0xd6,
+  0xa6, 0xc8, 0x04, 0x5c, 0x25, 0xa1, 0x96, 0x91, 0xfa, 0x31, 0xaf, 0xd2,
+  0x0d, 0xdd, 0x7f, 0x8a, 0x09, 0x4f, 0xd9, 0x38, 0x3f, 0xb6, 0x1e, 0x52,
+  0xf3, 0x8a, 0x27, 0x25, 0xe2, 0x93, 0x08, 0x7c, 0x69, 0xa4, 0x39, 0xd6,
+  0x59, 0x07, 0x0c, 0xd2, 0x91, 0x9c, 0xf3, 0x04, 0xf7, 0x7b, 0x99, 0x72,
+  0x2c, 0x73, 0x7b, 0x6d, 0xe7, 0x7b, 0x1a, 0x8b, 0x71, 0x8e, 0x8c, 0xf2,
+  0xea, 0x3a, 0x52, 0xee, 0x44, 0x91, 0xf8, 0x26, 0xfc, 0xc2, 0xde, 0x9b,
+  0xd9, 0x6c, 0x3c, 0xc4, 0xaf, 0x75, 0x64, 0x3c, 0xa4, 0x27, 0xdc, 0xf8,
+  0x5f, 0x91, 0x28, 0x87, 0xaa, 0xce, 0xea, 0x6e, 0x5c, 0xa2, 0x00, 0x04,
+  0xcb, 0x4c, 0xe5, 0x99, 0xca, 0x00, 0x27, 0x34, 0x72, 0x5e, 0x0b, 0x4e,
+  0x03, 0xbd, 0x7d, 0x10, 0x11, 0x90, 0xca, 0x8c, 0xbf, 0x04, 0xbe, 0xb2,
+  0x5b, 0x65, 0xf1, 0x22, 0x83, 0xd1, 0x84, 0x3d, 0x16, 0x26, 0x30, 0xf1,
+  0x03, 0xe6, 0x64, 0xa8, 0xc8, 0x20, 0x3c, 0x3b, 0x01, 0x72, 0xbc, 0xea,
+  0xaa, 0x94, 0xf2, 0x80, 0x1d, 0x93, 0xc3, 0x3c, 0xbf, 0x4f, 0xce, 0x48,
+  0x8f, 0xb5, 0x38, 0x83, 0x5c, 0x4d, 0x7f, 0xd6, 0x68, 0x70, 0x0c, 0x90,
+  0x8c, 0x5d, 0x2b, 0xc2, 0x60, 0x51, 0xad, 0xfb, 0xfb, 0x22, 0x97, 0x02,
+  0xe6, 0xda, 0x4c, 0x7c, 0x46, 0xfe, 0x36, 0xec, 0x8b, 0x9a, 0x09, 0x48,
+  0x7d, 0x13, 0x2e, 0xd7, 0x1b, 0x3f, 0xcb, 0xe9, 0xa5, 0x90, 0xc4, 0x30,
+  0x0c, 0x92, 0x23, 0x22, 0x89, 0x91, 0x62, 0x73, 0xb0, 0x8f, 0x55, 0xd2,
+  0x9e, 0x1c, 0x3a, 0x22, 0x57, 0x87, 0xd9, 0x6e, 0x47, 0x93, 0xdd, 0xfd,
+  0x53, 0xa0, 0x5e, 0x40, 0x92, 0x04, 0x54, 0x57, 0x3a, 0x69, 0x45, 0x7f,
+  0xe7, 0x8d, 0x03, 0x8b, 0xff, 0xe2, 0x76, 0x13, 0xc1, 0x22, 0x2d, 0xf3,
+  0xa9, 0x8b, 0xb9, 0x63, 0x33, 0x56, 0xa3, 0x9f, 0x02, 0xf5, 0x3d, 0x6c,
+  0x89, 0xe3, 0xc9, 0x88, 0xc3, 0xa3, 0xf0, 0x5e, 0x05, 0xcd, 0x22, 0xeb,
+  0xe1, 0x0c, 0x36, 0x2c, 0xb6, 0x7b, 0x40, 0x30, 0xf3, 0xab, 0x2f, 0xe0,
+  0x4f, 0x03, 0x97, 0x2b, 0xd9, 0xfe, 0xfe, 0x23, 0xa7, 0x9f, 0x05, 0xdc,
+  0x66, 0x82, 0xd2, 0x54, 0x6d, 0x87, 0xfa, 0x0c, 0x8e, 0x48, 0x25, 0xde,
+  0xb0, 0x13, 0x77, 0x71, 0x55, 0x1e, 0x89, 0x63, 0x8d, 0xdb, 0x8a, 0x1c,
+  0x31, 0x0d, 0xa2, 0xfa, 0xa0, 0x5c, 0x50, 0x34, 0x11, 0x22, 0x61, 0x1e,
+  0xe0, 0x55, 0xfe, 0xd7, 0x5a, 0x5c, 0x91, 0x2b, 0xaf, 0x65, 0x91, 0x8c,
+  0xe7, 0x1c, 0x34, 0x88, 0x22, 0x63, 0x2c, 0x56, 0x70, 0x4e, 0x15, 0x02,
+  0x9b, 0x52, 0xff, 0x22, 0x14, 0xff, 0xb3, 0x05, 0x6e, 0xb7, 0xb6, 0x41,
+  0x11, 0x21, 0x44, 0xe4, 0xf6, 0x90, 0xf0, 0x4d, 0x79, 0xf3, 0x34, 0x32,
+  0xf2, 0x33, 0xb4, 0x94, 0x69, 0x49, 0xeb, 0xd3, 0x43, 0x7b, 0x07, 0x60,
+  0xd1, 0xdc, 0x81, 0x43, 0x1a, 0x68, 0x1c, 0x9f, 0x64, 0xe3, 0x1c, 0x8d,
+  0xaf, 0x40, 0x52, 0xd5, 0x28, 0x26, 0x69, 0x9c, 0x9a, 0x26, 0x80, 0x4e,
+  0xc8, 0x12, 0x24, 0xeb, 0x56, 0x54, 0xe9, 0xb5, 0x2a, 0x0c, 0x44, 0xd2,
+  0xd2, 0xe7, 0x56, 0xab, 0x97, 0x16, 0xac, 0x18, 0x41, 0x28, 0x4e, 0x11,
+  0x46, 0x03, 0x2c, 0x79, 0x8c, 0x3f, 0xcf, 0x77, 0x96, 0x84, 0xc9, 0x03,
+  0x26, 0xee, 0x7d, 0x3e, 0x15, 0xb6, 0x6b, 0x1d, 0x90, 0xdd, 0x87, 0x29,
+  0x88, 0x06, 0x69, 0x19, 0x8c, 0x27, 0xef, 0x9d, 0x1a, 0x9f, 0xca, 0x12,
+  0xff, 0x70, 0xee, 0x16, 0x10, 0x71, 0x95, 0x2a, 0x19, 0x79, 0x54, 0x3e,
+  0x8b, 0xa7, 0x49, 0xc4, 0xe8, 0x4f, 0x2a, 0xac, 0xe0, 0x04, 0x66, 0x28,
+  0xcf, 0x2a, 0x87, 0x64, 0x3e, 0x5d, 0x04, 0x3e, 0xc4, 0x89, 0x06, 0xc9,
+  0x64, 0x98, 0xa0, 0xe7, 0x07, 0x6f, 0x05, 0xb4, 0xfb, 0x66, 0x9e, 0x33,
+  0xb3, 0xbc, 0xe3, 0x10, 0x86, 0xa4, 0x10, 0xc9, 0xfd, 0x89, 0x97, 0x13,
+  0x9e, 0x74, 0x49, 0x61, 0x29, 0xca, 0x9b, 0x98, 0x1a, 0x10, 0x84, 0x89,
+  0xac, 0x02, 0xa3, 0xbf, 0xf2, 0x5f, 0xff, 0x8a, 0xfc, 0xf9, 0xab, 0xd6,
+  0x90, 0xe5, 0xe0, 0x58, 0x2f, 0xd1, 0xde, 0x44, 0xc0, 0x5a, 0x67, 0x52,
+  0x63, 0x28, 0x0a, 0x04, 0x63, 0xcf, 0xc1, 0x21, 0x38, 0xe9, 0x8b, 0xaf,
+  0x2e, 0x4e, 0x40, 0x81, 0xa0, 0x9a, 0x1b, 0x69, 0x3f, 0x67, 0x07, 0x28,
+  0x8c, 0x24, 0x24, 0x68, 0x63, 0x12, 0xee, 0xce, 0xdf, 0x8b, 0xeb, 0x4d,
+  0x45, 0x07, 0xe7, 0xea, 0x49, 0xbb, 0xd1, 0x36, 0x6e, 0xdd, 0xd7, 0xe0,
+  0xaf, 0x12, 0xf4, 0x08, 0x48, 0x9b, 0xd4, 0x26, 0x19, 0x6a, 0x5e, 0x7b,
+  0xce, 0xd7, 0xde, 0xdd, 0x6a, 0x1f, 0xc1, 0x9b, 0xbd, 0x13, 0xb6, 0x1d,
+  0x84, 0x15, 0x93, 0x3c, 0xf4, 0xf0, 0x06, 0xfa, 0xcd, 0xce, 0x89, 0x78,
+  0x76, 0xe7, 0x23, 0x72, 0xe7, 0xf1, 0x3e, 0x27, 0x86, 0x54, 0x75, 0xec,
+  0xef, 0x9e, 0x7b, 0xf2, 0x75, 0x57, 0x46, 0xc4, 0x2b, 0xf0, 0x55, 0x6c,
+  0x95, 0x71, 0xc4, 0xf7, 0xd6, 0x32, 0xee, 0xd9, 0xa5, 0x8c, 0x6d, 0xce,
+  0x40, 0x25, 0xc9, 0x01, 0x80, 0x7d, 0x75, 0xbf, 0x8a, 0xeb, 0xbc, 0x48,
+  0xe7, 0xa7, 0x2e, 0x58, 0x06, 0x2c, 0xd5, 0xee, 0x20, 0x90, 0x22, 0xa8,
+  0x4a, 0x41, 0x1e, 0xe7, 0x62, 0x9b, 0x13, 0x28, 0x02, 0x4d, 0xd6, 0xd0,
+  0xb1, 0x80, 0x96, 0x39, 0xa3, 0x4c, 0xa4, 0x7b, 0x83, 0xf7, 0x78, 0x9f,
+  0xbe, 0x0a, 0xf9, 0x98, 0xcb, 0x17, 0x7d, 0x46, 0xe4, 0x10, 0xbd, 0xa6,
+  0x89, 0xca, 0x00, 0x98, 0xd0, 0x2f, 0xaa, 0x84, 0x09, 0xc2, 0xac, 0xc5,
+  0xd6, 0xe9, 0x91, 0x1b, 0x5e, 0x49, 0x52, 0x73, 0x15, 0xf5, 0x6b, 0xf0,
+  0xdb, 0xd4, 0x32, 0x8d, 0x34, 0xb8, 0x5c, 0x25, 0xe4, 0x21, 0x7a, 0x7c,
+  0x44, 0x2e, 0x54, 0xe3, 0x5d, 0xf2, 0x59, 0xfd, 0x63, 0x6b, 0xb6, 0x2f,
+  0x3b, 0xdb, 0xb3, 0x39, 0x94, 0xe5, 0x26, 0x26, 0x79, 0x5a, 0x0c, 0x26,
+  0x12, 0xfc, 0x41, 0x57, 0x89, 0x63, 0x11, 0x0b, 0xc6, 0x46, 0x57, 0xa3,
+  0xb2, 0xa5, 0x2a, 0x5d, 0xf6, 0xfd, 0x7c, 0x73, 0xe2, 0xaf, 0x6f, 0x5b,
+  0xa4, 0xb3, 0x05, 0x1c, 0x7d, 0xc1, 0x89, 0xfa, 0xcd, 0x03, 0x29, 0xa0,
+  0x25, 0x18, 0xcd, 0xe1, 0xf1, 0xee, 0x5a, 0x21, 0xbf, 0x4a, 0xb8, 0x4c,
+  0x9c, 0x87, 0x21, 0x09, 0x19, 0xe4, 0xa5, 0xe2, 0x03, 0x50, 0x31, 0x34,
+  0x7c, 0x49, 0xbf, 0xe6, 0x56, 0x6c, 0xb6, 0xdf, 0x4e, 0xa6, 0x34, 0xd9,
+  0xd8, 0x90, 0x50, 0x26, 0x54, 0x11, 0x14, 0x08, 0x28, 0x1f, 0x05, 0x1b,
+  0xa6, 0x5d, 0x39, 0x42, 0x77, 0xb6, 0xc7, 0xc4, 0xfa, 0xb1, 0x43, 0x0a,
+  0x93, 0x86, 0xf9, 0xe0, 0xfe, 0xa9, 0x65, 0x99, 0xfe, 0xeb, 0x93, 0xe3,
+  0x61, 0xb2, 0x2b, 0x6c, 0xde, 0xd6, 0xc6, 0x02, 0xc5, 0xc1, 0x91, 0x53,
+  0x5e, 0xf4, 0xcb, 0xf9, 0x70, 0x03, 0xb0, 0xde, 0x85, 0x18, 0xc6, 0x4b,
+  0xd0, 0xe2, 0x7a, 0x6a, 0x28, 0xc3, 0xec, 0x45, 0xc4, 0xf1, 0x91, 0x4a,
+  0x44, 0x4c, 0x78, 0xe3, 0xa4, 0x47, 0xd8, 0x6a, 0x9a, 0xc8, 0x21, 0x67,
+  0x10, 0x11, 0x35, 0x36, 0x42, 0xa2, 0xde, 0x4d, 0xb0, 0xc3, 0xb2, 0x5d,
+  0x44, 0x27, 0x18, 0xbc, 0xd5, 0xbf, 0xd4, 0x9d, 0xe4, 0xb5, 0x50, 0x88,
+  0x3a, 0xf8, 0x30, 0x8f, 0x64, 0xed, 0xbb, 0x28, 0x9e, 0x78, 0x9e, 0x41,
+  0x6d, 0x98, 0x2f, 0x6c, 0x1c, 0xe9, 0xe0, 0x51, 0x93, 0x2a, 0xd2, 0xa7,
+  0xdc, 0xcc, 0x91, 0x70, 0x40, 0xc9, 0x99, 0x82, 0x10, 0xec, 0xa9, 0xf9,
+  0xde, 0x9d, 0x5b, 0xd6, 0x9d, 0xb7, 0xb5, 0xb3, 0xe8, 0x33, 0x31, 0x0e,
+  0x49, 0x79, 0x25, 0x65, 0x51, 0x99, 0x28, 0x01, 0x3f, 0xad, 0x50, 0x9e,
+  0x5f, 0x5c, 0x0c, 0x73, 0x42, 0xac, 0x53, 0xb7, 0x71, 0x87, 0x5d, 0x3b,
+  0x53, 0x03, 0x30, 0x06, 0x7c, 0x66, 0xfa, 0x34, 0xfe, 0xa9, 0x41, 0xbf,
+  0xba, 0x85, 0xf6, 0xa8, 0xe4, 0xbb, 0x95, 0xf2, 0xce, 0x59, 0x01, 0x32,
+  0x50, 0x92, 0x13, 0xf8, 0xa9, 0x42, 0xad, 0x36, 0x27, 0x84, 0xd8, 0x5c,
+  0xe8, 0x84, 0xa4, 0x0a, 0x43, 0xc4, 0x7d, 0xdb, 0x8a, 0x8e, 0xdb, 0x4f,
+  0x34, 0xb8, 0x29, 0x1f, 0x4e, 0xa0, 0xc8, 0xa8, 0x88, 0xbf, 0xda, 0x86,
+  0xcf, 0xc5, 0xac, 0xed, 0x0e, 0x37, 0x26, 0xa4, 0xba, 0x6e, 0x40, 0xc3,
+  0x3a, 0x1f, 0x12, 0x44, 0xa4, 0xb0, 0x27, 0x28, 0x34, 0xe7, 0x7b, 0x2f,
+  0x87, 0xe7, 0x86, 0xfe, 0xce, 0x04, 0x38, 0xd3, 0x18, 0x99, 0x30, 0x29,
+  0xd6, 0x42, 0xce, 0xba, 0x73, 0xd8, 0x35, 0x6f, 0x43, 0x6a, 0x82, 0x5b,
+  0x51, 0x12, 0x0e, 0xd4, 0x61, 0x48, 0xb9, 0x4a, 0xfb, 0x34, 0x95, 0x71,
+  0x4c, 0xb8, 0x9a, 0xa7, 0x6e, 0xc6, 0x81, 0x38, 0xa4, 0x57, 0x83, 0xca,
+  0x64, 0x19, 0xb4, 0x90, 0x91, 0x32, 0xac, 0x9b, 0x79, 0xce, 0x42, 0x01,
+  0xf0, 0x66, 0x7f, 0x38, 0xa5, 0xad, 0x44, 0x43, 0x1f, 0xca, 0x0f, 0x59,
+  0xbe, 0x8f, 0x9d, 0xff, 0x16, 0xc9, 0xb6, 0xb7, 0x37, 0xa4, 0x46, 0x54,
+  0x62, 0xac, 0x03, 0x2a, 0xac, 0x07, 0x39, 0xf1, 0xc9, 0xcd, 0x9b, 0xd7,
+  0x6b, 0x47, 0x13, 0x25, 0xb0, 0x68, 0x24, 0x1e, 0xb0, 0xb8, 0xec, 0x19,
+  0xa7, 0x2e, 0xaf, 0x0e, 0xb2, 0x1b, 0xd1, 0x63, 0x56, 0x83, 0xce, 0x19,
+  0xe9, 0xcb, 0x14, 0x0b, 0x19, 0x4f, 0xc3, 0x61, 0x55, 0x8d, 0xfe, 0x94,
+  0x86, 0x4a, 0x0d, 0x78, 0xbb, 0x1b, 0x8a, 0x8d, 0x3d, 0xe4, 0xbe, 0x0e,
+  0xf4, 0xa0, 0x97, 0x91, 0x02, 0xfe, 0x7d, 0xf4, 0xda, 0x44, 0x07, 0x79,
+  0xc8, 0xa2, 0x4d, 0x24, 0x50, 0x39, 0x3f, 0x9c, 0x0f, 0x33, 0xba, 0x96,
+  0x0b, 0xf9, 0x2b, 0xb7, 0x87, 0xc5, 0x74, 0x69, 0xba, 0xb6, 0xe2, 0x67,
+  0x2d, 0xe0, 0xcc, 0x00, 0x0d, 0x5b, 0x64, 0x77, 0xb8, 0x4d, 0x1a, 0x23,
+  0x2f, 0xd3, 0xf6, 0x47, 0x76, 0xff, 0x6d, 0x74, 0xde, 0x84, 0x36, 0xc3,
+  0x7b, 0x62, 0x8c, 0x2f, 0xc4, 0x54, 0x15, 0x16, 0xc7, 0xd8, 0x10, 0xd7,
+  0xa6, 0x0e, 0xd9, 0xa3, 0x1a, 0x41, 0x19, 0x76, 0x44, 0xa5, 0xda, 0x9e,
+  0x6b, 0x0a, 0xaf, 0xea, 0x27, 0x29, 0x3f, 0xaf, 0x01, 0xb7, 0xb0, 0x31,
+  0xff, 0x9e, 0x15, 0x21, 0x3d, 0xec, 0x3e, 0x24, 0x8a, 0x38, 0x63, 0x94,
+  0x3c, 0x08, 0x39, 0xd9, 0x44, 0x99, 0x28, 0x64, 0x6b, 0x09, 0xcd, 0xe8,
+  0xf8, 0x99, 0xb1, 0x33, 0x6d, 0xd6, 0xa4, 0xa5, 0xd2, 0x3c, 0x09, 0x39,
+  0x38, 0x8b, 0x23, 0x14, 0x64, 0xb6, 0x01, 0xa2, 0x7e, 0x2c, 0xbe, 0xd5,
+  0x24, 0xe5, 0xd8, 0x19, 0xce, 0xc8, 0x77, 0x8c, 0xec, 0x6c, 0x8a, 0x38,
+  0x2d, 0x8b, 0xa8, 0x42, 0x2d, 0xb1, 0x34, 0x28, 0x9c, 0x85, 0x19, 0x78,
+  0x40, 0x0a, 0xee, 0xff, 0xfa, 0xa3, 0xd9, 0xa2, 0x26, 0x55, 0xdb, 0x8f,
+  0xa0, 0xc5, 0xd7, 0xa1, 0x07, 0x67, 0x87, 0x0f, 0x4e, 0x31, 0x09, 0x74,
+  0x2a, 0xd2, 0xf3, 0xfb, 0xf3, 0x8c, 0x51, 0x65, 0x27, 0x74, 0x67, 0x2c,
+  0x64, 0x7e, 0x6e, 0x32, 0xce, 0x12, 0x0b, 0x1b, 0xb6, 0xa2, 0xda, 0xb4,
+  0xc2, 0xf4, 0xaa, 0xfe, 0x3a, 0x47, 0x52, 0x9c, 0x91, 0x43, 0x1f, 0xe7,
+  0xee, 0x71, 0x8e, 0xa2, 0x3e, 0xbd, 0xf3, 0x2e, 0xbd, 0xbc, 0xae, 0x76,
+  0x7f, 0x15, 0x3d, 0x41, 0xc1, 0xf3, 0xed, 0xc2, 0xdb, 0x3a, 0xcd, 0x2d,
+  0xf4, 0xd4, 0x5e, 0x10, 0x02, 0x84, 0xd1, 0x23, 0x5d, 0xac, 0x86, 0x4c,
+  0x7d, 0x17, 0xd3, 0xbc, 0x7f, 0xec, 0x42, 0xa9, 0x74, 0x01, 0x01, 0xa3,
+  0x8e, 0x20, 0x8c, 0x26, 0x66, 0x4e, 0x03, 0xf5, 0x07, 0xac, 0x2b, 0xaf,
+  0x5a, 0xd2, 0xbf, 0xef, 0x74, 0xf1, 0x5c, 0xb1, 0xa7, 0x48, 0x1a, 0x48,
+  0x0c, 0x69, 0xc6, 0x32, 0xc0, 0x70, 0x80, 0x77, 0x9a, 0x4c, 0x6f, 0xd7,
+  0x22, 0xd8, 0xcd, 0x42, 0x3f, 0xae, 0xf9, 0x01, 0x08, 0x06, 0x9c, 0xca,
+  0xc8, 0x3d, 0x63, 0x2b, 0x54, 0x7e, 0x76, 0xc1, 0x2c, 0xe0, 0xf5, 0x50,
+  0x54, 0x51, 0x1b, 0xcb, 0x77, 0x36, 0xed, 0x30, 0x2e, 0x63, 0xad, 0x34,
+  0x38, 0x9a, 0xd6, 0x9b, 0x0c, 0xcd, 0x2c, 0x91, 0x7f, 0x19, 0xfc, 0x4d,
+  0x58, 0xac, 0x47, 0xdd, 0x17, 0xf3, 0xb8, 0xa0, 0x10, 0x3f, 0x16, 0xad,
+  0x9b, 0x06, 0xc9, 0x97, 0x7b, 0x3f, 0x40, 0xb0, 0x0d, 0x1d, 0x85, 0xcb,
+  0x12, 0x79, 0x61, 0x8e, 0x31, 0x20, 0x51, 0x9e, 0x59, 0x97, 0x87, 0x6d,
+  0xfa, 0x4a, 0x43, 0x70, 0x8f, 0x75, 0x9f, 0x31, 0x75, 0xd9, 0xa6, 0x84,
+  0x9b, 0x40, 0xaf, 0x62, 0xa1, 0x7b, 0x4a, 0x6e, 0x72, 0xdc, 0xd0, 0xa0,
+  0x04, 0x35, 0x94, 0xd5, 0xa7, 0x3e, 0xc6, 0xd3, 0x73, 0x7b, 0xfd, 0x5b,
+  0x64, 0x1d, 0x94, 0x48, 0x69, 0x8a, 0x89, 0xd8, 0x50, 0x22, 0x30, 0x94,
+  0xfb, 0x5f, 0xaa, 0x53, 0x0b, 0xb9, 0x53, 0xe4, 0xbe, 0x0a, 0x27, 0x97,
+  0x77, 0x53, 0x0d, 0xc5, 0xde, 0x64, 0x7f, 0x73, 0x77, 0x23, 0x5a, 0x47,
+  0xb0, 0xda, 0x7c, 0x3e, 0x00, 0xd4, 0x4f, 0x80, 0x3c, 0xd8, 0x7f, 0x4d,
+  0x76, 0x56, 0x8f, 0x55, 0xdd, 0x6d, 0x63, 0xde, 0xeb, 0xa3, 0x8e, 0x44,
+  0xcf, 0xcc, 0x9e, 0xe7, 0x42, 0x94, 0x7b, 0xb9, 0x1d, 0x7d, 0x15, 0xb3,
+  0x0a, 0x9e, 0xe8, 0xd5, 0x8f, 0x2e, 0xe4, 0xa6, 0x79, 0x55, 0x82, 0xff,
+  0xfe, 0x79, 0x3a, 0x3d, 0xa7, 0x02, 0x04, 0x8d, 0x65, 0x6e, 0xab, 0x9c,
+  0x62, 0xd8, 0x6f, 0x7e, 0xab, 0x21, 0x70, 0x12, 0x88, 0x76, 0x68, 0x5b,
+  0xe2, 0x4b, 0xc6, 0x69, 0x0d, 0x5f, 0xf8, 0x21, 0x92, 0xe5, 0x49, 0xef,
+  0xe6, 0x79, 0x9d, 0xcf, 0x6d, 0x5a, 0x7d, 0xbf, 0x08, 0x61, 0x62, 0xbd,
+  0x87, 0x75, 0x8e, 0x36, 0x1c, 0x0a, 0x13, 0x94, 0x9c, 0x03, 0x01, 0x2e,
+  0x47, 0xd8, 0x93, 0x13, 0xab, 0xab, 0x8d, 0xfe, 0x4d, 0xb3, 0x4e, 0x0a,
+  0x18, 0x67, 0x84, 0x38, 0x21, 0x11, 0xb0, 0x58, 0x7c, 0x78, 0x23, 0xaf,
+  0xbc, 0x58, 0xf7, 0x3b, 0xeb, 0x69, 0x59, 0xc9, 0x1a, 0x03, 0xe6, 0x00,
+  0x43, 0xc0, 0x15, 0x56, 0x9b, 0x19, 0xb3, 0xbc, 0xdb, 0xeb, 0xec, 0xca,
+  0xb8, 0x6a, 0x18, 0x7c, 0x59, 0xba, 0xa4, 0xc6, 0x84, 0x91, 0x12, 0x4b,
+  0x41, 0xf2, 0xbc, 0x5a, 0x52, 0x29, 0x99, 0x0c, 0x5e, 0xb0, 0x9f, 0x0c,
+  0xd4, 0xc5, 0x6e, 0xed, 0xf9, 0xb0, 0xc1, 0xc1, 0x7d, 0xae, 0x67, 0x4c,
+  0xc0, 0x55, 0xf4, 0xed, 0x03, 0xad, 0xc5, 0xb4, 0x83, 0xfe, 0xec, 0x16,
+  0x70, 0x08, 0xdd, 0x5c, 0x45, 0xb4, 0xb7, 0x99, 0x9b, 0xec, 0xa0, 0x06,
+  0x42, 0x44, 0xd0, 0x9f, 0xda, 0x05, 0xb7, 0xef, 0x7c, 0xd5, 0xa3, 0x0f,
+  0x4c, 0x36, 0xf7, 0x92, 0x98, 0xc4, 0x64, 0x89, 0xa7, 0x2a, 0x39, 0x41,
+  0xa1, 0x28, 0xcb, 0xc4, 0xc1, 0x77, 0xda, 0x49, 0xf7, 0xfa, 0xb3, 0x72,
+  0x93, 0xa0, 0xad, 0x09, 0x9b, 0xd9, 0x82, 0x44, 0xf6, 0x84, 0x9c, 0xbf,
+  0xad, 0x73, 0xde, 0x15, 0x76, 0xee, 0x9c, 0x4f, 0xce, 0x5f, 0x5d, 0xf4,
+  0x90, 0x51, 0xfc, 0xaf, 0xfc, 0x59, 0x2a, 0x70, 0x92, 0x66, 0xeb, 0xd3,
+  0x04, 0x29, 0xc8, 0xc2, 0x49, 0x40, 0x9a, 0xac, 0xff, 0x94, 0x31, 0x42,
+  0x81, 0x83, 0x17, 0x6f, 0x87, 0xdc, 0x62, 0xe7, 0x74, 0x50, 0xc9, 0xc6,
+  0x83, 0xbf, 0x7a, 0xe0, 0xae, 0x11, 0xbd, 0x86, 0x0f, 0x02, 0xdc, 0x2a,
+  0x58, 0xee, 0x50, 0x04, 0xcf, 0x28, 0x7d, 0xa0, 0xdf, 0xd8, 0x2b, 0xec,
+  0xe3, 0x79, 0xff, 0xd9, 0x2b, 0xc3, 0x23, 0x3a, 0x4a, 0x19, 0x26, 0x69,
+  0x7c, 0x5a, 0xcb, 0xf5, 0x66, 0x11, 0xdd, 0x7e, 0x4f, 0x99, 0xc6, 0xf2,
+  0x6f, 0xf6, 0xe5, 0x3f, 0x60, 0x46, 0xfe, 0x52, 0x26, 0xab, 0x3a, 0xcc,
+  0x48, 0xbf, 0xdf, 0xcc, 0xaf, 0x67, 0xc5, 0x02, 0x99, 0x93, 0x43, 0x0b,
+  0x11, 0x31, 0xda, 0x9c, 0xa6, 0x64, 0xb9, 0x4b, 0xed, 0x05, 0x56, 0xf8,
+  0x75, 0xdf, 0xbc, 0x7d, 0xfd, 0xee, 0x69, 0x59, 0xfb, 0x68, 0x7e, 0xfd,
+  0x94, 0xd3, 0x46, 0x1d, 0xa2, 0x61, 0x59, 0x8c, 0x7b, 0x05, 0x58, 0x07,
+  0x8a, 0xfe, 0x37, 0x7b, 0xbc, 0x9c, 0x40, 0x04, 0x4d, 0x08, 0x31, 0xca,
+  0x3c, 0xb9, 0x74, 0x67, 0x46, 0xbc, 0xc9, 0x79, 0x78, 0x4e, 0x60, 0xbf,
+  0xf8, 0x92, 0x51, 0xa4, 0xda, 0x35, 0xfd, 0xe8, 0x89, 0x4b, 0xe0, 0xc8,
+  0x9c, 0xb2, 0xbe, 0xb9, 0x3c, 0x26, 0x4b, 0x6a, 0x8a, 0xfa, 0xa8, 0x5c,
+  0xd3, 0x0b, 0x9a, 0x86, 0xd9, 0x5a, 0xa1, 0x2b, 0x13, 0x2d, 0xf1, 0xe9,
+  0xde, 0x99, 0x78, 0x0d, 0xc9, 0xae, 0x6d, 0x4e, 0x8e, 0x3c, 0x25, 0x2d,
+  0x1f, 0xb1, 0x04, 0x69, 0x86, 0x4b, 0x23, 0xc3, 0x70, 0x8c, 0x5d, 0x08,
+  0xc0, 0x3b, 0x8f, 0x88, 0x8f, 0x82, 0x42, 0x20, 0xef, 0xf8, 0xbb, 0x92,
+  0x06, 0x8b, 0x19, 0x3e, 0xc6, 0x34, 0xa5, 0x95, 0x90, 0xf0, 0x16, 0xac,
+  0xee, 0x4b, 0xed, 0x7c, 0xb6, 0x83, 0x2a, 0x67, 0x14, 0x8d, 0xec, 0x4c,
+  0xe5, 0x6e, 0x96, 0x92, 0xa6, 0x05, 0x2a, 0xb1, 0x57, 0xb8, 0x7c, 0x31,
+  0xc7, 0x56, 0xf4, 0xf3, 0xc9, 0x06, 0x3f, 0x51, 0x8e, 0x93, 0x45, 0xe6,
+  0x22, 0xed, 0x44, 0x71, 0xff, 0x61, 0x38, 0x7f, 0xc4, 0x57, 0xff, 0x3c,
+  0x04, 0x1a, 0xa1, 0xc8, 0x80, 0xb0, 0x97, 0x30, 0x2b, 0x17, 0xe5, 0x67,
+  0xa2, 0x54, 0x38, 0xdc, 0x5e, 0x48, 0x27, 0xe8, 0x08, 0xd7, 0xfd, 0xef,
+  0x99, 0x34, 0xb1, 0x40, 0x06, 0x14, 0x49, 0x43, 0x2b, 0x18, 0xbe, 0x5a,
+  0x1d, 0xc1, 0x8e, 0xcf, 0x0a, 0xca, 0xf0, 0x13, 0x5b, 0x8b, 0x3f, 0xe8,
+  0x3c, 0xa0, 0x84, 0x46, 0x09, 0x69, 0x14, 0x70, 0x1f, 0x06, 0x61, 0x3d,
+  0xd3, 0x25, 0x24, 0x5f, 0x37, 0x0b, 0x36, 0xea, 0xbd, 0xce, 0xd9, 0xb5,
+  0x0f, 0x21, 0x84, 0x25, 0xb4, 0x8b, 0x34, 0xe5, 0x41, 0xa7, 0x58, 0x47,
+  0xcc, 0x97, 0x91, 0x1e, 0xcc, 0x63, 0x88, 0x8b, 0x84, 0xb9, 0xf7, 0x0c,
+  0x59, 0xb4, 0x28, 0x8a, 0xa8, 0xcc, 0xa9, 0xc4, 0x9a, 0xb6, 0x2e, 0xca,
+  0x0d, 0x8c, 0x52, 0x08, 0x9b, 0xd7, 0xee, 0x2a, 0x1b, 0x0e, 0xde, 0x81,
+  0x38, 0x62, 0x97, 0x43, 0xe3, 0xd2, 0x20, 0x5a, 0x30, 0x92, 0xe9, 0x1f,
+  0x14, 0x99, 0x69, 0x8c, 0xa1, 0x13, 0xc8, 0x48, 0x4e, 0xf5, 0x73, 0x3a,
+  0xf4, 0xa1, 0xfb, 0xf4, 0x7c, 0xfb, 0x3f, 0x2d, 0xe6, 0x2d, 0x78, 0x10,
+  0x03, 0x70, 0x7c, 0xc1, 0x90, 0x96, 0x4f, 0x09, 0x04, 0xfd, 0x03, 0x55,
+  0xf7, 0x1a, 0x58, 0x5f, 0x6a, 0x26, 0x25, 0x80, 0xc6, 0x9f, 0xf7, 0x1b,
+  0x45, 0x06, 0xdc, 0xcd, 0xf4, 0x65, 0x4b, 0xfb, 0xbe, 0xd7, 0x45, 0x19,
+  0x1d, 0x41, 0x90, 0x82, 0x39, 0x14, 0x83, 0x35, 0x9c, 0xf3, 0xd7, 0x9f,
+  0x9a, 0x70, 0x43, 0x03, 0x90, 0xde, 0x6d, 0x84, 0xb0, 0xe9, 0x55, 0x68,
+  0xfb, 0xcd, 0xfb, 0x3c, 0x9b, 0x44, 0xb0, 0x22, 0x8b, 0x97, 0x79, 0x83,
+  0xe9, 0xee, 0x5b, 0x59, 0xab, 0x8a, 0x69, 0x85, 0x37, 0x57, 0x11, 0x8f,
+  0x97, 0x21, 0x80, 0xa1, 0x2c, 0x89, 0xc9, 0xed, 0x6c, 0xce, 0x4d, 0xb5,
+  0xe2, 0xb7, 0xd2, 0xc4, 0xa2, 0x70, 0xe1, 0xb4, 0x45, 0x78, 0x2f, 0x0e,
+  0x63, 0x06, 0x33, 0xc7, 0x9d, 0x1a, 0x52, 0x13, 0xdf, 0xda, 0xdb, 0xe8,
+  0x57, 0x49, 0x1d, 0x81, 0xac, 0x71, 0x8c, 0x64, 0x90, 0x29, 0x19, 0xd1,
+  0x33, 0xf9, 0xc0, 0xce, 0x13, 0xf2, 0x59, 0x16, 0xf0, 0xea, 0x6a, 0x75,
+  0x78, 0x07, 0x75, 0xf0, 0xf9, 0x0a, 0x66, 0x52, 0x48, 0xd0, 0x4e, 0xd0,
+  0x6b, 0x89, 0xd6, 0x9b, 0xef, 0x7e, 0xef, 0x23, 0x29, 0x0a, 0x4c, 0x28,
+  0xe4, 0xc8, 0x1f, 0x15, 0x13, 0x3a, 0xca, 0x98, 0x20, 0x7f, 0xe2, 0x9d,
+  0x2a, 0xe6, 0x1c, 0x77, 0xa5, 0x06, 0xe3, 0x19, 0xce, 0x7f, 0x38, 0xcf,
+  0x5e, 0xd1, 0xef, 0xf8, 0x81, 0x20, 0xfa, 0x98, 0x45, 0x9f, 0x2b, 0x27,
+  0xe0, 0x73, 0x8c, 0xe1, 0x01, 0x2c, 0x05, 0x0a, 0xa7, 0x19, 0xd9, 0xe5,
+  0xf6, 0x06, 0xd4, 0x02, 0xdb, 0xee, 0x38, 0x41, 0x35, 0x02, 0x48, 0xa4,
+  0x72, 0x0a, 0xa2, 0x6c, 0x6a, 0x8a, 0x18, 0x08, 0x4b, 0x26, 0x44, 0xa4,
+  0x0a, 0x1e, 0x20, 0xcf, 0xfc, 0xa8, 0x72, 0x37, 0xe6, 0xe4, 0xea, 0xb4,
+  0x4c, 0xe9, 0xe5, 0x6e, 0x1c, 0x57, 0x83, 0x2f, 0x44, 0x50, 0xc0, 0x3c,
+  0x37, 0x07, 0x38, 0xbd, 0x6a, 0xc7, 0x88, 0x90, 0x0b, 0x7d, 0xe9, 0x20,
+  0x2a, 0xbc, 0x73, 0xad, 0x07, 0x60, 0x52, 0x9a, 0x47, 0x2f, 0xe2, 0xc6,
+  0x9a, 0xc0, 0x0d, 0x37, 0x12, 0x60, 0x99, 0x51, 0xfc, 0x5e, 0xdf, 0xc0,
+  0x23, 0x7f, 0x47, 0xa2, 0x5c, 0xa6, 0x2f, 0xa5, 0x62, 0x13, 0xc6, 0x3b,
+  0x61, 0xf1, 0x52, 0xe1, 0x90, 0x9b, 0xba, 0x4a, 0x67, 0x02, 0x3f, 0xfd,
+  0x8d, 0xfe, 0xd7, 0xe1, 0xed, 0xd6, 0x26, 0x3a, 0xd9, 0x48, 0x3c, 0x00,
+  0x11, 0x36, 0x33, 0x18, 0x6c, 0x9e, 0x57, 0x89, 0xe5, 0x44, 0xfe, 0xae,
+  0x69, 0xd9, 0x4c, 0x22, 0x1f, 0x18, 0xe9, 0x07, 0xf8, 0xbf, 0x42, 0x8c,
+  0x0b, 0xf1, 0xb5, 0x6c, 0x95, 0x2f, 0xcb, 0x0c, 0x85, 0x90, 0xc0, 0xfa,
+  0x98, 0xcb, 0x32, 0xd8, 0xfb, 0x1a, 0x57, 0x49, 0xf5, 0xea, 0x9b, 0x27,
+  0x3d, 0xf6, 0x11, 0xf5, 0xfc, 0xa9, 0x7f, 0xca, 0xe3, 0xf5, 0xb3, 0x50,
+  0xd5, 0x78, 0xcf, 0x28, 0x99, 0x82, 0x11, 0x96, 0x46, 0x51, 0x00, 0x25,
+  0x56, 0x4e, 0xf6, 0xa6, 0x59, 0xd3, 0x97, 0xdf, 0x0c, 0x1f, 0x4e, 0xa6,
+  0x69, 0x50, 0x2f, 0xad, 0xe4, 0x84, 0x8b, 0x82, 0xc6, 0x45, 0x2f, 0xb8,
+  0x07, 0x9a, 0x5c, 0x1e, 0xa8, 0xe7, 0x9a, 0xcc, 0xff, 0xf4, 0x89, 0x30,
+  0xa7, 0x52, 0x9b, 0x99, 0x65, 0x28, 0xda, 0xef, 0x4f, 0x5a, 0x8c, 0x27,
+  0x36, 0x4a, 0x06, 0x5d, 0xc0, 0x5c, 0x79, 0x96, 0xbf, 0x2d, 0xd6, 0xcb,
+  0xa4, 0xcc, 0xc7, 0x15, 0xa0, 0x93, 0xb0, 0x2f, 0xa1, 0x19, 0x5f, 0x6e,
+  0x66, 0x94, 0xe7, 0x37, 0x74, 0xf8, 0x22, 0x57, 0xed, 0xca, 0x0f, 0x0d,
+  0x31, 0x54, 0xe2, 0x5b, 0xc6, 0xb1, 0x3d, 0x97, 0xb5, 0xdb, 0xaa, 0x5d,
+  0x60, 0x0f, 0x08, 0x22, 0x1e, 0x2d, 0x80, 0x99, 0x92, 0x1a, 0x4d, 0x2d,
+  0x90, 0x41, 0x38, 0x40, 0x0d, 0x07, 0xe0, 0xbc, 0x0c, 0x76, 0x58, 0x61,
+  0xb2, 0xd1, 0x4b, 0x97, 0x68, 0x12, 0x3f, 0x6a, 0x4f, 0xc3, 0xf9, 0x1f,
+  0xc8, 0x58, 0x39, 0x7b, 0xbc, 0x7f, 0x5a, 0xf9, 0xc4, 0x1a, 0x14, 0x88,
+  0x27, 0x1d, 0xc6, 0xf6, 0x66, 0x95, 0x87, 0xcb, 0x99, 0xee, 0x50, 0x8d,
+  0x56, 0xff, 0x90, 0x0b, 0xb4, 0x94, 0x77, 0xcb, 0x06, 0x63, 0x7a, 0x65,
+  0xf1, 0xfc, 0x35, 0x59, 0x68, 0xee, 0x50, 0x25, 0xf2, 0x5c, 0xff, 0x28,
+  0x9e, 0xd1, 0xd5, 0xea, 0x84, 0x14, 0x90, 0x28, 0xfc, 0x5f, 0xa0, 0x3e,
+  0xc8, 0xee, 0x61, 0xeb, 0x05, 0x9c, 0x6e, 0x44, 0x58, 0x78, 0xfc, 0xfe,
+  0x0c, 0xb5, 0x01, 0xf9, 0xab, 0xf3, 0xbf, 0xcd, 0x6f, 0x8e, 0x31, 0xdc,
+  0x4a, 0xb4, 0x12, 0xe9, 0x8a, 0x15, 0x90, 0x62, 0x4d, 0xc1, 0xef, 0xbf,
+  0x53, 0xeb, 0x8f, 0x90, 0x1d, 0x17, 0xbf, 0xc7, 0xa3, 0x0c, 0x35, 0x26,
+  0x76, 0x9b, 0xa4, 0x56, 0xf0, 0xfc, 0x41, 0xe0, 0x96, 0x02, 0x75, 0x9b,
+  0x0f, 0xfe, 0x1a, 0x9c, 0x10, 0x79, 0xa5, 0xfa, 0x2c, 0x5b, 0x6f, 0xfa,
+  0xf3, 0x16, 0xea, 0xca, 0xed, 0xb5, 0xe9, 0xd3, 0x73, 0xf0, 0x41, 0x29,
+  0x98, 0x4a, 0x00, 0x10, 0x03, 0xe8, 0x02, 0x6f, 0x15, 0xf8, 0x42, 0x65,
+  0xb6, 0x8b, 0xf7, 0x12, 0x96, 0x55, 0xf6, 0x0e, 0x38, 0xaa, 0xc7, 0x6f,
+  0x70, 0x7b, 0x40, 0x0f, 0xce, 0x02, 0xa7, 0xe3, 0xba, 0x8f, 0xff, 0xaa,
+  0x76, 0x7e, 0x3c, 0xc9, 0x43, 0x98, 0x59, 0xa5, 0x4c, 0x68, 0x99, 0x03,
+  0x01, 0x45, 0x11, 0x0d, 0x04, 0x60, 0xfa, 0x9d, 0xa9, 0xf7, 0xfd, 0x9e,
+  0x3b, 0xac, 0xc6, 0xf9, 0xdd, 0xd2, 0x8c, 0x9b, 0x13, 0x58, 0x83, 0xcc,
+  0x69, 0x6e, 0x63, 0x58, 0x79, 0x80, 0x10, 0xc6, 0x61, 0x21, 0xe0, 0x61,
+  0x42, 0xac, 0x07, 0x95, 0xfd, 0xbd, 0xb7, 0xa8, 0x17, 0xed, 0x71, 0xc2,
+  0x58, 0xf3, 0x36, 0x5e, 0x4e, 0x09, 0xe0, 0x3f, 0x6e, 0x1d, 0x28, 0x7c,
+  0x4b, 0x9d, 0x1f, 0xd7, 0x84, 0x27, 0x29, 0xd3, 0x1f, 0xcf, 0x0a, 0xfc,
+  0xdb, 0x3a, 0xde, 0xda, 0xd1, 0x3a, 0x50, 0x4a, 0x5a, 0x82, 0x80, 0x48,
+  0xd1, 0x38, 0x49, 0x9d, 0x88, 0xb7, 0x39, 0x16, 0xa7, 0xb7, 0xbb, 0xdf,
+  0x82, 0xfa, 0xa4, 0x08, 0xca, 0x13, 0x20, 0xe4, 0xcc, 0x69, 0x10, 0x89,
+  0x85, 0xdc, 0xfe, 0xca, 0xd5, 0xbb, 0x1c, 0x75, 0x71, 0x94, 0x70, 0xce,
+  0x46, 0x58, 0x33, 0x92, 0x5d, 0x61, 0x29, 0xe4, 0xa1, 0xaf, 0xed, 0x8e,
+  0x35, 0x89, 0xa7, 0x45, 0x82, 0x33, 0x85, 0xa5, 0x36, 0x9f, 0x70, 0xbd,
+  0xf4, 0x63, 0x5d, 0xc2, 0x3c, 0xd8, 0xea, 0x53, 0x7b, 0x6a, 0xf0, 0xa9,
+  0x19, 0xbb, 0x9b, 0x1d, 0xf5, 0xaf, 0x4e, 0x71, 0xf4, 0xae, 0x44, 0x12,
+  0x18, 0x71, 0x03, 0x4d, 0x9d, 0x04, 0x89, 0x47, 0xc4, 0x02, 0x69, 0xb9,
+  0x6b, 0x79, 0x76, 0x29, 0x6f, 0xe6, 0x9b, 0x40, 0xe8, 0x4b, 0x94, 0x84,
+  0xd1, 0x90, 0x3d, 0xaf, 0xcf, 0x3e, 0xdb, 0xe5, 0xec, 0x5e, 0x2d, 0x7f,
+  0x1a, 0x92, 0x32, 0x10, 0xcc, 0xcb, 0xb5, 0xf0, 0x13, 0x15, 0xb4, 0x2e,
+  0xec, 0x11, 0x65, 0x90, 0x42, 0x1b, 0xb5, 0x20, 0xa7, 0x7c, 0x92, 0xd1,
+  0x33, 0x9d, 0xea, 0xa8, 0x46, 0xca, 0x2a, 0x60, 0x3d, 0xcf, 0x5d, 0x8f,
+  0xa5, 0x25, 0x42, 0xe5, 0xff, 0x2a, 0x0b, 0x60, 0xcf, 0xfd, 0x8c, 0xb7,
+  0xd9, 0x83, 0xa2, 0xc9, 0x6f, 0xc2, 0x5a, 0x30, 0xc2, 0xd8, 0x41, 0xd7,
+  0x9a, 0xbe, 0x1b, 0xfe, 0x3c, 0xa3, 0x0f, 0x2d, 0x02, 0xe0, 0x4a, 0x66,
+  0x92, 0x2d, 0xb4, 0x11, 0x48, 0xcb, 0xed, 0x04, 0xd9, 0xd1, 0x5b, 0xe3,
+  0x7f, 0x9f, 0x99, 0x3b, 0x92, 0x95, 0x51, 0x64, 0x3a, 0x5d, 0x94, 0xce,
+  0xfb, 0x73, 0xf1, 0xde, 0x2b, 0xf0, 0xcf, 0xb2, 0x00, 0x44, 0xe4, 0x92,
+  0xbd, 0x3f, 0x5b, 0xa5, 0x1f, 0x97, 0xeb, 0x84, 0x52, 0x18, 0xd5, 0xad,
+  0x79, 0x2d, 0x47, 0xfd, 0x24, 0xa3, 0x43, 0x2d, 0x0f, 0xa2, 0x9a, 0xd0,
+  0xe5, 0x70, 0x23, 0x04, 0x82, 0x3d, 0x84, 0xab, 0x22, 0xf8, 0x82, 0x90,
+  0x48, 0x56, 0x50, 0xb7, 0x9a, 0x41, 0x2d, 0xfc, 0x6f, 0x25, 0x0b, 0x86,
+  0x01, 0x8b, 0x35, 0x18, 0xc4, 0xa4, 0x68, 0x78, 0x3a, 0x99, 0xd4, 0xa0,
+  0xd3, 0xa3, 0x23, 0xf5, 0xde, 0x69, 0xba, 0x22, 0x60, 0x89, 0x56, 0x51,
+  0x87, 0xe9, 0xea, 0x48, 0xbc, 0xdf, 0xe2, 0x9e, 0x7b, 0xfc, 0x88, 0x6b,
+  0x6a, 0xe9, 0x65, 0xb8, 0x9c, 0xe9, 0x72, 0x28, 0xc9, 0xe9, 0x89, 0x11,
+  0xf1, 0x2a, 0xd1, 0x4f, 0x7e, 0xf9, 0x5e, 0x07, 0x4f, 0xee, 0xdc, 0x82,
+  0x4a, 0x53, 0x30, 0xf9, 0x96, 0x85, 0x1f, 0x99, 0xac, 0xd9, 0xfa, 0x44,
+  0xa4, 0xe5, 0x4f, 0x16, 0xe7, 0x9c, 0x42, 0x11, 0x2d, 0x95, 0x2c, 0xbf,
+  0x00, 0x17, 0x9e, 0x98, 0xc9, 0x9e, 0x77, 0x85, 0xe2, 0x0b, 0x29, 0xb7,
+  0xa2, 0x4f, 0x04, 0xc9, 0x2d, 0xa3, 0x04, 0x8f, 0x82, 0x5e, 0x16, 0x58,
+  0x33, 0x00, 0x21, 0x34, 0x72, 0xe4, 0x2a, 0xd9, 0x44, 0x7a, 0x63, 0xfc,
+  0xf5, 0xa5, 0x80, 0x7f, 0x9e, 0xb6, 0xb9, 0xa5, 0xe3, 0xb4, 0x99, 0x1f,
+  0x4d, 0x61, 0x1e, 0xcd, 0xa6, 0x37, 0x9f, 0x38, 0x8c, 0xfa, 0x28, 0xa5,
+  0x81, 0x18, 0xe4, 0xbb, 0x29, 0xcf, 0x1c, 0x74, 0xd7, 0x69, 0xa7, 0xd9,
+  0xed, 0x4c, 0x10, 0x93, 0xf3, 0x47, 0x81, 0xe7, 0x90, 0x32, 0x6d, 0xc4,
+  0x74, 0x2a, 0xcd, 0x2f, 0x04, 0xd2, 0x00, 0xcc, 0x20, 0x7e, 0x71, 0xab,
+  0x73, 0xf4, 0xda, 0xd9, 0xe2, 0xf7, 0x2c, 0xf4, 0x86, 0x42, 0x85, 0x13,
+  0x47, 0x25, 0x2e, 0xe0, 0x65, 0x6f, 0x5a, 0x22, 0xbc, 0x1c, 0xf1, 0x8f,
+  0x87, 0xff, 0xda, 0x99, 0x50, 0x54, 0xa4, 0x48, 0x47, 0x0f, 0xf6, 0x2d,
+  0xdf, 0x99, 0xc9, 0xb4, 0xb4, 0x67, 0x8c, 0x06, 0x3e, 0x80, 0xf9, 0x9a,
+  0x03, 0x25, 0x97, 0x84, 0x04, 0x93, 0x97, 0xa5, 0x52, 0xc4, 0x43, 0x0e,
+  0x91, 0x45, 0x0c, 0x06, 0xf5, 0x15, 0x89, 0x47, 0x15, 0xba, 0xaa, 0x03,
+  0x90, 0xf1, 0x43, 0x8a, 0x33, 0xc6, 0xc7, 0x19, 0x21, 0x47, 0x00, 0xac,
+  0x89, 0xec, 0xa9, 0xb6, 0xb8, 0x34, 0x7b, 0xf2, 0x51, 0xd3, 0xf9, 0xf4,
+  0x18, 0x19, 0x87, 0xd0, 0x07, 0x54, 0x70, 0xf9, 0x79, 0x74, 0x51, 0xee,
+  0x41, 0x0d, 0xfa, 0xed, 0x8f, 0x0e, 0x2f, 0xf7, 0xd4, 0x8b, 0xc3, 0xb5,
+  0x72, 0x26, 0x5c, 0xe5, 0xbe, 0x9c, 0x3e, 0x01, 0x04, 0xfc, 0x6d, 0x7b,
+  0xc2, 0x4f, 0xfe, 0x2c, 0x5e, 0xea, 0xf1, 0x64, 0x31, 0xc5, 0x31, 0x31,
+  0x42, 0x7d, 0x98, 0x80, 0x64, 0x42, 0x47, 0xc4, 0x45, 0xed, 0xfc, 0xf2,
+  0x9f, 0x45, 0xad, 0xda, 0xaf, 0x51, 0x61, 0x97, 0x45, 0x68, 0x31, 0xc9,
+  0xa1, 0x46, 0x5e, 0x03, 0xa9, 0xaa, 0x05, 0x14, 0x51, 0x61, 0xe9, 0xbd,
+  0x58, 0x6c, 0x6d, 0x09, 0xd2, 0x48, 0x65, 0x7d, 0x79, 0xd9, 0xc9, 0x1e,
+  0xca, 0xa5, 0xdc, 0xa7, 0x86, 0x77, 0xd6, 0x41, 0x45, 0x0f, 0x88, 0x7e,
+  0xb1, 0xa5, 0xfa, 0xdd, 0xaa, 0x2d, 0xa8, 0x89, 0xa1, 0x32, 0x3b, 0x0b,
+  0xe0, 0x0a, 0xf5, 0x72, 0x29, 0x9c, 0x03, 0xce, 0x00, 0x42, 0x46, 0x06,
+  0x79, 0xbc, 0xd2, 0xfd, 0x23, 0x08, 0x00, 0x7c, 0xad, 0x65, 0xc5, 0x69,
+  0x51, 0xa8, 0xcc, 0x68, 0x45, 0x7b, 0xc4, 0x72, 0xdc, 0xf0, 0x43, 0xd0,
+  0xa3, 0x24, 0x94, 0x4f, 0xd3, 0x03, 0x53, 0xf9, 0x47, 0xf2, 0xcd, 0x79,
+  0xa7, 0x4b, 0x7c, 0xbb, 0x69, 0x00, 0x51, 0xaf, 0x4e, 0x11, 0xf1, 0x3e,
+  0x80, 0xaa, 0x8d, 0x57, 0x2f, 0xc9, 0x6a, 0xff, 0x3d, 0xbc, 0xdb, 0xad,
+  0xea, 0x75, 0xfb, 0xdb, 0x70, 0x64, 0xd1, 0x1b, 0xed, 0x4a, 0x55, 0x01,
+  0xe0, 0x6d, 0x99, 0x6f, 0x17, 0x56, 0x2d, 0x1e, 0x17, 0x47, 0x26, 0x1d,
+  0x50, 0xcf, 0x00, 0xdc, 0xb2, 0x28, 0x2a, 0x9f, 0xd7, 0xf7, 0x2e, 0xb6,
+  0xb9, 0xe3, 0x91, 0xca, 0x9e, 0x58, 0xdb, 0x64, 0x4a, 0x42, 0x31, 0xfa,
+  0x8a, 0xba, 0x7c, 0xa5, 0x8a, 0x76, 0xce, 0xdc, 0x47, 0xe3, 0xf8, 0xeb,
+  0x3a, 0xdc, 0x90, 0xb1, 0xc4, 0x28, 0x1c, 0xaa, 0x08, 0x51, 0xfb, 0x74,
+  0x76, 0xbd, 0x83, 0x75, 0x3e, 0xef, 0x2d, 0xb3, 0x21, 0x60, 0x04, 0xa2,
+  0xf8, 0x05, 0x14, 0x72, 0xa8, 0x61, 0x20, 0xe5, 0x26, 0x77, 0x71, 0x70,
+  0x4f, 0x8a, 0xfa, 0x3b, 0x88, 0x7b, 0x59, 0x65, 0x10, 0xdd, 0xa2, 0x22,
+  0x55, 0x58, 0x28, 0xfc, 0xb5, 0xe9, 0x91, 0x7a, 0xf2, 0x35, 0x08, 0x50,
+  0x9a, 0x5f, 0xd2, 0xda, 0xb6, 0x5b, 0xda, 0xb9, 0x14, 0x83, 0xb2, 0x5f,
+  0xee, 0x73, 0x0f, 0xa8, 0x6c, 0xb3, 0xe2, 0x4a, 0x47, 0xc1, 0x3d, 0xf5,
+  0x44, 0x8d, 0x50, 0xfa, 0xa2, 0x3e, 0x85, 0xf0, 0x1f, 0x7d, 0x49, 0x47,
+  0xc5, 0x43, 0x7f, 0x40, 0xa5, 0xe2, 0x09, 0x03, 0xae, 0x98, 0x4b, 0xd3,
+  0x07, 0xb9, 0x1e, 0x05, 0x7c, 0xf1, 0xb1, 0xe7, 0x26, 0xd6, 0xc9, 0xc9,
+  0x0f, 0x06, 0xd6, 0x9d, 0xfc, 0x2a, 0xdb, 0x7f, 0x43, 0x39, 0x61, 0x69,
+  0x32, 0xe7, 0x98, 0xdb, 0xde, 0x51, 0xd7, 0x21, 0xd1, 0x2a, 0x84, 0x9d,
+  0x16, 0x32, 0xa1, 0x4e, 0x70, 0x41, 0x23, 0x97, 0x2f, 0xa2, 0x4f, 0x4e,
+  0xb4, 0x97, 0xae, 0x5e, 0x6f, 0x05, 0x03, 0x7a, 0x23, 0x40, 0x3c, 0x2d,
+  0x42, 0xa5, 0x95, 0x6c, 0x40, 0xec, 0x65, 0x30, 0x72, 0x8e, 0x11, 0x0c,
+  0x49, 0xa0, 0x9b, 0x28, 0xcf, 0x9f, 0xca, 0x67, 0x7b, 0xa0, 0x68, 0x16,
+  0xf1, 0x31, 0xe3, 0x6f, 0xc2, 0xb6, 0xee, 0xf3, 0xd6, 0xb6, 0x68, 0x19,
+  0x86, 0x97, 0xc5, 0x22, 0x57, 0xa8, 0x1b, 0xe4, 0x78, 0xd7, 0x1d, 0xf9,
+  0xe8, 0xcf, 0x15, 0x9b, 0x73, 0x48, 0xc2, 0xd5, 0x50, 0xd1, 0x6d, 0x3d,
+  0xf8, 0xfd, 0xdb, 0x57, 0x90, 0x60, 0xdf, 0x30, 0xdd, 0x85, 0x47, 0xc6,
+  0xa3, 0x5e, 0x19, 0xef, 0x8c, 0xd9, 0x29, 0xe2, 0x46, 0x59, 0xb1, 0x72,
+  0x9d, 0x59, 0xbf, 0x72, 0xae, 0x37, 0x1c, 0xc4, 0x87, 0xc5, 0x23, 0x15,
+  0xc3, 0xc2, 0xcb, 0xe1, 0x1a, 0x52, 0x48, 0x21, 0xf7, 0x20, 0xd8, 0xb9,
+  0xdf, 0xbd, 0xd5, 0x4e, 0x45, 0x50, 0x29, 0x16, 0xe4, 0xc8, 0x4d, 0xf1,
+  0x8a, 0x34, 0x61, 0x0e, 0x50, 0xca, 0x22, 0x7e, 0x22, 0x31, 0xd9, 0xc5,
+  0x67, 0xa6, 0x83, 0x1a, 0x5c, 0x91, 0x0c, 0xf2, 0xdf, 0x19, 0x9d, 0x00,
+  0x95, 0x0f, 0x72, 0xba, 0xa2, 0xd9, 0xff, 0x1f, 0xc7, 0x45, 0xbc, 0xcc,
+  0x49, 0x90, 0xc9, 0x78, 0xc1, 0x8e, 0x98, 0x51, 0x10, 0x34, 0xf6, 0xc9,
+  0x64, 0xd5, 0x55, 0x14, 0xc5, 0xc5, 0x71, 0x2e, 0x51, 0x79, 0xbe, 0xaa,
+  0xff, 0xa6, 0xb3, 0x8d, 0x62, 0x34, 0x49, 0x63, 0xa3, 0x51, 0xd0, 0x91,
+  0x23, 0x29, 0x11, 0xe2, 0x85, 0xdc, 0xd2, 0x61, 0x57, 0x25, 0x76, 0x2b,
+  0x42, 0x08, 0x69, 0xac, 0x57, 0xa4, 0x35, 0x34, 0x4b, 0xd5, 0x86, 0xf0,
+  0x35, 0x9d, 0xb9, 0x17, 0x98, 0xbe, 0x69, 0x70, 0xd9, 0xcd, 0x0f, 0xe5,
+  0xe5, 0xaf, 0x97, 0x1f, 0xa4, 0xc7, 0xd3, 0x8b, 0x22, 0x32, 0x78, 0x49,
+  0x84, 0x64, 0xaa, 0xe7, 0xe9, 0x86, 0xd8, 0xb8, 0xad, 0xe9, 0xc5, 0x11,
+  0xcb, 0xf3, 0xad, 0xb5, 0x14, 0xa5, 0xe2, 0xf1, 0x43, 0xb5, 0xdf, 0xd3,
+  0x7e, 0xb7, 0x9e, 0x50, 0x68, 0xf6, 0xcb, 0x9e, 0x43, 0x4b, 0xf5, 0x19,
+  0x0c, 0xa9, 0x1f, 0xd6, 0x14, 0x0e, 0xdc, 0xe0, 0x09, 0x64, 0xa5, 0xe6,
+  0x02, 0x95, 0x71, 0x7c, 0xed, 0xb9, 0xb4, 0x87, 0x6c, 0x96, 0x50, 0xcc,
+  0x13, 0xa1, 0x36, 0xee, 0xbf, 0x7e, 0xdc, 0x58, 0xf7, 0x7f, 0xd1, 0x04,
+  0x13, 0x01, 0xa4, 0x6d, 0xb4, 0x9a, 0x1a, 0xd0, 0x9e, 0x4f, 0xe0, 0xe7,
+  0xdc, 0x93, 0xb6, 0xfd, 0xd4, 0x54, 0xd8, 0xed, 0x0b, 0xeb, 0x38, 0x5b,
+  0xfe, 0xde, 0xf9, 0x0e, 0x0f, 0xad, 0x17, 0x04, 0x84, 0x2c, 0x25, 0x0f,
+  0x99, 0xd2, 0x10, 0xcb, 0x19, 0x1a, 0xcc, 0x59, 0x6f, 0xe8, 0x17, 0x6f,
+  0xe5, 0x04, 0xb3, 0x40, 0x00, 0x02, 0x40, 0x77, 0x01, 0x1b, 0x6a, 0xb0,
+  0x55, 0xf7, 0x29, 0x1c, 0x95, 0x64, 0x42, 0xdd, 0xbf, 0x21, 0x1d, 0xa9,
+  0x43, 0x24, 0x8b, 0xfc, 0x52, 0xc0, 0xce, 0x58, 0x00, 0xf0, 0x1d, 0x19,
+  0x7d, 0x2c, 0x52, 0xfe, 0x5f, 0x3d, 0x5e, 0x94, 0x05, 0x22, 0x72, 0x87,
+  0x80, 0xb1, 0x4b, 0xb4, 0x94, 0xb2, 0x4d, 0x2f, 0x8e, 0x25, 0xbb, 0x22,
+  0x6c, 0x35, 0x03, 0x4c, 0xcd, 0x16, 0x45, 0xf2, 0x64, 0x9f, 0x82, 0x08,
+  0x78, 0x33, 0x8d, 0x1a, 0x20, 0x78, 0xbb, 0x99, 0xbf, 0xf8, 0x4e, 0x91,
+  0x76, 0x5d, 0x26, 0x18, 0x5b, 0x0c, 0xf0, 0x42, 0x6a, 0xa0, 0x71, 0xfe,
+  0xa7, 0xd2, 0x26, 0xd1, 0x69, 0x5e, 0x73, 0x42, 0x1d, 0xb0, 0x99, 0xd6,
+  0x49, 0x03, 0xe2, 0x2e, 0x1d, 0xd1, 0x86, 0x6c, 0x95, 0xf5, 0x14, 0x13,
+  0x56, 0xb5, 0x6e, 0x0a, 0xde, 0x8a, 0x28, 0x62, 0x37, 0x9d, 0x99, 0x29,
+  0xd0, 0x86, 0x14, 0x26, 0x81, 0x6a, 0xa8, 0x07, 0xbb, 0x23, 0x58, 0x54,
+  0xd7, 0x5a, 0x36, 0xef, 0xe7, 0xd8, 0x1b, 0x86, 0xba, 0x6e, 0x29, 0xe6,
+  0x9c, 0x91, 0xb8, 0x19, 0xe7, 0xb3, 0x03, 0xba, 0x1a, 0x39, 0x64, 0x34,
+  0x8f, 0x72, 0x0f, 0x2d, 0xff, 0x0d, 0x8a, 0xaf, 0x34, 0x4e, 0x31, 0xf6,
+  0x64, 0xbb, 0x5c, 0x0c, 0x66, 0x87, 0xb4, 0xd0, 0x95, 0x37, 0x98, 0x14,
+  0x48, 0x01, 0x10, 0x8d, 0x60, 0x1b, 0xd2, 0xc6, 0xe9, 0x02, 0xff, 0x3c,
+  0x01, 0xcc, 0xa5, 0x95, 0xa3, 0x42, 0x4d, 0x59, 0x00, 0x33, 0x5d, 0x38,
+  0xe7, 0x71, 0x79, 0xeb, 0xcc, 0x2b, 0xd3, 0x34, 0xb5, 0xd7, 0x61, 0xac,
+  0x14, 0xb2, 0xec, 0x52, 0x1a, 0x0e, 0x97, 0x02, 0x49, 0xed, 0xfc, 0x06,
+  0xbb, 0x7f, 0x6f, 0xfa, 0x23, 0xad, 0x6f, 0x96, 0x2e, 0xee, 0x03, 0x36,
+  0x34, 0x08, 0x4f, 0x26, 0x4f, 0xcd, 0x3e, 0x28, 0x54, 0x97, 0xbd, 0xfb,
+  0x31, 0x46, 0x1a, 0x6b, 0x9b, 0xcf, 0x2d, 0xca, 0x37, 0xab, 0x8f, 0xd6,
+  0x30, 0xc5, 0x95, 0x6d, 0xfe, 0x6f, 0xc8, 0x1b, 0x70, 0x90, 0x25, 0xb1,
+  0x92, 0x02, 0xb0, 0x9d, 0x81, 0x0e, 0x26, 0x51, 0x97, 0x60, 0xbe, 0x25,
+  0x62, 0xae, 0x5c, 0xd6, 0xbd, 0xfc, 0xca, 0xad, 0x6a, 0x6a, 0xdb, 0x4b,
+  0x19, 0x8a, 0x04, 0xce, 0x73, 0x73, 0x39, 0x22, 0x6b, 0x2f, 0x5f, 0x22,
+  0x78, 0xd6, 0xd1, 0xcb, 0xa3, 0xf0, 0x48, 0x78, 0x80, 0xb9, 0x69, 0xe4,
+  0x57, 0xdc, 0x0e, 0x47, 0x6a, 0x28, 0x94, 0x88, 0xca, 0xac, 0x83, 0x27,
+  0xbb, 0x11, 0x74, 0x74, 0xc8, 0xce, 0x11, 0x01, 0xc0, 0x0e, 0x92, 0xaf,
+  0x58, 0xf9, 0xd3, 0xae, 0xa5, 0xed, 0x81, 0x84, 0x69, 0xd5, 0xcb, 0xe3,
+  0x65, 0xc9, 0x84, 0xbb, 0x5d, 0x89, 0xe3, 0x8f, 0x98, 0x04, 0xf7, 0x06,
+  0x93, 0x9f, 0xd8, 0xb3, 0x61, 0xfe, 0xfa, 0xd2, 0x86, 0x39, 0x53, 0xed,
+  0x58, 0x0b, 0x61, 0x88, 0x46, 0x8f, 0x8f, 0x1f, 0xdf, 0x1a, 0x7a, 0x77,
+  0x06, 0x72, 0xc5, 0x6a, 0x88, 0x60, 0x2f, 0x4a, 0x60, 0xe4, 0xbe, 0xa0,
+  0x59, 0x69, 0xb0, 0xc6, 0x49, 0x7a, 0x95, 0x03, 0x0e, 0xa9, 0x60, 0x22,
+  0xa3, 0xd4, 0xc6, 0x54, 0x63, 0xdc, 0x1c, 0x5a, 0x8a, 0x25, 0x19, 0x4f,
+  0xc4, 0x8d, 0xae, 0xba, 0x9b, 0x3e, 0xe1, 0xd2, 0x27, 0x1c, 0x68, 0x87,
+  0x18, 0x06, 0x5f, 0x64, 0x25, 0xba, 0x67, 0x0e, 0xda, 0x9a, 0xb9, 0x97,
+  0x9e, 0x52, 0x32, 0x44, 0x25, 0x9a, 0xa7, 0xa3, 0xae, 0xce, 0x19, 0x6d,
+  0x33, 0x04, 0x63, 0x93, 0x14, 0x43, 0x8c, 0xaf, 0xa8, 0x4f, 0xa8, 0xe3,
+  0x53, 0x6f, 0x77, 0x4b, 0xc6, 0xd9, 0x6c, 0x02, 0x8f, 0xd8, 0x17, 0x9d,
+  0x52, 0x10, 0x2b, 0x4f, 0x92, 0x91, 0xd1, 0xa2, 0x94, 0x8f, 0xd5, 0xb9,
+  0xd2, 0xf5, 0xd9, 0xec, 0x47, 0x4f, 0x27, 0x87, 0x21, 0x6d, 0x2c, 0x81,
+  0x87, 0x07, 0xb5, 0x29, 0x26, 0x46, 0x7c, 0x47, 0x38, 0x97, 0x98, 0x13,
+  0xa2, 0xaa, 0x47, 0x9d, 0x23, 0x3c, 0x9c, 0x2d, 0x80, 0x56, 0x10, 0xb9,
+  0xbe, 0x78, 0xe8, 0x61, 0x17, 0x92, 0x8b, 0x88, 0x70, 0xf4, 0x31, 0xf0,
+  0x0c, 0x07, 0xe7, 0xbd, 0x1c, 0x34, 0xe5, 0x8e, 0x8c, 0xe8, 0xd6, 0x4e,
+  0x38, 0xef, 0x0b, 0x59, 0xf7, 0xc1, 0x5f, 0x0f, 0xa4, 0x21, 0x93, 0x90,
+  0x27, 0x80, 0x21, 0x29, 0xe5, 0x7d, 0x12, 0xfd, 0x0e, 0x27, 0x0b, 0x42,
+  0x8e, 0xcd, 0x12, 0x50, 0x96, 0x5b, 0x94, 0xa0, 0x3e, 0x29, 0xee, 0x1a,
+  0x6f, 0xc5, 0x07, 0x9a, 0xef, 0xbc, 0x9e, 0x9e, 0x8b, 0x6f, 0x99, 0x96,
+  0x78, 0x3b, 0x2c, 0xd2, 0xc5, 0x05, 0x91, 0x96, 0x5e, 0x39, 0x06, 0xb2,
+  0x0f, 0x34, 0xa5, 0x98, 0x98, 0x67, 0xd9, 0x4e, 0x92, 0xb8, 0x46, 0xc0,
+  0x7a, 0xf4, 0xf2, 0x90, 0x97, 0xcf, 0x33, 0x9e, 0x0b, 0xb7, 0xf3, 0xef,
+  0xa5, 0xa5, 0xbf, 0x97, 0xf9, 0x04, 0x46, 0xea, 0x31, 0x21, 0x94, 0x61,
+  0x19, 0x17, 0xd1, 0x9d, 0xe7, 0xfa, 0x3a, 0xaa, 0x52, 0x55, 0x46, 0x72,
+  0x1b, 0x97, 0xd9, 0x6b, 0x5e, 0x3d, 0x15, 0x83, 0x55, 0x01, 0x95, 0x52,
+  0x27, 0xd1, 0x0c, 0x41, 0x90, 0x67, 0x44, 0x7d, 0x4f, 0xd8, 0x7a, 0x3e,
+  0x9f, 0xae, 0xc3, 0x00, 0x86, 0xc3, 0xc2, 0x06, 0xd8, 0x99, 0xb4, 0xfc,
+  0x00, 0xbf, 0x8e, 0xa3, 0x0c, 0xf9, 0x14, 0x48, 0x2a, 0xb0, 0x5e, 0xf8,
+  0xfe, 0x6b, 0x83, 0x13, 0xaa, 0x94, 0xd0, 0x62, 0x9b, 0xbb, 0xa7, 0x33,
+  0x26, 0x18, 0xca, 0x60, 0x48, 0x0c, 0x5c, 0xe3, 0x13, 0x94, 0x24, 0xfe,
+  0x00, 0xf3, 0x1f, 0xa2, 0x2f, 0xae, 0x49, 0x92, 0xe7, 0xf6, 0x49, 0x1e,
+  0xf7, 0x57, 0x4c, 0xe5, 0x4c, 0x5f, 0x8c, 0xa3, 0xdc, 0x70, 0xbe, 0x5b,
+  0x8c, 0x3c, 0xdb, 0xd3, 0x84, 0x02, 0x6e, 0xdc, 0xd5, 0x6a, 0xc9, 0xc2,
+  0x5f, 0x95, 0x3a, 0x2d, 0x44, 0x87, 0x09, 0x52, 0x90, 0x41, 0x1f, 0xa8,
+  0x93, 0x76, 0xae, 0x53, 0xd3, 0xef, 0x26, 0x15, 0x27, 0x38, 0x04, 0xc7,
+  0xda, 0xed, 0xb1, 0x11, 0xe8, 0x2a, 0x67, 0x03, 0xd0, 0xfe, 0x5f, 0x85,
+  0xfc, 0xa0, 0x6a, 0x73, 0x6e, 0xac, 0x15, 0x8d, 0xa2, 0xca, 0x5b, 0x32,
+  0x52, 0xc1, 0x2e, 0xf4, 0xe6, 0x68, 0x99, 0xbd, 0xeb, 0x05, 0x4e, 0x8f,
+  0xb7, 0x5c, 0xd1, 0x31, 0x5b, 0x17, 0x98, 0x81, 0xef, 0x69, 0x3d, 0x23,
+  0x01, 0xc3, 0x34, 0xc7, 0x69, 0x39, 0x5e, 0xb3, 0x1e, 0x99, 0xa6, 0xbf,
+  0x78, 0xee, 0x88, 0xe2, 0xdb, 0xd7, 0x4e, 0x17, 0xa0, 0x27, 0x0f, 0xe6,
+  0x9f, 0x9f, 0x74, 0x0c, 0xa4, 0xd2, 0x47, 0xe3, 0xc1, 0xb5, 0xc9, 0x13,
+  0xaa, 0x72, 0x22, 0xbb, 0x7d, 0xd6, 0xb8, 0x76, 0x6c, 0x5e, 0xd5, 0xf7,
+  0x22, 0x69, 0x7c, 0x40, 0x4f, 0x64, 0xcd, 0x02, 0x43, 0x4a, 0x09, 0x1d,
+  0x95, 0x90, 0x16, 0x3f, 0xaa, 0x4d, 0xdf, 0x5d, 0xea, 0x76, 0xb0, 0x52,
+  0x92, 0xa1, 0xde, 0xd6, 0x2f, 0x66, 0x7d, 0x53, 0x65, 0xb4, 0xa6, 0x3e,
+  0x0a, 0x85, 0x03, 0x56, 0x82, 0x6f, 0x17, 0xe6, 0xb6, 0xef, 0x0f, 0x4e,
+  0x01, 0xc5, 0xba, 0x01, 0xdb, 0x23, 0x4c, 0x9f, 0x11, 0x59, 0x28, 0x71,
+  0xc4, 0xf2, 0xeb, 0x00, 0xa9, 0x72, 0x7b, 0xd7, 0x02, 0x94, 0xd8, 0xaf,
+  0xad, 0x16, 0x92, 0x51, 0xea, 0xe4, 0xb6, 0xf6, 0xe1, 0x80, 0xaf, 0x6b,
+  0x0d, 0x2c, 0xbc, 0x6f, 0xb4, 0x0c, 0xa9, 0xd4, 0xf8, 0xb8, 0x19, 0xc5,
+  0x69, 0x5d, 0x8f, 0xce, 0x4b, 0x98, 0x11, 0xae, 0x66, 0x19, 0x66, 0x6e,
+  0xe5, 0x88, 0xc9, 0x23, 0xf5, 0xc6, 0x3d, 0x52, 0x4d, 0x5a, 0x6d, 0x5e,
+  0xdc, 0x00, 0x21, 0x41, 0x53, 0xab, 0x97, 0x3d, 0xa3, 0xfb, 0xd9, 0xdf,
+  0x90, 0x77, 0xeb, 0x4f, 0x8d, 0xec, 0xca, 0x17, 0xad, 0x65, 0xb9, 0x92,
+  0x0c, 0x24, 0xd4, 0x80, 0x19, 0x78, 0x49, 0x7d, 0x9b, 0xcf, 0xdd, 0xaf,
+  0xfd, 0xb8, 0xdd, 0x89, 0x4b, 0xe5, 0xb9, 0x99, 0x9b, 0x70, 0x24, 0xc5,
+  0x86, 0x42, 0x92, 0x2c, 0x47, 0xd5, 0x1a, 0x50, 0x5d, 0x4d, 0xcf, 0xdc,
+  0xb4, 0x19, 0x9a, 0xe2, 0x94, 0x5f, 0x1b, 0x19, 0x40, 0xd3, 0x5c, 0xe3,
+  0x09, 0xe3, 0x7c, 0x15, 0x60, 0x49, 0xf7, 0xf9, 0xdb, 0x8e, 0x38, 0x69,
+  0xfa, 0xa2, 0xe6, 0x18, 0x11, 0xc3, 0x57, 0xa0, 0xec, 0x1b, 0x43, 0x3a,
+  0xb1, 0x5a, 0x6a, 0xcd, 0x5a, 0x2e, 0x59, 0x10, 0x8b, 0xc1, 0xfc, 0xbd,
+  0x75, 0xc9, 0x5e, 0x5c, 0xe2, 0x28, 0xb8, 0x72, 0xbc, 0xb3, 0x8a, 0x5e,
+  0x82, 0x32, 0x50, 0xa3, 0xe0, 0x77, 0xf6, 0xe0, 0x46, 0xbe, 0xda, 0x52,
+  0xa5, 0x13, 0xa5, 0x99, 0xcd, 0xc3, 0x55, 0x31, 0x83, 0x10, 0x72, 0xa3,
+  0x2d, 0x14, 0x49, 0xda, 0x57, 0x81, 0xd7, 0x7f, 0xbd, 0x29, 0x6d, 0xb8,
+  0x21, 0xe4, 0x4b, 0x58, 0x99, 0x74, 0x84, 0xef, 0x77, 0xd6, 0x92, 0xe0,
+  0x81, 0xe1, 0xc0, 0x3c, 0x10, 0x81, 0xf9, 0xa9, 0xaa, 0x63, 0x74, 0x98,
+  0x91, 0xa8, 0x72, 0x16, 0xa6, 0xf3, 0xf9, 0x89, 0xe4, 0xe6, 0x48, 0xac,
+  0x50, 0x65, 0x11, 0x4c, 0xef, 0xfe, 0xcf, 0x89, 0xd3, 0x9f, 0xc1, 0xfc,
+  0xdc, 0xea, 0x75, 0x19, 0xc7, 0xd0, 0x12, 0xaf, 0x20, 0x64, 0x82, 0x08,
+  0x8e, 0xc8, 0x0f, 0x15, 0x51, 0x7b, 0xe2, 0x6b, 0xb0, 0x1c, 0xcd, 0xad,
+  0xd1, 0x77, 0x2d, 0xad, 0xa0, 0xec, 0x81, 0xa7, 0xa8, 0x28, 0xcd, 0xb1,
+  0xcc, 0xa5, 0x43, 0xc4, 0x5b, 0xb8, 0x9c, 0x84, 0xa5, 0x2c, 0xac, 0xba,
+  0xc0, 0x2a, 0x61, 0xc7, 0xf1, 0xb6, 0x57, 0x56, 0xe5, 0xca, 0x96, 0xbb,
+  0xfb, 0x8e, 0x49, 0x3e, 0x50, 0x2f, 0x36, 0x73, 0x5b, 0x44, 0x5b, 0x36,
+  0x9c, 0xa0, 0x90, 0xc6, 0x96, 0x4e, 0x73, 0x1f, 0x68, 0x47, 0x43, 0xd3,
+  0x6b, 0x1f, 0x4d, 0x43, 0x1e, 0xbf, 0x1c, 0x28, 0xe9, 0xf5, 0x3d, 0xac,
+  0x48, 0x4c, 0xd4, 0x6d, 0x32, 0x25, 0xf3, 0x71, 0x29, 0xe9, 0xf0, 0x08,
+  0x2a, 0xd2, 0x75, 0xc1, 0xa6, 0x5f, 0x1f, 0xca, 0xbb, 0x76, 0x91, 0xdc,
+  0xca, 0x13, 0x3b, 0x18, 0xd9, 0x66, 0x48, 0xb0, 0x29, 0x01, 0x39, 0xfd,
+  0x35, 0x8b, 0xd7, 0xac, 0xeb, 0xe3, 0x92, 0x96, 0xef, 0xe1, 0x7e, 0xd7,
+  0xd0, 0xe9, 0xd6, 0xcf, 0xd7, 0x28, 0x58, 0x0a, 0x20, 0xcc, 0xc1, 0x8a,
+  0x45, 0x45, 0xe0, 0x71, 0xca, 0x66, 0x75, 0xb0, 0x97, 0x89, 0x13, 0x7b,
+  0xa3, 0x27, 0x5d, 0xce, 0x36, 0x58, 0xf6, 0x0a, 0x66, 0xf5, 0x83, 0xc8,
+  0xef, 0x6e, 0x6f, 0x98, 0x79, 0x52, 0xd7, 0xd4, 0xa3, 0x3f, 0xda, 0x70,
+  0xe2, 0x41, 0x10, 0x55, 0x20, 0x71, 0xb0, 0xd8, 0xd9, 0x14, 0x19, 0xc6,
+  0x76, 0x0d, 0x45, 0x78, 0xb5, 0x70, 0x88, 0x65, 0x5a, 0x6b, 0xeb, 0x2f,
+  0x28, 0x38, 0xf9, 0xbc, 0x28, 0xbe, 0xca, 0x44, 0x86, 0x4e, 0xd4, 0x29,
+  0xc6, 0x16, 0xca, 0x3e, 0xb7, 0x33, 0x58, 0x04, 0x33, 0x7c, 0xac, 0xb5,
+  0x9f, 0xf9, 0xfd, 0x6d, 0xb9, 0xff, 0x5a, 0x35, 0xa6, 0xd8, 0xa5, 0x28,
+  0x30, 0xf5, 0x16, 0x95, 0xa9, 0x14, 0x65, 0x97, 0x56, 0x01, 0x4d, 0xf8,
+  0x71, 0xc9, 0x93, 0xad, 0xac, 0x97, 0x1d, 0xab, 0x70, 0x21, 0x2d, 0xf3,
+  0x26, 0x16, 0x66, 0xcb, 0xa2, 0x67, 0x56, 0x09, 0xd9, 0x9d, 0x9c, 0xec,
+  0x37, 0x4d, 0x71, 0xbd, 0xef, 0xaf, 0x22, 0x78, 0xd9, 0x4c, 0xdd, 0xab,
+  0x9a, 0x12, 0x28, 0x7d, 0xb4, 0xd4, 0x9c, 0x01, 0xf2, 0x85, 0x2f, 0xbc,
+  0x58, 0x77, 0x85, 0x32, 0xdf, 0x4e, 0x79, 0x41, 0x41, 0xda, 0x6e, 0x9f,
+  0x60, 0x09, 0x82, 0xf4, 0x50, 0x15, 0x68, 0x0f, 0xfd, 0x0b, 0x5b, 0x09,
+  0x33, 0x98, 0x9c, 0x92, 0x1d, 0xc1, 0x38, 0xbe, 0xdc, 0x17, 0xbe, 0x88,
+  0xa8, 0xa6, 0x88, 0xa2, 0x0f, 0x81, 0xcd, 0xb6, 0xde, 0x42, 0xc7, 0x7d,
+  0x53, 0xc6, 0xab, 0xd3, 0x94, 0x9d, 0x2e, 0x79, 0x2f, 0x0b, 0x76, 0x63,
+  0x36, 0xa5, 0x85, 0x7f, 0x94, 0x07, 0x53, 0xe7, 0xa8, 0x6a, 0x0d, 0xb1,
+  0xda, 0x1f, 0xad, 0xb6, 0x5b, 0x13, 0xe7, 0x21, 0xcc, 0xe7, 0x29, 0x09,
+  0x48, 0x1a, 0x19, 0x7e, 0x22, 0x1b, 0x1b, 0xe5, 0xf2, 0x1a, 0x08, 0x25,
+  0x30, 0xca, 0xf1, 0xd6, 0x97, 0x56, 0x3a, 0xa7, 0x3f, 0x0b, 0xce, 0xaf,
+  0xfc, 0x50, 0x24, 0x34, 0xab, 0xf0, 0x9c, 0x91, 0x12, 0xc0, 0x4f, 0xd5,
+  0xed, 0xa4, 0xf4, 0xe4, 0x36, 0x54, 0x49, 0xed, 0x36, 0x61, 0x6d, 0xa4,
+  0x1e, 0x63, 0x24, 0x3c, 0x40, 0xb0, 0xb2, 0x44, 0xe3, 0x6d, 0xf2, 0xa6,
+  0x96, 0x97, 0xe9, 0x97, 0xd4, 0x76, 0x80, 0x0c, 0x6d, 0xa8, 0xb1, 0x39,
+  0x48, 0x48, 0x7c, 0x1b, 0x46, 0x9e, 0x94, 0x7a, 0xbf, 0xfd, 0xc6, 0xff,
+  0x72, 0xf0, 0x4d, 0x4b, 0x22, 0x46, 0x32, 0x8e, 0x51, 0x23, 0xe7, 0xb2,
+  0xe7, 0xa7, 0x05, 0x38, 0xb9, 0x25, 0xcc, 0xe2, 0xbf, 0x08, 0xff, 0x77,
+  0xf9, 0xb6, 0x37, 0xcd, 0x29, 0x47, 0xc3, 0x10, 0xe4, 0xc9, 0xd5, 0xaa,
+  0x41, 0xe8, 0x6c, 0x6d, 0x17, 0xa2, 0x8a, 0x08, 0xcc, 0xde, 0xa3, 0xcb,
+  0xeb, 0x66, 0x86, 0x2c, 0x0b, 0xd3, 0xeb, 0xb3, 0x4b, 0x9e, 0x64, 0x70,
+  0xf3, 0xa2, 0x8e, 0x30, 0x14, 0x32, 0x09, 0xea, 0xbd, 0x57, 0x4b, 0x6b,
+  0x1e, 0xa3, 0x12, 0x01, 0xc2, 0x46, 0x65, 0x23, 0xe9, 0xac, 0x21, 0xb2,
+  0xba, 0x60, 0xef, 0x6e, 0xa8, 0x32, 0x16, 0x1b, 0x69, 0x41, 0x23, 0x93,
+  0xfb, 0x48, 0x7a, 0xb3, 0xe2, 0xab, 0x9b, 0x1a, 0x44, 0xce, 0x8a, 0x35,
+  0xfc, 0x87, 0x3e, 0xe4, 0xa5, 0xec, 0xcf, 0x98, 0x04, 0x32, 0xc2, 0x32,
+  0x4b, 0x48, 0x96, 0xed, 0x6a, 0xd1, 0xca, 0x3a, 0xf0, 0xb9, 0x32, 0x14,
+  0xe3, 0x11, 0x23, 0x87, 0x09, 0x49, 0x59, 0x20, 0x6b, 0x3a, 0xb7, 0xc5,
+  0xa7, 0xb3, 0x86, 0xd1, 0x87, 0x0d, 0xcf, 0x04, 0x92, 0x2a, 0x87, 0xa4,
+  0x36, 0xc9, 0x03, 0x3f, 0x05, 0x2f, 0x39, 0xad, 0xfb, 0xbb, 0x25, 0x0c,
+  0xbe, 0x23, 0xe4, 0x18, 0x1c, 0x24, 0x71, 0xd1, 0x6c, 0xba, 0x6a, 0xba,
+  0xa6, 0xa7, 0x93, 0x08, 0x43, 0x92, 0x13, 0xfa, 0x02, 0xe0, 0x0e, 0xf6,
+  0x26, 0x20, 0x11, 0x5c, 0x4f, 0x54, 0xc0, 0xb2, 0x0b, 0x5e, 0x79, 0x41,
+  0xd9, 0x03, 0xd8, 0x4f, 0xb4, 0x60, 0xf7, 0x2c, 0xbd, 0xd8, 0xcd, 0xdd,
+  0x19, 0xee, 0x46, 0x5f, 0x44, 0x2b, 0x57, 0x3f, 0xe3, 0x6b, 0x41, 0x4b,
+  0x63, 0x19, 0x2b, 0x69, 0xb3, 0xe4, 0x14, 0xe0, 0xfc, 0x70, 0x6f, 0xc5,
+  0x9e, 0xe2, 0x56, 0xfe, 0x62, 0xc7, 0x2b, 0x68, 0x43, 0x34, 0xb0, 0xf8,
+  0x71, 0xd9, 0x0e, 0xbd, 0x20, 0x29, 0x83, 0xf1, 0xfe, 0xed, 0xec, 0xd5,
+  0xeb, 0x12, 0xc9, 0x13, 0x9d, 0x1f, 0xb4, 0xce, 0x39, 0xd8, 0x15, 0xa9,
+  0x6c, 0x24, 0x8d, 0x6f, 0xc5, 0x0a, 0x0c, 0xa2, 0x7e, 0x29, 0x67, 0xf1,
+  0x3a, 0xf8, 0xd6, 0xd0, 0x3b, 0x28, 0x30, 0x94, 0x0c, 0x28, 0x77, 0x06,
+  0x79, 0x3f, 0xfc, 0x67, 0xf2, 0x76, 0x8b, 0xb5, 0xc0, 0x4a, 0x1a, 0x79,
+  0x9c, 0x04, 0xef, 0xc1, 0x61, 0x0e, 0xe9, 0xe0, 0xf3, 0x4a, 0x03, 0x00,
+  0xf1, 0x4a, 0xa6, 0x66, 0x51, 0x53, 0x76, 0x35, 0x72, 0xc7, 0x59, 0x4b,
+  0x34, 0x34, 0xc9, 0x1d, 0x91, 0x21, 0x1a, 0x5f, 0xb6, 0x81, 0x9e, 0x7a,
+  0x62, 0x4a, 0xb8, 0x54, 0xb7, 0xdf, 0xe7, 0xd7, 0xb0, 0x5f, 0xa8, 0x1c,
+  0x93, 0xae, 0x94, 0x3d, 0x82, 0x83, 0xe7, 0x9c, 0x50, 0x79, 0xa5, 0x03,
+  0xf2, 0x3f, 0x19, 0xd7, 0x3f, 0x5f, 0x33, 0xf1, 0x5b, 0x65, 0x03, 0x4d,
+  0x40, 0x88, 0x66, 0x67, 0x3f, 0x16, 0x8e, 0x7c, 0x4f, 0xd6, 0x15, 0xb3,
+  0x1d, 0xed, 0x86, 0xc7, 0x2b, 0x82, 0x4e, 0x4e, 0xc1, 0x9b, 0x25, 0xc1,
+  0xf5, 0x3f, 0x6e, 0xde, 0xbd, 0x23, 0x44, 0xa1, 0xb4, 0x84, 0xfb, 0x0a,
+  0x95, 0x59, 0x57, 0x60, 0x73, 0x54, 0xcf, 0x4d, 0x2d, 0x5d, 0x8d, 0xc3,
+  0xc8, 0x2a, 0x98, 0x7d, 0xb2, 0x59, 0x94, 0xe6, 0x90, 0x43, 0xed, 0xa2,
+  0xc2, 0x13, 0x33, 0xf5, 0xee, 0x21, 0x72, 0x82, 0xaa, 0x33, 0xfc, 0x92,
+  0x15, 0xc1, 0xf6, 0xef, 0x7d, 0xdf, 0x25, 0x8a, 0xbe, 0x36, 0xe8, 0x69,
+  0x91, 0x42, 0x93, 0x4f, 0x1d, 0xc4, 0x92, 0xa5, 0xf3, 0xc1, 0x5d, 0x3d,
+  0x1b, 0x36, 0xd7, 0xc4, 0x35, 0x7d, 0xe5, 0x02, 0x5b, 0xca, 0x8f, 0xcc,
+  0x0c, 0x86, 0x7b, 0x20, 0xbc, 0xc2, 0xc1, 0x6f, 0x5a, 0x7c, 0xfe, 0x66,
+  0x6d, 0xeb, 0x5e, 0xa5, 0xba, 0xbe, 0x26, 0xd3, 0xda, 0xe8, 0x51, 0x26,
+  0x57, 0xac, 0xcf, 0x3f, 0x86, 0x1d, 0x38, 0x71, 0xa4, 0x35, 0x70, 0xe9,
+  0x50, 0x02, 0x72, 0xc2, 0x22, 0x79, 0x78, 0xeb, 0x7d, 0xcf, 0xc7, 0x87,
+  0xbc, 0x7e, 0xc7, 0x1c, 0x8d, 0x13, 0x44, 0xf3, 0xd0, 0x8a, 0x25, 0xf6,
+  0xf7, 0x3c, 0xd9, 0x6f, 0xf2, 0x37, 0x9e, 0xad, 0x33, 0x43, 0x86, 0x40,
+  0x4e, 0x90, 0x92, 0x33, 0x8c, 0x49, 0x90, 0x26, 0xf5, 0x25, 0x7d, 0xfe,
+  0xf7, 0x16, 0x7e, 0x57, 0xef, 0xde, 0x6f, 0x2f, 0x93, 0xbe, 0x57, 0xda,
+  0xae, 0x04, 0x35, 0x40, 0xcc, 0x4d, 0x72, 0x03, 0x2b, 0xb8, 0x1a, 0xfb,
+  0xda, 0x1b, 0xb6, 0xff, 0x86, 0x6b, 0x76, 0xa6, 0xee, 0x71, 0xdd, 0xe8,
+  0x10, 0xd8, 0x00, 0x94, 0x00, 0xa4, 0x6b, 0x00, 0x46, 0xd3, 0x8d, 0x16,
+  0x64, 0x4c, 0x21, 0xd5, 0xc0, 0xca, 0x64, 0x44, 0xd2, 0xe6, 0xee, 0x4f,
+  0xc4, 0xfa, 0x35, 0x45, 0x64, 0xc5, 0x51, 0xa8, 0x7c, 0x14, 0x77, 0xeb,
+  0x97, 0x87, 0x0b, 0xae, 0x1d, 0x9c, 0x6e, 0x0d, 0xba, 0xb8, 0xa8, 0x8c,
+  0xc8, 0x97, 0xd7, 0xb5, 0x43, 0xf3, 0x6b, 0x2d, 0x86, 0xdd, 0x01, 0xf6,
+  0x07, 0xde, 0x7d, 0x7f, 0xb7, 0x3c, 0xe2, 0x30, 0x6b, 0x98, 0x99, 0xce,
+  0xa6, 0xcb, 0x18, 0xa4, 0xa7, 0x3b, 0xc9, 0x62, 0xb9, 0x61, 0x3c, 0x87,
+  0xe0, 0x7f, 0x85, 0x0f, 0xda, 0x1f, 0x83, 0x76, 0x6e, 0x9c, 0x53, 0x95,
+  0x0c, 0x75, 0xe3, 0xc2, 0x90, 0x91, 0x96, 0x54, 0x87, 0x70, 0xcf, 0xb6,
+  0x84, 0xe2, 0xbe, 0x31, 0xe5, 0x4a, 0x79, 0x00, 0x4a, 0x25, 0x06, 0x54,
+  0x19, 0x39, 0x4d, 0x14, 0x28, 0xfd, 0x71, 0x91, 0xa2, 0x69, 0xee, 0x2b,
+  0xa2, 0x88, 0x97, 0x37, 0x4f, 0x3e, 0xfa, 0xb7, 0x2a, 0x41, 0x55, 0x10,
+  0xdf, 0xc4, 0x24, 0xfc, 0xde, 0xa9, 0x45, 0x74, 0xb5, 0xb9, 0xee, 0xef,
+  0xd7, 0xb3, 0x8d, 0xc3, 0x41, 0x0c, 0xe8, 0x23, 0x5e, 0x41, 0x29, 0x83,
+  0x23, 0x90, 0xc9, 0xf1, 0x54, 0x0e, 0xb8, 0xbf, 0x95, 0x5a, 0x28, 0x2c,
+  0x5d, 0xd2, 0xd6, 0x50, 0x60, 0x5b, 0x1d, 0xbe, 0x64, 0x4d, 0x10, 0x28,
+  0x92, 0x87, 0x88, 0x7d, 0x3f, 0x8d, 0xaf, 0xfc, 0x0f, 0x0c, 0x00, 0xa3,
+  0x29, 0xd2, 0x10, 0x8b, 0xd9, 0x14, 0xb8, 0x3b, 0x81, 0x76, 0x64, 0xc2,
+  0x97, 0xbe, 0x6f, 0x92, 0x61, 0x8b, 0xb7, 0x05, 0xbd, 0x3e, 0x6d, 0x54,
+  0x50, 0x0c, 0x87, 0x95, 0x97, 0xf4, 0x49, 0x2d, 0x06, 0xac, 0xb8, 0xa9,
+  0x31, 0xd3, 0x76, 0x92, 0x4a, 0xa3, 0xd9, 0x1f, 0xf4, 0x08, 0xd9, 0x29,
+  0x49, 0xa9, 0xe3, 0x65, 0xee, 0x68, 0x60, 0x12, 0x97, 0xcc, 0xfc, 0xe1,
+  0x5d, 0x26, 0xcc, 0xbe, 0xa8, 0x4e, 0xdd, 0x9a, 0x28, 0x21, 0xc3, 0x41,
+  0x2f, 0x8a, 0x4e, 0x60, 0xb7, 0x03, 0x8c, 0x1f, 0x6f, 0x05, 0x5e, 0x99,
+  0x73, 0x33, 0x43, 0xd2, 0xe7, 0x22, 0x75, 0xbc, 0x98, 0xe0, 0x34, 0x7e,
+  0x2c, 0xb0, 0x0f, 0xa9, 0xee, 0xbc, 0x82, 0xa8, 0x1d, 0xa0, 0xd0, 0x95,
+  0x5e, 0xa1, 0x33, 0x95, 0xf4, 0xdb, 0xe0, 0xf5, 0x3c, 0x1c, 0xa4, 0x5e,
+  0x12, 0x08, 0x40, 0x7c, 0xc6, 0x12, 0x22, 0xb3, 0x6d, 0x81, 0xa2, 0x88,
+  0xac, 0x97, 0x6f, 0x2a, 0xc9, 0xd6, 0xde, 0x6b, 0xb6, 0x02, 0x58, 0x18,
+  0x40, 0xc7, 0x92, 0x06, 0x63, 0x26, 0x11, 0x98, 0xf1, 0x05, 0x50, 0x73,
+  0x37, 0x4c, 0xcf, 0x8e, 0x77, 0xe6, 0x0f, 0x6e, 0x4f, 0x36, 0x5e, 0x7a,
+  0x94, 0xd1, 0x13, 0xa5, 0xb1, 0x22, 0x0c, 0x20, 0xa1, 0x97, 0x8c, 0x7e,
+  0xcb, 0xf9, 0xfa, 0x17, 0x4a, 0x4a, 0x40, 0x5e, 0xef, 0xe6, 0x48, 0x6c,
+  0x3b, 0x18, 0xca, 0x2c, 0x67, 0x91, 0x09, 0x85, 0x6a, 0xcd, 0xdd, 0xdb,
+  0xdb, 0x82, 0x07, 0xa7, 0x57, 0xa2, 0x42, 0x84, 0xf8, 0xe7, 0xd2, 0xbe,
+  0x8b, 0x80, 0xe4, 0xda, 0x07, 0x4e, 0xcc, 0x11, 0xc9, 0xf6, 0x5f, 0x5e,
+  0x22, 0xcd, 0xf3, 0x82, 0xa9, 0x6d, 0x7a, 0xc4, 0x26, 0x70, 0xec, 0x1d,
+  0x6a, 0x79, 0x7f, 0x37, 0x28, 0x88, 0x1a, 0x53, 0x84, 0xf8, 0x00, 0xad,
+  0x47, 0x7b, 0xfe, 0x19, 0xc9, 0xac, 0xab, 0x55, 0x76, 0xde, 0x4b, 0x6d,
+  0x6f, 0x2e, 0x77, 0xca, 0xd7, 0x4e, 0x73, 0x18, 0xcd, 0xc3, 0x41, 0xac,
+  0x39, 0x9a, 0x22, 0xac, 0xbf, 0xd2, 0xc0, 0xec, 0x4c, 0x54, 0xfb, 0xb9,
+  0x76, 0x39, 0xd4, 0xcf, 0x63, 0xd6, 0xd6, 0x3c, 0xfe, 0x6f, 0xc0, 0x22,
+  0xc0, 0x14, 0x36, 0xb8, 0x02, 0x19, 0x1e, 0x6a, 0x8b, 0xa3, 0x39, 0x78,
+  0x1a, 0x82, 0x9e, 0x78, 0xf6, 0x58, 0xdb, 0x2e, 0x0a, 0x70, 0xc3, 0xa7,
+  0x45, 0x41, 0x19, 0x8d, 0xca, 0x91, 0xed, 0x28, 0x12, 0x8c, 0xbb, 0x91,
+  0xbd, 0xb3, 0xf0, 0x6a, 0xff, 0x79, 0x7f, 0xdf, 0xbc, 0x03, 0x6c, 0x4f,
+  0x05, 0xe1, 0xaf, 0x39, 0x14, 0x37, 0x08, 0xbd, 0xd8, 0xa5, 0x3a, 0x0d,
+  0xe2, 0x65, 0xdd, 0x9f, 0x80, 0x0c, 0xca, 0xd2, 0x19, 0x36, 0x1d, 0x84,
+  0xfa, 0xa0, 0xa7, 0xb3, 0x26, 0x14, 0x4e, 0x53, 0xb5, 0x98, 0x15, 0x7b,
+  0x53, 0x55, 0xc7, 0x55, 0x59, 0x65, 0xf7, 0xf9, 0xb5, 0x6b, 0x96, 0x59,
+  0x7d, 0xb6, 0xf2, 0xab, 0x6f, 0x4e, 0x48, 0xa1, 0x30, 0x18, 0x01, 0x2a,
+  0x3e, 0x20, 0x3a, 0xc6, 0x6d, 0x2a, 0x23, 0x0d, 0x17, 0x3d, 0x66, 0x30,
+  0xe5, 0xe5, 0xac, 0x86, 0x84, 0x08, 0x01, 0x7a, 0xcc, 0xed, 0xf9, 0xfa,
+  0x83, 0xcf, 0x09, 0x95, 0xdf, 0xf8, 0xed, 0x8c, 0x12, 0x7d, 0xf0, 0xcc,
+  0x3e, 0x35, 0xfe, 0x10, 0x50, 0xed, 0x35, 0xcc, 0x8a, 0x13, 0x18, 0x67,
+  0x22, 0x79, 0x04, 0xd8, 0x43, 0xd2, 0x38, 0xb3, 0xe8, 0x4c, 0x57, 0x6b,
+  0xab, 0xfa, 0x95, 0x4e, 0x2c, 0x5e, 0x14, 0x0e, 0x7e, 0x06, 0xd6, 0x7d,
+  0xcd, 0xe9, 0xb7, 0xbb, 0x8b, 0x76, 0x35, 0xe5, 0xf1, 0x87, 0x6c, 0x92,
+  0x2c, 0x44, 0x8e, 0x59, 0xa3, 0x84, 0x27, 0x55, 0xaa, 0xe7, 0x8a, 0xda,
+  0x3a, 0x08, 0xa3, 0x3c, 0x94, 0x69, 0x07, 0x98, 0xf9, 0x33, 0x0a, 0xe8,
+  0xfe, 0xfd, 0x7e, 0x55, 0x0c, 0x5b, 0x81, 0xba, 0x56, 0xb4, 0x86, 0xd9,
+  0xca, 0x80, 0xc8, 0x12, 0xe8, 0x83, 0x8d, 0x51, 0x04, 0xb9, 0xcf, 0xe8,
+  0x0f, 0x34, 0x97, 0xe7, 0x3b, 0xab, 0xaf, 0x85, 0x7f, 0x6f, 0x38, 0x1e,
+  0x7b, 0xd8, 0x54, 0x31, 0xa7, 0x82, 0x4f, 0x2c, 0xa0, 0xff, 0x18, 0x73,
+  0x8f, 0xbc, 0x57, 0xfe, 0x8f, 0x7f, 0xe5, 0x34, 0xfa, 0x16, 0x59, 0xa5,
+  0x36, 0x3c, 0x01, 0x22, 0x89, 0x33, 0x99, 0x73, 0x93, 0xf1, 0x6b, 0x99,
+  0xe3, 0xaa, 0xab, 0xf0, 0x37, 0x21, 0x09, 0xb2, 0x5d, 0x5a, 0x61, 0x89,
+  0xb9, 0x62, 0xaf, 0x90, 0x3f, 0x8a, 0x42, 0x9d, 0x6b, 0x41, 0x86, 0x00,
+  0x51, 0x78, 0x28, 0x41, 0x37, 0x35, 0x84, 0x73, 0xc6, 0x1e, 0x42, 0x52,
+  0x91, 0x4a, 0x93, 0xce, 0x78, 0x0a, 0x08, 0x51, 0xec, 0x92, 0x15, 0x48,
+  0x58, 0xe4, 0x94, 0x48, 0xbb, 0x8b, 0xd7, 0xf6, 0x5b, 0xac, 0x69, 0x5f,
+  0x9a, 0x9d, 0x6c, 0xd9, 0x8e, 0xef, 0xb0, 0x71, 0xf8, 0x1a, 0xc4, 0xa8,
+  0x90, 0x93, 0xec, 0x1a, 0x66, 0xbd, 0x29, 0x0f, 0xa9, 0xce, 0xf1, 0x65,
+  0xb2, 0xc7, 0xb4, 0x4a, 0x92, 0x3d, 0x94, 0xcb, 0xae, 0x15, 0xc8, 0x99,
+  0x44, 0x6d, 0x82, 0x00, 0x89, 0x20, 0x96, 0x97, 0x38, 0xd0, 0x5b, 0x8e,
+  0xfa, 0x6d, 0x6a, 0x40, 0xa0, 0x72, 0xb2, 0x92, 0x27, 0xb5, 0xbc, 0x34,
+  0x50, 0xfa, 0x5f, 0x1a, 0xfa, 0xe5, 0xdd, 0x75, 0x76, 0xb7, 0x7c, 0x19,
+  0xbb, 0xe2, 0x89, 0x31, 0xab, 0xc9, 0x59, 0x72, 0x19, 0x7f, 0x3e, 0x60,
+  0x9c, 0x8d, 0x4d, 0xdf, 0x90, 0xea, 0xcb, 0x65, 0xca, 0x03, 0x96, 0x59,
+  0x22, 0x32, 0x8c, 0xfc, 0x0c, 0x97, 0x1f, 0x39, 0x75, 0xff, 0xd1, 0x79,
+  0x9b, 0xce, 0x89, 0xd2, 0xe5, 0x8d, 0x04, 0xf0, 0xe2, 0x59, 0x48, 0xd0,
+  0xf9, 0xc3, 0xbe, 0xee, 0x58, 0x06, 0xb7, 0xe6, 0xd1, 0x80, 0x6b, 0x13,
+  0xb4, 0x41, 0x11, 0x06, 0x51, 0x8c, 0x66, 0xf9, 0x7e, 0x34, 0x07, 0xc1,
+  0x4f, 0xfe, 0x9b, 0x31, 0xdf, 0x1e, 0x62, 0x44, 0xe7, 0x26, 0xc6, 0xa2,
+  0x28, 0x25, 0x22, 0x28, 0xf8, 0x8d, 0xad, 0x27, 0x0b, 0xc7, 0x78, 0x01,
+  0x82, 0x8c, 0x15, 0xe7, 0x96, 0x55, 0x1c, 0x63, 0xf1, 0xcc, 0x5d, 0xba,
+  0x89, 0xbf, 0x1a, 0xd9, 0x98, 0xaf, 0xa1, 0x87, 0x6c, 0x8c, 0x86, 0xf4,
+  0x4f, 0xc7, 0xf3, 0x13, 0x7c, 0x94, 0x5d, 0x95, 0x46, 0xbf, 0xad, 0x0d,
+  0x9d, 0x3c, 0xe8, 0x12, 0x88, 0x99, 0x92, 0x5a, 0x15, 0x62, 0x50, 0xdb,
+  0x67, 0x7a, 0xf3, 0x53, 0x6d, 0x5a, 0xd2, 0x12, 0x2f, 0x2e, 0xd0, 0x50,
+  0x22, 0x8c, 0x3f, 0x3b, 0x45, 0x54, 0x5c, 0x54, 0x35, 0xe7, 0xb3, 0x78,
+  0xf5, 0x10, 0x53, 0x38, 0xd8, 0xa1, 0x5f, 0x28, 0xe4, 0xc1, 0xf0, 0x66,
+  0x54, 0x56, 0xdb, 0xed, 0xff, 0xd3, 0x60, 0x08, 0x41, 0xb5, 0xa0, 0x41,
+  0x8c, 0x51, 0x96, 0x60, 0x0e, 0x3a, 0x5a, 0xf0, 0x13, 0xbc, 0x49, 0xd5,
+  0xf9, 0xd7, 0xcf, 0xcc, 0x04, 0x20, 0x97, 0x64, 0x1a, 0xe6, 0x36, 0x03,
+  0xa1, 0x4b, 0xaf, 0x34, 0x1d, 0x06, 0x31, 0x80, 0x8c, 0x0a, 0x5c, 0xf0,
+  0x93, 0x03, 0xde, 0xb3, 0xd9, 0xca, 0xda, 0x9e, 0xd8, 0x99, 0xce, 0x9b,
+  0xef, 0x72, 0x29, 0x72, 0x79, 0xfc, 0x5f, 0x01, 0xd7, 0x36, 0x93, 0x03,
+  0xda, 0xcf, 0xd3, 0x2f, 0xa0, 0xad, 0xb4, 0x3f, 0xc7, 0x30, 0x92, 0xf0,
+  0x3b, 0x49, 0x5d, 0xa2, 0x5c, 0xd2, 0x39, 0x45, 0x2f, 0xe8, 0xad, 0xfc,
+  0xa6, 0x3f, 0xed, 0x61, 0x3d, 0x0a, 0x24, 0x1c, 0x02, 0x78, 0x41, 0xda,
+  0xff, 0x02, 0xaa, 0xcf, 0xb1, 0xf3, 0xa3, 0xae, 0x72, 0xff, 0xe2, 0x83,
+  0xfa, 0x92, 0xf6, 0xe3, 0x45, 0x8a, 0xcb, 0x10, 0x74, 0x19, 0xdc, 0x97,
+  0x8d, 0x02, 0x75, 0x17, 0x0b, 0x05, 0x2f, 0x59, 0x62, 0x48, 0x61, 0xca,
+  0x18, 0x07, 0x65, 0x11, 0x8e, 0x63, 0xde, 0xd2, 0xaf, 0xb6, 0x66, 0xaf,
+  0xd1, 0x1f, 0xaf, 0x63, 0xe4, 0xc3, 0x50, 0xf1, 0xd0, 0x04, 0xc6, 0x3b,
+  0x66, 0xc9, 0xd6, 0x25, 0xe2, 0xe7, 0xfa, 0xdf, 0xca, 0x26, 0xde, 0x2f,
+  0xdc, 0xf9, 0x33, 0x13, 0x72, 0xa8, 0x9e, 0x6c, 0x18, 0x09, 0xc1, 0x39,
+  0x1a, 0x6e, 0x81, 0x80, 0x4f, 0x2c, 0xde, 0xb3, 0xae, 0xf2, 0xf6, 0xbe,
+  0xa5, 0xed, 0x7d, 0x66, 0xac, 0xd0, 0x63, 0xba, 0x74, 0x9a, 0x4e, 0xe7,
+  0x18, 0x71, 0x4d, 0xf0, 0xfb, 0x72, 0x49, 0x13, 0x72, 0x6b, 0x00, 0xf3,
+  0x6e, 0xc8, 0x76, 0x3a, 0xf2, 0xba, 0x5b, 0xf8, 0xd8, 0x70, 0x8a, 0x1a,
+  0x16, 0x7e, 0x43, 0x41, 0xde, 0x02, 0x50, 0x23, 0x70, 0xa5, 0x90, 0x2b,
+  0x22, 0x97, 0xc1, 0xf2, 0xb9, 0xe9, 0xa9, 0x43, 0xb0, 0x43, 0xf9, 0x37,
+  0x8c, 0x6a, 0x86, 0x49, 0x13, 0xca, 0x03, 0xc1, 0x32, 0x68, 0x1d, 0xd3,
+  0x2e, 0x9b, 0x6f, 0x51, 0xb8, 0x46, 0x19, 0x51, 0x34, 0x64, 0xd0, 0x62,
+  0x23, 0xf1, 0x7c, 0x46, 0x60, 0xdf, 0xca, 0xd6, 0x6a, 0xf3, 0x9e, 0x20,
+  0x00, 0xd1, 0x94, 0xa8, 0x04, 0xb0, 0xf0, 0x41, 0xf3, 0xd6, 0xad, 0xb3,
+  0x8a, 0x30, 0xb3, 0x4a, 0x53, 0x11, 0x8d, 0x1b, 0xd0, 0x0f, 0xc5, 0x97,
+  0xd0, 0x20, 0x4f, 0x4b, 0x36, 0xe2, 0x06, 0x14, 0xd9, 0xa0, 0x18, 0x78,
+  0x05, 0x02, 0x23, 0x09, 0xcf, 0xe3, 0xfa, 0x0a, 0x66, 0x71, 0xf6, 0xe0,
+  0xf1, 0xc0, 0xc5, 0xa0, 0xa7, 0xff, 0xb5, 0xca, 0x89, 0x2d, 0x3c, 0x67,
+  0x3f, 0x37, 0x80, 0xce, 0x59, 0x5f, 0x3f, 0xa8, 0x4b, 0xa6, 0xcd, 0x0a,
+  0x65, 0x1a, 0x25, 0x13, 0x18, 0x5e, 0xb2, 0x7b, 0x9f, 0x35, 0xc6, 0xc6,
+  0x45, 0x7b, 0x3b, 0x32, 0x8c, 0x04, 0xcc, 0x85, 0xe8, 0x68, 0xd2, 0x62,
+  0xed, 0xe7, 0x57, 0x18, 0xad, 0xda, 0xe1, 0xd9, 0x89, 0x09, 0x1f, 0x06,
+  0x79, 0x5e, 0x82, 0xcd, 0x80, 0x61, 0xb1, 0x0b, 0x8a, 0x24, 0x09, 0xc1,
+  0xe9, 0x4a, 0xac, 0x8d, 0xe7, 0x55, 0xcc, 0x55, 0x07, 0x7d, 0xdb, 0xbd,
+  0x8b, 0x29, 0x4e, 0x78, 0xfb, 0x46, 0x64, 0x94, 0xaf, 0xa1, 0x19, 0x6f,
+  0xcd, 0xbe, 0x72, 0x60, 0xe3, 0x55, 0xe1, 0xa5, 0x61, 0x83, 0xbb, 0xce,
+  0x8c, 0x62, 0xe3, 0x2e, 0x84, 0x1f, 0x3c, 0xdc, 0x03, 0xf4, 0x41, 0xab,
+  0x68, 0x63, 0xe3, 0x94, 0x8e, 0x1c, 0xe4, 0x80, 0xc6, 0xfb, 0x10, 0xb9,
+  0xaf, 0xee, 0xcd, 0xfe, 0xfa, 0x9c, 0x18, 0xd8, 0xbc, 0xd6, 0xe0, 0xa8,
+  0xe1, 0xfe, 0x78, 0x82, 0x0e, 0xd7, 0x0e, 0x80, 0xc9, 0x1f, 0x11, 0x5e,
+  0x57, 0x35, 0x41, 0xdb, 0x6c, 0x39, 0xdb, 0xda, 0xfc, 0xb3, 0x12, 0x26,
+  0x05, 0x9a, 0x01, 0xd4, 0x86, 0x4e, 0x60, 0x6a, 0x69, 0x72, 0xf1, 0x15,
+  0x9f, 0x63, 0xaf, 0x9b, 0xe7, 0x1c, 0xbc, 0x33, 0xde, 0x3b, 0x6a, 0x74,
+  0x8a, 0x9e, 0x74, 0x5c, 0xa0, 0x64, 0xc3, 0x01, 0xf1, 0x04, 0xef, 0xaf,
+  0x45, 0x52, 0x5b, 0xed, 0xb2, 0xf8, 0x80, 0xb9, 0xc6, 0x04, 0x40, 0x1e,
+  0x0b, 0xd0, 0x0f, 0xcf, 0x73, 0x2a, 0x65, 0xd2, 0xee, 0xcc, 0xdb, 0xe6,
+  0xe8, 0x84, 0xff, 0xda, 0xb1, 0x25, 0x3a, 0x14, 0x94, 0x67, 0x0e, 0x03,
+  0xdc, 0x93, 0xfe, 0x50, 0x19, 0x60, 0x61, 0xa5, 0xf3, 0xd2, 0x2d, 0x8e,
+  0x6b, 0xa2, 0xc5, 0x63, 0xa9, 0x99, 0x8e, 0xe7, 0x21, 0x5e, 0x08, 0x4c,
+  0xe5, 0x22, 0x66, 0x88, 0xc0, 0x7c, 0x0e, 0x5d, 0x97, 0xb2, 0x15, 0x30,
+  0xd5, 0xee, 0xd4, 0x25, 0x22, 0x82, 0x28, 0x64, 0xc9, 0x96, 0x12, 0x46,
+  0x53, 0xcb, 0xa1, 0xb7, 0x38, 0xe2, 0x8e, 0x52, 0x5a, 0x03, 0x1e, 0xf4,
+  0x4a, 0xb2, 0x8e, 0x77, 0xfa, 0x6b, 0xe6, 0x8c, 0x12, 0xc3, 0x4d, 0x12,
+  0x87, 0xc1, 0x78, 0x29, 0xfa, 0x86, 0xd9, 0xe0, 0xbc, 0x10, 0x87, 0xc6,
+  0x42, 0x13, 0x8d, 0x19, 0x0f, 0x02, 0x4f, 0x56, 0xac, 0xb3, 0xce, 0x6a,
+  0x84, 0xb9, 0x39, 0x59, 0x26, 0x23, 0xe0, 0xcf, 0x72, 0x2e, 0xb9, 0xa2,
+  0xda, 0x32, 0x18, 0x77, 0x12, 0xc9, 0xc1, 0x95, 0x80, 0x93, 0x93, 0xac,
+  0x2d, 0xdf, 0x4c, 0xc2, 0x53, 0x0d, 0xa3, 0x2c, 0xac, 0x3e, 0xfe, 0x72,
+  0xdb, 0xf6, 0x20, 0x80, 0x21, 0xbd, 0x98, 0x71, 0x5d, 0x21, 0xf3, 0x45,
+  0x64, 0x71, 0x0b, 0xb0, 0x33, 0x40, 0xa3, 0x33, 0x57, 0xe5, 0x96, 0x87,
+  0xc4, 0xec, 0x80, 0x90, 0x1d, 0xfb, 0x31, 0x73, 0x5d, 0x7f, 0x70, 0xb3,
+  0x61, 0xa4, 0x8b, 0x3c, 0xc8, 0x44, 0x4d, 0x09, 0xb2, 0x32, 0x74, 0x3e,
+  0xa0, 0xaf, 0xd7, 0x66, 0xe8, 0xd0, 0xb1, 0xc3, 0xa8, 0x81, 0xbc, 0x70,
+  0xe8, 0x6e, 0x68, 0x89, 0x14, 0xaf, 0x8f, 0x4b, 0x60, 0xae, 0x6a, 0xcd,
+  0xa8, 0xbc, 0xd7, 0xbd, 0x35, 0x15, 0xbc, 0xcb, 0x9c, 0x84, 0x27, 0x86,
+  0x69, 0xe5, 0x09, 0x21, 0xf6, 0xa4, 0xd9, 0xaf, 0x33, 0x48, 0x84, 0x93,
+  0x91, 0x24, 0x96, 0xe5, 0x4c, 0x78, 0xee, 0xec, 0x79, 0x5b, 0x0a, 0x3c,
+  0xa8, 0x62, 0xe9, 0xa9, 0x68, 0x21, 0x2c, 0x6a, 0x48, 0x4a, 0x17, 0x19,
+  0x60, 0x65, 0xa5, 0x0c, 0x97, 0xd4, 0xc9, 0xde, 0x56, 0xe9, 0xf0, 0xf7,
+  0x56, 0x57, 0x6c, 0x8e, 0x3e, 0xf6, 0x52, 0xe1, 0x86, 0x42, 0x80, 0x01,
+  0x80, 0xa1, 0x28, 0x64, 0x32, 0x8f, 0x80, 0xf3, 0x7d, 0xa2, 0x97, 0x84,
+  0x82, 0xe7, 0x91, 0x41, 0x92, 0x08, 0xe6, 0x02, 0x69, 0x37, 0xfe, 0xcd,
+  0xa2, 0x85, 0xfa, 0xb7, 0x64, 0xab, 0x78, 0x95, 0xb4, 0x85, 0x44, 0x28,
+  0xa5, 0xe5, 0xb8, 0xc0, 0x11, 0xac, 0x21, 0x5a, 0xd3, 0x98, 0x5e, 0x8a,
+  0x08, 0x60, 0x14, 0x0d, 0x53, 0xde, 0xce, 0x06, 0xd4, 0x37, 0xb1, 0x22,
+  0xe2, 0x68, 0x34, 0xc7, 0xc5, 0xa3, 0xf5, 0x1b, 0xce, 0xed, 0x45, 0x24,
+  0xd9, 0x4a, 0x08, 0xdd, 0x65, 0x07, 0x8b, 0xbf, 0x81, 0xda, 0x3b, 0x31,
+  0xdc, 0xb1, 0x7b, 0x3d, 0x8a, 0xb4, 0x74, 0x6e, 0xc8, 0xd4, 0x46, 0xd9,
+  0xb6, 0x97, 0x45, 0x3b, 0xa0, 0x24, 0x88, 0xc3, 0xc4, 0x1d, 0x58, 0xa5,
+  0xa7, 0xf0, 0x7c, 0xae, 0xd6, 0x77, 0x47, 0x7c, 0xe2, 0xb0, 0x18, 0xef,
+  0x2c, 0x35, 0x82, 0x8c, 0x89, 0x93, 0x76, 0x40, 0x52, 0xbc, 0xf1, 0xf9,
+  0x7f, 0x77, 0x03, 0x74, 0xdc, 0x12, 0xfd, 0x74, 0x2e, 0x16, 0xe6, 0x19,
+  0xd5, 0xe0, 0x8b, 0x06, 0x4b, 0x99, 0x1f, 0x68, 0x3c, 0xd1, 0xbe, 0xe8,
+  0x9c, 0xf7, 0xb5, 0x9d, 0x17, 0x1f, 0xaf, 0x47, 0xc5, 0x38, 0x92, 0x2c,
+  0x1b, 0x54, 0x6f, 0x2b, 0x1d, 0x09, 0xeb, 0x4d, 0x89, 0x8e, 0x32, 0xe7,
+  0x59, 0x84, 0x91, 0xfd, 0x57, 0xd9, 0x79, 0x4f, 0x8a, 0xdb, 0xc3, 0x3a,
+  0x09, 0xe0, 0x07, 0x36, 0xdd, 0x93, 0x94, 0x1e, 0x69, 0x6b, 0xe1, 0x31,
+  0xae, 0x72, 0xed, 0x66, 0x80, 0x06, 0x1b, 0x4a, 0x45, 0xdc, 0xbc, 0xdc,
+  0x93, 0x44, 0xce, 0xf4, 0x01, 0xdc, 0x08, 0x73, 0x02, 0x32, 0xa3, 0xf0,
+  0x61, 0x9a, 0x50, 0x04, 0x3b, 0x28, 0xb3, 0x9a, 0xbf, 0xe7, 0x5c, 0x5a,
+  0x99, 0x4b, 0xf7, 0xff, 0x3b, 0x76, 0x7b, 0x7a, 0xcc, 0xcd, 0x49, 0xdf,
+  0x49, 0x48, 0xcc, 0x99, 0x34, 0x14, 0x07, 0xda, 0x06, 0xfb, 0x9d, 0x97,
+  0xc4, 0xd9, 0x2e, 0x25, 0x34, 0x63, 0x0c, 0x97, 0xce, 0xfa, 0x3b, 0xcf,
+  0x87, 0x18, 0xdd, 0xf7, 0x3f, 0x8b, 0xe1, 0x00, 0xcb, 0x61, 0x03, 0x2c,
+  0x38, 0xbc, 0x31, 0xdc, 0x80, 0xc4, 0x3f, 0xd5, 0x8c, 0x64, 0xe1, 0x09,
+  0x4e, 0x86, 0x59, 0xec, 0x85, 0x55, 0xf0, 0x3a, 0xa7, 0xae, 0xae, 0x02,
+  0xd1, 0x9c, 0x00, 0xc9, 0x20, 0x3e, 0x3c, 0x3f, 0x6e, 0x2e, 0xd9, 0x64,
+  0xb9, 0x0c, 0x82, 0x32, 0x81, 0xe7, 0x46, 0xf5, 0x72, 0xb5, 0x70, 0x5c,
+  0x4c, 0xaf, 0xda, 0xfc, 0x29, 0x07, 0x12, 0x3b, 0x09, 0xde, 0xd3, 0x29,
+  0x06, 0xa0, 0x66, 0x94, 0x72, 0xbe, 0xa0, 0x3f, 0xc3, 0xef, 0x4f, 0xf2,
+  0x77, 0x21, 0x37, 0x58, 0xd9, 0x62, 0x25, 0x08, 0x41, 0xf4, 0x47, 0xc4,
+  0xcb, 0xcb, 0xac, 0x63, 0x14, 0x12, 0xb6, 0xe8, 0xfa, 0xb7, 0x12, 0x6d,
+  0x41, 0xd1, 0x1c, 0x8c, 0x3b, 0x3d, 0x10, 0x20, 0xcb, 0xcb, 0x9c, 0xab,
+  0x1a, 0x27, 0xe1, 0x71, 0xce, 0x95, 0x67, 0x02, 0xe4, 0x8b, 0x90, 0xe2,
+  0x13, 0xb3, 0xb3, 0x0d, 0x33, 0xb3, 0xb3, 0x96, 0x7e, 0xb3, 0xb6, 0x89,
+  0x44, 0x94, 0x0a, 0x0c, 0xc0, 0xd6, 0xc3, 0xe9, 0x14, 0x19, 0x0a, 0xfb,
+  0xd0, 0x9d, 0x0a, 0x39, 0x61, 0xbe, 0xbb, 0x5f, 0xa4, 0xd4, 0xf8, 0xc4,
+  0x7c, 0x91, 0x18, 0xe8, 0x84, 0x46, 0x1f, 0x25, 0x29, 0x9c, 0xbb, 0xd4,
+  0x41, 0x9e, 0xdb, 0x04, 0x3b, 0xef, 0x46, 0x72, 0xc6, 0xdb, 0x40, 0x25,
+  0x92, 0x7c, 0x34, 0x68, 0x2b, 0x43, 0xbd, 0x4b, 0xfd, 0x8c, 0x51, 0xa2,
+  0xcd, 0x91, 0x3e, 0x7b, 0xfe, 0x67, 0xb7, 0x93, 0x5b, 0x62, 0x43, 0x25,
+  0x7f, 0xd2, 0x98, 0xd5, 0xfd, 0x63, 0x21, 0x2a, 0x18, 0x0d, 0x0a, 0x3d,
+  0xc6, 0x78, 0xe5, 0xd2, 0x92, 0xb1, 0x2a, 0x11, 0xd0, 0x9b, 0xa0, 0x4a,
+  0x54, 0x1a, 0x68, 0x04, 0xca, 0x18, 0x7a, 0xc0, 0x4b, 0xeb, 0x76, 0xc9,
+  0x81, 0x8e, 0x32, 0xb4, 0x5b, 0x50, 0xa0, 0x94, 0xe6, 0x80, 0xc9, 0x19,
+  0xf8, 0x26, 0x57, 0xef, 0xf7, 0x29, 0x71, 0x17, 0xfb, 0xeb, 0x85, 0xa8,
+  0xa8, 0x41, 0x5b, 0x26, 0x48, 0x51, 0x83, 0x4c, 0x89, 0x1b, 0xa1, 0x8e,
+  0x91, 0xf1, 0xe9, 0x8c, 0xff, 0xba, 0xee, 0xd7, 0x6b, 0x0f, 0xf5, 0x39,
+  0x60, 0x69, 0xda, 0xbc, 0x76, 0xd8, 0x15, 0x79, 0x9a, 0x79, 0x59, 0x54,
+  0xa5, 0x46, 0xb2, 0x65, 0x7e, 0x34, 0xd4, 0xc4, 0xf6, 0xc7, 0x98, 0x26,
+  0x39, 0x9c, 0x30, 0x18, 0xc0, 0x04, 0xac, 0xba, 0xca, 0x5f, 0xcd, 0x7b,
+  0x03, 0xd7, 0x0d, 0xa0, 0x71, 0xdd, 0x90, 0x86, 0x85, 0x5e, 0x44, 0xfc,
+  0xe3, 0x41, 0xf7, 0xc2, 0xd6, 0x6b, 0xee, 0xa5, 0x6b, 0x2f, 0x72, 0x18,
+  0xbb, 0xc8, 0x48, 0xa0, 0x26, 0x48, 0x9b, 0xca, 0xac, 0x6d, 0x73, 0x5a,
+  0x5d, 0x3d, 0xef, 0x97, 0xdc, 0x83, 0x4d, 0x47, 0x40, 0xee, 0x60, 0x85,
+  0x61, 0xf6, 0x23, 0x2c, 0x80, 0x7c, 0x45, 0x5b, 0x49, 0x91, 0x43, 0x0c,
+  0x50, 0x6c, 0xa2, 0x19, 0x0c, 0x03, 0x1f, 0xe7, 0x85, 0x15, 0x7f, 0x75,
+  0xb2, 0xf2, 0x64, 0x05, 0x1a, 0x28, 0xbc, 0xa9, 0x21, 0x97, 0x42, 0x86,
+  0x5e, 0x10, 0x01, 0xb9, 0x3c, 0x91, 0xfb, 0x95, 0x32, 0xde, 0x1a, 0xdd,
+  0x32, 0x09, 0x81, 0x94, 0x9d, 0xda, 0x12, 0xed, 0x5a, 0x53, 0x4a, 0xc8,
+  0xa2, 0xeb, 0xa8, 0x41, 0xcd, 0xaf, 0xfc, 0xe3, 0xb5, 0x89, 0x53, 0x90,
+  0x30, 0x22, 0x59, 0x0a, 0x00, 0xcb, 0x01, 0xf0, 0x49, 0xb3, 0x5b, 0x7f,
+  0x61, 0xc3, 0xc8, 0xee, 0xd9, 0x6d, 0xc8, 0xe1, 0x01, 0xa6, 0xe7, 0x26,
+  0x84, 0xe8, 0xc8, 0x9c, 0x20, 0x3e, 0x18, 0x2a, 0xb7, 0x15, 0xd6, 0x66,
+  0xb1, 0x51, 0x09, 0x20, 0xc1, 0x1a, 0x8b, 0x2d, 0x01, 0xdc, 0xac, 0xf6,
+  0x1f, 0x6a, 0x74, 0x58, 0x8f, 0x30, 0x61, 0x46, 0x0e, 0x04, 0x91, 0x73,
+  0x29, 0x08, 0x51, 0x0f, 0x92, 0x6f, 0x03, 0xaa, 0x88, 0x1d, 0x95, 0x57,
+  0x6e, 0xec, 0xc2, 0xf8, 0xae, 0x43, 0x50, 0x14, 0xa4, 0x18, 0x19, 0x50,
+  0x19, 0x08, 0x7c, 0x78, 0xde, 0xe7, 0xb3, 0x5e, 0x5c, 0x17, 0xde, 0xc0,
+  0x66, 0x90, 0xed, 0x65, 0xaa, 0x00, 0x4e, 0x85, 0x3c, 0x6c, 0x79, 0x20,
+  0x0d, 0x0f, 0xaa, 0x95, 0xa8, 0x5e, 0xb7, 0x8f, 0xbf, 0x3c, 0x07, 0x12,
+  0x11, 0x91, 0xbd, 0xa9, 0x1f, 0x31, 0xf3, 0xd7, 0x8a, 0x6c, 0xd2, 0xa9,
+  0xbd, 0x7d, 0xd1, 0x63, 0x39, 0x63, 0x64, 0x85, 0xe1, 0x94, 0xba, 0xb1,
+  0xb5, 0xc0, 0xf4, 0xe2, 0xf7, 0x7b, 0xab, 0xc3, 0x99, 0xee, 0x43, 0x23,
+  0x18, 0x80, 0x18, 0x50, 0xc3, 0xc0, 0x8e, 0x42, 0xf9, 0xef, 0xe5, 0xad,
+  0xe2, 0x6d, 0xd8, 0xb6, 0x2e, 0xde, 0x45, 0xa3, 0x21, 0x87, 0x97, 0x70,
+  0x33, 0xcb, 0xfa, 0xe6, 0x45, 0x7b, 0x46, 0x89, 0xf9, 0xa1, 0x2b, 0x09,
+  0x65, 0x28, 0x87, 0x9b, 0xb8, 0x79, 0x04, 0x69, 0x01, 0xda, 0xbd, 0x17,
+  0x7c, 0x84, 0x94, 0x23, 0x4b, 0x0a, 0x57, 0xe3, 0xf3, 0xed, 0x5d, 0x27,
+  0xcc, 0x12, 0xe4, 0x07, 0xd3, 0x01, 0x46, 0x49, 0x43, 0x26, 0xf4, 0x70,
+  0x85, 0x6b, 0x65, 0x9f, 0xaa, 0xa4, 0x88, 0x66, 0x20, 0x88, 0x44, 0x03,
+  0x4c, 0x32, 0xa0, 0xa2, 0x5c, 0x8f, 0xb4, 0x0d, 0x90, 0x1f, 0x39, 0x41,
+  0xfb, 0x48, 0x5c, 0x04, 0x70, 0xd9, 0x47, 0xec, 0x43, 0xae, 0x77, 0x33,
+  0x84, 0xda, 0x48, 0xa6, 0xbd, 0xed, 0x92, 0xca, 0x38, 0x60, 0x28, 0x80,
+  0x18, 0xd1, 0xa1, 0xd9, 0x46, 0xc7, 0xae, 0x2e, 0xcf, 0xd6, 0x4f, 0xb3,
+  0x3c, 0xb7, 0xd0, 0x01, 0x03, 0x31, 0x97, 0xda, 0xd5, 0xee, 0xd7, 0x26,
+  0x06, 0x12, 0xa5, 0xe8, 0x2f, 0xdf, 0x80, 0x18, 0xe2, 0x59, 0x64, 0xe1,
+  0x20, 0x10, 0xc8, 0x97, 0x92, 0x4b, 0xad, 0x54, 0x02, 0x12, 0xc3, 0xcd,
+  0x8a, 0x33, 0xc7, 0xf4, 0xfd, 0x4d, 0xeb, 0x6d, 0x4c, 0xa3, 0x34, 0x00,
+  0xf8, 0xa8, 0xc8, 0x21, 0x90, 0x43, 0x3f, 0xae, 0x7b, 0xaf, 0x37, 0x7a,
+  0x72, 0xc3, 0x47, 0xce, 0xbb, 0xbf, 0xd0, 0x80, 0x6e, 0x00, 0xd6, 0x71,
+  0x42, 0x92, 0x12, 0x9c, 0x62, 0x09, 0xc7, 0x3f, 0x62, 0x36, 0xd2, 0xfe,
+  0xff, 0xba, 0xb5, 0x08, 0x27, 0x88, 0x26, 0x86, 0x3b, 0xd4, 0x34, 0x8c,
+  0x08, 0xf8, 0x24, 0xb3, 0x46, 0x1b, 0x60, 0xf3, 0x86, 0x32, 0x90, 0x47,
+  0xb6, 0x92, 0x1f, 0x8b, 0xb6, 0xa1, 0x7a, 0x4e, 0x67, 0x04, 0x86, 0x51,
+  0xfa, 0x96, 0xb4, 0xba, 0xe3, 0xe3, 0x6a, 0x97, 0x0a, 0x02, 0x30, 0x0a,
+  0xd5, 0x08, 0x35, 0x42, 0x67, 0x00, 0xac, 0xa0, 0xd6, 0x6a, 0xcc, 0x52,
+  0xa3, 0xe5, 0xec, 0xb9, 0x9c, 0xcb, 0xce, 0x53, 0xca, 0x63, 0x97, 0x95,
+  0x91, 0x16, 0x6c, 0x65, 0x16, 0xcb, 0x6c, 0x3c, 0xa0, 0xa3, 0x34, 0x42,
+  0x29, 0x5e, 0x01, 0x5e, 0xf4, 0xd2, 0xe1, 0x32, 0x9e, 0x42, 0x12, 0x3f,
+  0x72, 0x3a, 0x8d, 0xe8, 0xab, 0x8b, 0x0a, 0x86, 0x29, 0x99, 0x00, 0xe3,
+  0x38, 0x9a, 0x34, 0x0c, 0xd0, 0xcb, 0x4a, 0x21, 0x11, 0xdc, 0x07, 0xad,
+  0x53, 0xe5, 0xb2, 0x30, 0x69, 0x13, 0x92, 0xc9, 0x64, 0xb3, 0x00, 0x35,
+  0x33, 0x4d, 0xc0, 0xca, 0x64, 0x3e, 0x08, 0x03, 0x3a, 0x38, 0xde, 0x0d,
+  0xd2, 0x96, 0xb7, 0xb7, 0xab, 0xc4, 0x9a, 0x26, 0x74, 0x27, 0xe9, 0xf1,
+  0x0a, 0xc3, 0x6f, 0x5a, 0x79, 0xd5, 0xf2, 0x92, 0xd5, 0x33, 0x30, 0x40,
+  0x41, 0x06, 0x81, 0x8d, 0xe1, 0xde, 0x9c, 0x8a, 0xbd, 0xb4, 0xb5, 0xc5,
+  0x82, 0x8b, 0xe3, 0xc3, 0xf3, 0x03, 0xd3, 0x84, 0xa2, 0xcc, 0x03, 0xed,
+  0x67, 0xe6, 0x20, 0x32, 0x94, 0x92, 0x18, 0x0e, 0x44, 0x61, 0x52, 0xaf,
+  0xb8, 0x51, 0x7c, 0xac, 0x20, 0x67, 0x2c, 0x3b, 0x90, 0xe1, 0x90, 0x99,
+  0x43, 0x24, 0x3d, 0x3f, 0x68, 0xad, 0xda, 0x91, 0x3e, 0x30, 0xc5, 0x2f,
+  0xf1, 0x50, 0x71, 0x45, 0xf0, 0x09, 0x4e, 0x34, 0xd2, 0x7d, 0x94, 0xb3,
+  0xe9, 0xbd, 0x44, 0x0d, 0x34, 0x18, 0x4f, 0xc4, 0x5c, 0xc3, 0x04, 0x3c,
+  0x9b, 0x08, 0xc5, 0x2d, 0x65, 0x23, 0x40, 0x64, 0xa5, 0xf4, 0x77, 0xfb,
+  0xbf, 0xca, 0x23, 0x89, 0x8d, 0x03, 0x4b, 0x40, 0xf6, 0xb4, 0x49, 0x39,
+  0x24, 0x7c, 0x4f, 0x79, 0xce, 0x13, 0x0b, 0x38, 0xc9, 0xbf, 0xc5, 0x94,
+  0x64, 0x07, 0xd0, 0x2d, 0xed, 0xe0, 0x30, 0x14, 0x68, 0xfd, 0x3f, 0x08,
+  0x42, 0x62, 0xa3, 0xd3, 0x1c, 0x88, 0x58, 0xe8, 0x8c, 0x9b, 0x22, 0x3c,
+  0x41, 0xa6, 0xa5, 0x7d, 0x1d, 0xbf, 0xc0, 0xf9, 0xf9, 0xbe, 0x78, 0x67,
+  0x0a, 0x2f, 0xbf, 0x39, 0xd4, 0xb2, 0x6f, 0x07, 0xcc, 0x09, 0xe5, 0x7d,
+  0x54, 0xfc, 0xbb, 0x30, 0xc6, 0x22, 0x66, 0x84, 0xf2, 0xb4, 0x8c, 0xa1,
+  0x74, 0xaf, 0x04, 0x8e, 0x73, 0x71, 0x1a, 0xf0, 0x67, 0xad, 0x8a, 0x18,
+  0xd0, 0xf1, 0x63, 0x95, 0xf4, 0xc7, 0xc4, 0x7e, 0x75, 0xb6, 0x12, 0xd8,
+  0xd4, 0xe7, 0x03, 0x11, 0xb2, 0x1e, 0x70, 0x8f, 0xb2, 0xbf, 0x18, 0x7b,
+  0xf8, 0x98, 0x97, 0xe1, 0xe7, 0x08, 0x0c, 0x6f, 0x55, 0x19, 0x94, 0xfa,
+  0xd5, 0x89, 0xb7, 0xdc, 0xf1, 0x2b, 0xc6, 0x4b, 0x32, 0x8c, 0x26, 0x26,
+  0x96, 0x72, 0x4d, 0x55, 0x3d, 0xba, 0x6e, 0xbc, 0xb6, 0x98, 0xe1, 0x9c,
+  0x6e, 0x18, 0x12, 0x84, 0xf1, 0x8d, 0x14, 0x0e, 0x5e, 0x01, 0xe2, 0x74,
+  0xf7, 0x4a, 0x55, 0xff, 0xb7, 0x3c, 0xe7, 0xfe, 0xd2, 0x97, 0xce, 0xed,
+  0xc6, 0xc6, 0xec, 0xfd, 0x89, 0xe9, 0x52, 0x26, 0x8b, 0x82, 0xfa, 0x44,
+  0x8c, 0x21, 0xbc, 0xa5, 0x79, 0x76, 0x5b, 0xb7, 0x93, 0x70, 0x56, 0xe0,
+  0x00, 0x48, 0x84, 0xee, 0x09, 0x17, 0x61, 0x46, 0x90, 0x44, 0x07, 0x32,
+  0x9c, 0xc7, 0x71, 0x56, 0x64, 0x67, 0x46, 0x3e, 0xbf, 0x93, 0xdf, 0x4e,
+  0xa6, 0x2c, 0x0a, 0x05, 0x0a, 0x6b, 0x15, 0x0f, 0xe9, 0x0d, 0xb6, 0xf0,
+  0xce, 0x0a, 0x32, 0xa1, 0x59, 0x11, 0xe3, 0xa6, 0xac, 0xe1, 0xb4, 0xc4,
+  0xbf, 0xcc, 0xac, 0x9d, 0xed, 0xe7, 0x34, 0x49, 0xf1, 0x26, 0xad, 0x58,
+  0xdb, 0xf1, 0xb5, 0x00, 0xa1, 0x05, 0xed, 0xb2, 0xe0, 0xc2, 0x96, 0x82,
+  0x05, 0xa4, 0x95, 0x59, 0x76, 0xbf, 0xe6, 0x96, 0xb8, 0xd0, 0x29, 0xe5,
+  0xad, 0x2b, 0x7b, 0x73, 0xb3, 0x2d, 0x01, 0x20, 0x4d, 0x12, 0x72, 0xdc,
+  0x92, 0x5d, 0x1c, 0x24, 0x2e, 0xb8, 0x33, 0x70, 0xe9, 0x41, 0x56, 0xaf,
+  0x9f, 0xeb, 0x1a, 0xa5, 0xae, 0x1a, 0x74, 0x68, 0x04, 0x24, 0xc0, 0x01,
+  0x38, 0x4e, 0xc8, 0xc9, 0x9f, 0x01, 0xc3, 0x39, 0xc3, 0xb5, 0x0c, 0xa3,
+  0xe2, 0xaa, 0x6e, 0xf0, 0x69, 0x07, 0xda, 0x17, 0xbf, 0x6a, 0xcd, 0x92,
+  0x26, 0x87, 0xd7, 0x87, 0xae, 0x0a, 0x3d, 0xf5, 0x87, 0xfc, 0x3b, 0x9c,
+  0xb1, 0xf2, 0xe8, 0x90, 0x12, 0x92, 0x27, 0xb9, 0x40, 0xea, 0xc5, 0x63,
+  0xab, 0xfe, 0xf3, 0xbe, 0x62, 0x07, 0xa2, 0x95, 0xf3, 0x47, 0x72, 0x1b,
+  0xd9, 0xaf, 0xd2, 0x2c, 0x51, 0x28, 0x8c, 0x9f, 0xcc, 0xe4, 0xfb, 0x83,
+  0x33, 0xdd, 0xba, 0xbe, 0xb4, 0xbb, 0x33, 0xf7, 0x4d, 0x8c, 0xe0, 0xb6,
+  0x41, 0xc9, 0x13, 0xc3, 0x72, 0xad, 0xd1, 0xd1, 0xed, 0x58, 0x16, 0xf9,
+  0xff, 0xde, 0xf5, 0x0b, 0xfb, 0x38, 0xbb, 0x1b, 0x8c, 0x1e, 0xdf, 0x9a,
+  0x5f, 0xd5, 0x8d, 0xb9, 0x8c, 0x60, 0x1c, 0xbc, 0xc2, 0x58, 0x44, 0x23,
+  0x94, 0x67, 0xf4, 0x1d, 0x27, 0x10, 0x46, 0xfb, 0x75, 0xa0, 0xc3, 0x22,
+  0x6d, 0x45, 0xc1, 0x94, 0xa6, 0xc5, 0x08, 0x7e, 0x30, 0x56, 0x7d, 0xb6,
+  0x59, 0xcd, 0x35, 0xfe, 0xcf, 0xfc, 0xf0, 0x1a, 0xe7, 0xb8, 0xf3, 0x04,
+  0x0c, 0xa7, 0x05, 0x09, 0xe0, 0x15, 0x86, 0x4e, 0x56, 0xce, 0xff, 0x8b,
+  0x6e, 0xed, 0x94, 0x26, 0x79, 0xa2, 0x12, 0xe4, 0x25, 0x38, 0x12, 0xce,
+  0xe7, 0x92, 0xfa, 0x6a, 0xaa, 0xb6, 0xa8, 0x84, 0x71, 0xd9, 0x9b, 0x72,
+  0xd9, 0x14, 0xb1, 0x66, 0x85, 0x09, 0x91, 0x29, 0xe5, 0xc9, 0x17, 0xa0,
+  0x09, 0xfa, 0x20, 0xa5, 0xc3, 0x66, 0x2e, 0x3b, 0x53, 0x59, 0xd1, 0x0c,
+  0x40, 0x5c, 0xd2, 0xf7, 0x95, 0x46, 0x53, 0x01, 0x10, 0x4e, 0x53, 0xfd,
+  0x46, 0xb7, 0x82, 0x6b, 0xe8, 0xea, 0x52, 0xc6, 0x9b, 0xe5, 0xa5, 0x88,
+  0x2a, 0xf0, 0x28, 0x23, 0x51, 0x99, 0x77, 0x00, 0x46, 0x77, 0x3c, 0x9a,
+  0xfa, 0x51, 0x28, 0xad, 0x8d, 0x13, 0x0d, 0xe9, 0x41, 0x1a, 0x12, 0x43,
+  0xee, 0x12, 0x28, 0xbb, 0x8e, 0xf6, 0x0e, 0x18, 0xc0, 0x57, 0x6f, 0x2d,
+  0x28, 0x32, 0x33, 0xf2, 0xa4, 0x06, 0xf2, 0x7b, 0xa3, 0xf1, 0x6b, 0x06,
+  0xcf, 0x23, 0x81, 0xe7, 0x90, 0xc5, 0xa8, 0xa9, 0x27, 0x64, 0x97, 0x44,
+  0xba, 0x07, 0x1a, 0x52, 0xc9, 0xa2, 0x97, 0x56, 0x19, 0xca, 0x2a, 0x7e,
+  0xd8, 0x92, 0x79, 0xbd, 0x7a, 0x0d, 0xf9, 0x61, 0x80, 0x9b, 0x83, 0x31,
+  0xa6, 0xa6, 0xe8, 0x32, 0x38, 0x40, 0x99, 0x81, 0x75, 0xd5, 0xa5, 0xd8,
+  0xbd, 0x0c, 0x71, 0xb8, 0x1c, 0xe5, 0x65, 0x99, 0x50, 0x09, 0x0c, 0xb3,
+  0xe2, 0x7b, 0x5a, 0xbc, 0x1c, 0x0d, 0x21, 0xa9, 0xc8, 0x33, 0x01, 0x2c,
+  0x64, 0x66, 0x6f, 0x49, 0xf4, 0xf8, 0xb7, 0x5a, 0x5f, 0xe8, 0x86, 0x10,
+  0xcc, 0x01, 0x08, 0xc6, 0x9e, 0x8b, 0xc8, 0x91, 0x47, 0x72, 0x22, 0x55,
+  0x83, 0xfb, 0xa5, 0xa7, 0x50, 0xd3, 0x4d, 0xcb, 0xd2, 0xa5, 0x96, 0x60,
+  0x35, 0x1e, 0x52, 0x00, 0xa3, 0x39, 0x23, 0xf6, 0x4c, 0x6d, 0x4b, 0x14,
+  0x96, 0xf9, 0xa9, 0x43, 0xd9, 0x80, 0x27, 0x6a, 0xf3, 0xa2, 0xcf, 0xc3,
+  0x19, 0x19, 0x4f, 0x2a, 0x69, 0x72, 0x32, 0x95, 0x65, 0x3e, 0x9b, 0xfa,
+  0x8e, 0x23, 0x36, 0x83, 0xb0, 0x71, 0xd4, 0x0d, 0x52, 0xaf, 0x99, 0x02,
+  0xf9, 0x7b, 0x20, 0x8c, 0x82, 0x33, 0x8e, 0x5d, 0xb1, 0x34, 0x18, 0x1c,
+  0x32, 0xad, 0x70, 0x4c, 0x88, 0x95, 0x1e, 0xc2, 0xf8, 0xda, 0x70, 0xe0,
+  0xc8, 0x62, 0xfc, 0xdc, 0xc8, 0x96, 0x02, 0x83, 0x41, 0x56, 0xbf, 0xc5,
+  0xfc, 0xba, 0xdc, 0x53, 0x94, 0x9c, 0x63, 0x38, 0x9c, 0x19, 0x29, 0x99,
+  0xa4, 0x60, 0x12, 0xac, 0x53, 0x6b, 0xcc, 0xb1, 0xc3, 0xca, 0x50, 0x24,
+  0x4f, 0x68, 0x12, 0x35, 0x53, 0x3b, 0xbe, 0xca, 0x08, 0x87, 0x79, 0x49,
+  0x20, 0xd5, 0x60, 0xea, 0x68, 0xc4, 0x50, 0xcb, 0x29, 0x50, 0xf7, 0x02,
+  0xfe, 0xba, 0x30, 0x35, 0x3e, 0x06, 0xf5, 0x86, 0x7c, 0x32, 0x22, 0x53,
+  0x24, 0xa2, 0x82, 0x33, 0x19, 0x3e, 0xc8, 0x35, 0xbb, 0x30, 0xd2, 0x05,
+  0x8b, 0x9f, 0xf0, 0x22, 0xdd, 0xa3, 0x22, 0x81, 0x48, 0x37, 0xda, 0x88,
+  0x20, 0xae, 0x96, 0x5c, 0xa1, 0xbd, 0x18, 0x49, 0xe6, 0xe6, 0x6b, 0xdb,
+  0xeb, 0x19, 0x06, 0x9c, 0xe8, 0x99, 0x11, 0x93, 0xc9, 0x7d, 0x42, 0xff,
+  0xe3, 0xa3, 0x00, 0x82, 0x88, 0x1e, 0x94, 0x67, 0x47, 0xe2, 0xd6, 0x5a,
+  0x64, 0xb2, 0x26, 0x40, 0xa1, 0xe9, 0xc2, 0x45, 0x33, 0x4a, 0x8a, 0x5f,
+  0x61, 0x3c, 0x11, 0x2d, 0x23, 0xa6, 0x9c, 0xe4, 0x8a, 0x17, 0xa0, 0x4f,
+  0xe2, 0xf8, 0xb8, 0xbc, 0xd1, 0x6a, 0x34, 0xa1, 0x94, 0x19, 0x32, 0x97,
+  0x80, 0xd5, 0x67, 0x26, 0x01, 0xce, 0x95, 0x41, 0xcb, 0x42, 0x8e, 0x50,
+  0x83, 0x0e, 0x70, 0x8d, 0xc0, 0x7a, 0xdc, 0x88, 0xa2, 0x48, 0x9c, 0xf2,
+  0x52, 0xfb, 0x6c, 0x49, 0x62, 0xec, 0xcd, 0xe1, 0x39, 0x06, 0xfb, 0x09,
+  0xf6, 0x8e, 0x84, 0x8e, 0xe9, 0x25, 0xb9, 0x39, 0x7e, 0x9c, 0xaf, 0x11,
+  0x1b, 0x04, 0xf9, 0x7d, 0x9a, 0x1a, 0x4a, 0xab, 0x00, 0xdb, 0xba, 0x4a,
+  0xe6, 0xd2, 0x6b, 0x9b, 0x85, 0xf2, 0xcc, 0x32, 0xab, 0xc7, 0x2d, 0x21,
+  0x59, 0x3a, 0xb0, 0x27, 0xbf, 0xc5, 0xf2, 0x7b, 0x3f, 0x43, 0x6c, 0xab,
+  0xbf, 0xd5, 0xe5, 0x2e, 0xcd, 0x4e, 0xbe, 0xe1, 0xc8, 0x3c, 0x96, 0x13,
+  0xed, 0x14, 0xe8, 0xf8, 0x81, 0x7c, 0x49, 0x06, 0x5b, 0xd1, 0xca, 0x45,
+  0x2f, 0x2a, 0x34, 0x2e, 0x03, 0xc5, 0x86, 0x64, 0x40, 0x8e, 0x1e, 0x80,
+  0x0d, 0x42, 0x14, 0x80, 0x6f, 0xb4, 0xc9, 0xe4, 0xf6, 0xed, 0xda, 0xd4,
+  0x45, 0x0d, 0x42, 0xc1, 0x76, 0xe2, 0xbb, 0xd1, 0x05, 0x66, 0x4a, 0xd4,
+  0xd1, 0xca, 0x85, 0xc8, 0xcb, 0xfb, 0x84, 0xa5, 0xca, 0x98, 0x8f, 0xbf,
+  0xcf, 0xc5, 0x71, 0x5f, 0xfe, 0xe6, 0x92, 0x56, 0x20, 0xa4, 0x34, 0x8a,
+  0x35, 0x7a, 0xaa, 0xa2, 0xb5, 0x79, 0xe1, 0x24, 0xa9, 0xee, 0xc3, 0x2c,
+  0x4d, 0x59, 0xa0, 0x41, 0xf5, 0x87, 0xa8, 0xa0, 0xeb, 0x02, 0xe9, 0xfd,
+  0xdf, 0x77, 0xbb, 0x72, 0xc4, 0x17, 0x9e, 0xdb, 0xe1, 0x18, 0x70, 0xca,
+  0x6a, 0x87, 0x24, 0x68, 0xb8, 0x80, 0x84, 0x94, 0xc1, 0xe7, 0xd5, 0x07,
+  0xde, 0xd4, 0xdc, 0xce, 0x2a, 0xde, 0x74, 0xb8, 0xd9, 0xfd, 0x5a, 0x0f,
+  0x91, 0x9a, 0x70, 0x8a, 0x34, 0x0a, 0xc9, 0x5f, 0x88, 0x28, 0xf9, 0x3a,
+  0x79, 0xd6, 0xee, 0x4c, 0x82, 0xa4, 0x97, 0x24, 0x4a, 0x43, 0x2b, 0x25,
+  0xf5, 0x55, 0xcb, 0x6f, 0x23, 0xb1, 0x2c, 0x9a, 0x43, 0xe6, 0x9e, 0xe1,
+  0x70, 0x77, 0x07, 0x09, 0x14, 0x9c, 0x00, 0x5e, 0xb9, 0x22, 0x28, 0xd7,
+  0xf9, 0x41, 0xe6, 0x13, 0xa6, 0x2b, 0x73, 0x5a, 0x4f, 0x6b, 0x98, 0x39,
+  0xba, 0xf8, 0xa7, 0xfc, 0x07, 0x1d, 0xbf, 0x69, 0xcc, 0x00, 0xd1, 0x66,
+  0xa6, 0x41, 0x00, 0x91, 0x41, 0x1e, 0xe0, 0x07, 0xcb, 0x16, 0xfe, 0xc6,
+  0xe6, 0xd5, 0x54, 0xb4, 0x51, 0x4e, 0xf7, 0x2a, 0xb4, 0x86, 0xa0, 0x77,
+  0xb8, 0x2b, 0xf2, 0x41, 0x2f, 0xb2, 0x03, 0xc0, 0x7a, 0x92, 0x7b, 0xcb,
+  0xd5, 0x9a, 0x65, 0xd2, 0x37, 0x80, 0xbe, 0xdc, 0x4e, 0x0c, 0x3e, 0xaa,
+  0x86, 0xef, 0x86, 0x01, 0xa8, 0x77, 0x36, 0xd7, 0xf2, 0xf5, 0xb9, 0xeb,
+  0xd8, 0x6e, 0x5e, 0x12, 0x5d, 0xfc, 0xf7, 0x93, 0xb6, 0x91, 0xbc, 0x00,
+  0x04, 0x67, 0x97, 0xf7, 0x37, 0xac, 0x3b, 0x81, 0xbe, 0xab, 0x3e, 0xfa,
+  0x92, 0x67, 0xb1, 0x60, 0x4e, 0xf4, 0x64, 0x27, 0x08, 0x08, 0x32, 0x40,
+  0x9a, 0x3e, 0x2c, 0x4c, 0x9a, 0x53, 0x45, 0xcc, 0xe1, 0xfa, 0x70, 0xda,
+  0x8c, 0x00, 0x49, 0x6d, 0x0e, 0x4b, 0x22, 0xf6, 0x7f, 0xd1, 0x49, 0x37,
+  0xa0, 0x28, 0x48, 0x5e, 0xa4, 0xc5, 0x76, 0xb8, 0x86, 0x1a, 0xa5, 0x34,
+  0xe6, 0x0a, 0x25, 0x80, 0x48, 0x9f, 0x01, 0x25, 0xb3, 0xde, 0xf1, 0x0b,
+  0xaf, 0x6b, 0x22, 0x1c, 0x60, 0x1c, 0xc9, 0xa3, 0x17, 0x96, 0x19, 0xb2,
+  0x1b, 0xcb, 0xc2, 0x1d, 0xf6, 0x9f, 0xc2, 0x89, 0x99, 0xcd, 0x9b, 0x7f,
+  0x67, 0x7e, 0x39, 0xdf, 0x37, 0x9b, 0xd3, 0xf3, 0x7f, 0xfe, 0xb8, 0x34,
+  0xb0, 0xf0, 0x03, 0xbf, 0x33, 0x23, 0xa5, 0x01, 0x51, 0x28, 0x09, 0x90,
+  0x89, 0x78, 0x4f, 0xd0, 0x1c, 0xf6, 0x61, 0xc6, 0xb4, 0xd4, 0x08, 0x9d,
+  0x22, 0xcf, 0x08, 0xa4, 0x70, 0xc6, 0x79, 0x77, 0xa8, 0x15, 0xe9, 0x0d,
+  0x74, 0x0a, 0xc6, 0x04, 0xb0, 0x6f, 0x39, 0x80, 0x43, 0xcc, 0xa8, 0xfc,
+  0x5a, 0x32, 0xa0, 0x2a, 0xd6, 0x01, 0xb9, 0x41, 0xd1, 0xd8, 0x96, 0x5a,
+  0x07, 0x25, 0xf4, 0x5c, 0x48, 0x1f, 0x0b, 0x38, 0x4c, 0x2e, 0x15, 0x23,
+  0x32, 0xe2, 0xee, 0x7c, 0x7d, 0xf8, 0xa5, 0x89, 0xde, 0x89, 0x2f, 0xc7,
+  0x4d, 0xba, 0x2f, 0xfe, 0x48, 0x95, 0x19, 0x4e, 0x06, 0x64, 0x4e, 0x54,
+  0xfc, 0x0c, 0xf6, 0xc3, 0x5a, 0x17, 0xb0, 0x90, 0x9e, 0x52, 0x5c, 0xf2,
+  0x51, 0xa4, 0x15, 0xc5, 0xf2, 0x98, 0xce, 0x50, 0xfc, 0xef, 0x86, 0x91,
+  0x5b, 0x95, 0x23, 0x42, 0x48, 0xa3, 0x90, 0xea, 0xcb, 0x47, 0x98, 0xdf,
+  0xf2, 0xcc, 0xfc, 0x5b, 0x0d, 0xdc, 0x8e, 0x78, 0x86, 0x58, 0xf2, 0xed,
+  0xa0, 0x6a, 0xea, 0xe1, 0x51, 0xf1, 0x0c, 0xfb, 0x3a, 0x2c, 0x4e, 0x59,
+  0xec, 0x82, 0x32, 0x65, 0x93, 0xc2, 0xd9, 0xa4, 0x32, 0x72, 0x41, 0x91,
+  0x45, 0x23, 0x43, 0xc3, 0xab, 0x8a, 0xfb, 0xaf, 0x21, 0xc6, 0x42, 0x85,
+  0x61, 0x24, 0xcb, 0x25, 0x09, 0xf4, 0xf6, 0x54, 0x1e, 0x45, 0xe1, 0x42,
+  0x19, 0x49, 0x1c, 0x96, 0x11, 0x3c, 0x89, 0x2f, 0xf3, 0xa9, 0x48, 0x39,
+  0x02, 0x14, 0x50, 0x26, 0x8f, 0x64, 0x33, 0x85, 0x4f, 0x35, 0x85, 0xe7,
+  0xdd, 0x7f, 0x7d, 0xfb, 0xd9, 0xd4, 0x62, 0x06, 0x1a, 0x57, 0x10, 0xfe,
+  0x12, 0xc6, 0x9e, 0x26, 0xb6, 0x5d, 0x41, 0xde, 0x66, 0x1e, 0xcf, 0x32,
+  0x7b, 0x20, 0x4e, 0xec, 0xf1, 0x84, 0xb2, 0x28, 0x55, 0xd2, 0x4f, 0xcd,
+  0x23, 0xff, 0xcb, 0xd4, 0x96, 0x6a, 0x16, 0xc9, 0x1a, 0xd8, 0x02, 0x59,
+  0x7f, 0x06, 0x3e, 0x7d, 0xe1, 0x0f, 0x60, 0x79, 0xec, 0x1b, 0x41, 0x5f,
+  0x99, 0xb9, 0x65, 0x5d, 0x82, 0xbe, 0x2f, 0x97, 0x8f, 0xd2, 0xef, 0x0e,
+  0x32, 0xd7, 0xab, 0x65, 0xc5, 0xa1, 0x92, 0xf1, 0x74, 0x65, 0xf3, 0x00,
+  0xb1, 0xab, 0x54, 0x7f, 0x26, 0x43, 0x2c, 0x4e, 0xba, 0x6d, 0x83, 0xb9,
+  0x1a, 0x75, 0xec, 0x98, 0x6d, 0x1f, 0xa1, 0x37, 0xdb, 0xaa, 0x3e, 0xb4,
+  0x1a, 0xef, 0xe9, 0x4a, 0x7a, 0x76, 0xe3, 0x66, 0x0c, 0x92, 0xf5, 0x06,
+  0xcc, 0x39, 0x3d, 0x78, 0x84, 0x7a, 0x7e, 0xb0, 0x7d, 0xd5, 0xff, 0x20,
+  0x07, 0x08, 0x68, 0x35, 0xbf, 0x04, 0xd8, 0xc6, 0x59, 0x67, 0xec, 0xa4,
+  0x24, 0xfc, 0xce, 0x83, 0x4f, 0x44, 0x3e, 0xde, 0x86, 0xd4, 0x79, 0x9b,
+  0xb0, 0xaf, 0x98, 0x4c, 0xf2, 0xa8, 0xe0, 0x1f, 0x47, 0x83, 0x85, 0x12,
+  0xfb, 0x32, 0x01, 0x0a, 0x5a, 0xca, 0xc6, 0x92, 0x31, 0x8a, 0x45, 0x1a,
+  0x3f, 0x57, 0x1f, 0xb8, 0x96, 0xe1, 0xfd, 0x20, 0xc8, 0x98, 0x54, 0x56,
+  0x01, 0x27, 0x2a, 0x50, 0xcd, 0x0f, 0x9e, 0x36, 0xe2, 0x97, 0xae, 0x69,
+  0x36, 0x86, 0x5e, 0x54, 0xcc, 0x68, 0x69, 0x73, 0x32, 0xdb, 0x56, 0xbf,
+  0xfb, 0xa7, 0x66, 0x20, 0xd6, 0xcb, 0x06, 0x82, 0x07, 0x98, 0x46, 0x6f,
+  0xb9, 0x61, 0xbe, 0x3d, 0x57, 0x3d, 0xed, 0x8f, 0x50, 0x2e, 0x56, 0x2f,
+  0x37, 0x75, 0xed, 0x94, 0xc2, 0x72, 0x66, 0x91, 0x07, 0x95, 0xa5, 0x6d,
+  0xf1, 0xb5, 0xaf, 0x8e, 0xd8, 0xcb, 0x20, 0x1a, 0x44, 0x09, 0xbc, 0xd0,
+  0x13, 0x2c, 0x12, 0xb2, 0xa1, 0xf1, 0x3e, 0xda, 0x6b, 0x21, 0xad, 0x9d,
+  0x53, 0x59, 0x33, 0x6e, 0x1a, 0x50, 0xb0, 0xc3, 0x19, 0x55, 0x31, 0x00,
+  0x61, 0x7c, 0xa9, 0xe5, 0xf8, 0xb7, 0x7f, 0x2e, 0x8f, 0x9b, 0x6e, 0xd1,
+  0x3a, 0x1c, 0x66, 0xd0, 0x65, 0xc3, 0x04, 0xe6, 0xe6, 0xf0, 0x98, 0x09,
+  0x21, 0x95, 0xe2, 0x18, 0xa7, 0xb2, 0xbd, 0x90, 0x14, 0x05, 0x78, 0xcf,
+  0x21, 0x65, 0xa1, 0x93, 0x47, 0x09, 0x15, 0xbe, 0x1f, 0x92, 0xf0, 0x15,
+  0x32, 0x84, 0xd8, 0xe0, 0x22, 0x8c, 0xdc, 0xa3, 0x2f, 0x83, 0xf1, 0x43,
+  0x14, 0x4c, 0x7e, 0xe1, 0xa0, 0x18, 0xef, 0x5f, 0xa2, 0x1b, 0xe6, 0x66,
+  0x97, 0x2a, 0x3e, 0x2d, 0x7f, 0x80, 0x5a, 0x1b, 0xc7, 0x2e, 0x94, 0xdf,
+  0x17, 0xe0, 0xfe, 0x8a, 0x77, 0x05, 0xc3, 0x3c, 0x33, 0x28, 0xc2, 0x90,
+  0xc9, 0x66, 0x0a, 0x2a, 0x60, 0xa6, 0xec, 0x11, 0x9e, 0x54, 0xd2, 0x82,
+  0x5f, 0xdc, 0x10, 0x88, 0x5b, 0x24, 0x6f, 0x4f, 0x69, 0x4a, 0xf5, 0xb8,
+  0x5c, 0xac, 0xc6, 0xf7, 0x77, 0x35, 0x19, 0x81, 0x0a, 0x32, 0x0d, 0x92,
+  0x11, 0xa3, 0xf1, 0xa2, 0xc8, 0x99, 0x4c, 0xb9, 0x43, 0x2d, 0x28, 0x4a,
+  0xf5, 0x3e, 0x23, 0x36, 0x1d, 0xd1, 0xc3, 0x94, 0x87, 0xdc, 0x06, 0xfb,
+  0x07, 0x78, 0x60, 0xed, 0x05, 0x2c, 0x9f, 0x65, 0x0f, 0xe5, 0x09, 0x53,
+  0x9e, 0x84, 0x91, 0x66, 0x72, 0x4f, 0xc7, 0x1f, 0x05, 0xd6, 0x68, 0x7c,
+  0x58, 0xd0, 0xcc, 0xd0, 0xec, 0xc2, 0x86, 0x98, 0x51, 0x7c, 0xa6, 0xa3,
+  0x33, 0x56, 0xa1, 0x6f, 0xf1, 0xf8, 0x20, 0xcc, 0x48, 0xed, 0x46, 0xf2,
+  0x69, 0x72, 0xf1, 0x72, 0x39, 0x69, 0x09, 0xde, 0x33, 0xf1, 0x54, 0x2b,
+  0xcc, 0x4e, 0x3e, 0x52, 0x29, 0x11, 0xd8, 0x4f, 0x8f, 0x06, 0x60, 0xfd,
+  0xdd, 0x5d, 0x34, 0xae, 0x37, 0xe6, 0x5c, 0x5e, 0x75, 0xc1, 0xd3, 0xbe,
+  0x50, 0x24, 0xb6, 0xf7, 0x23, 0x87, 0xa5, 0xc3, 0x94, 0x12, 0xfc, 0x01,
+  0xf7, 0xfb, 0xfb, 0x3b, 0xbe, 0x9e, 0xea, 0xce, 0x5e, 0x2e, 0xf5, 0xba,
+  0x4f, 0x90, 0x5e, 0xa6, 0x8e, 0x4f, 0x4e, 0x84, 0x8d, 0x0f, 0x14, 0x61,
+  0xf6, 0xe9, 0xd5, 0x5e, 0x6b, 0x35, 0x5b, 0xea, 0xba, 0xd0, 0x3b, 0xd4,
+  0xb5, 0x33, 0x37, 0x63, 0xb7, 0x94, 0x98, 0x99, 0x4f, 0x2a, 0x7e, 0x3b,
+  0x48, 0x1c, 0xeb, 0xb4, 0xa6, 0x9e, 0x76, 0x2b, 0xc2, 0x89, 0x3b, 0xf8,
+  0x36, 0x55, 0xce, 0x57, 0x8d, 0xd0, 0x0b, 0xdd, 0x53, 0x34, 0xa0, 0x93,
+  0x01, 0xb1, 0x80, 0x25, 0xa5, 0x51, 0xf1, 0x3d, 0x3e, 0xbc, 0xb3, 0x56,
+  0x99, 0xb7, 0x12, 0xa1, 0x73, 0x23, 0x5f, 0x14, 0xf1, 0xb8, 0x83, 0x2e,
+  0x73, 0x84, 0xf8, 0x82, 0xb4, 0x54, 0xcb, 0x4c, 0x6b, 0xdb, 0xf3, 0xf1,
+  0x04, 0xad, 0x66, 0xb6, 0x7b, 0x9a, 0x25, 0x2c, 0x63, 0x80, 0xfb, 0x61,
+  0x8c, 0x0d, 0x1e, 0xe0, 0x4e, 0xfe, 0x37, 0x63, 0x1e, 0x7a, 0x86, 0xfe,
+  0xb7, 0x9d, 0x2b, 0x79, 0xd7, 0x9c, 0x0a, 0x0d, 0x35, 0x12, 0x40, 0x83,
+  0x49, 0x55, 0x8c, 0x3d, 0x3a, 0xfb, 0x4a, 0x3e, 0xb6, 0xb6, 0xbb, 0xed,
+  0x13, 0x6d, 0x2f, 0x9d, 0x95, 0x6e, 0xdc, 0xa9, 0x09, 0x9e, 0x7c, 0xfe,
+  0x9c, 0xd5, 0xdd, 0x9d, 0xf3, 0x9e, 0xcf, 0xcb, 0xb9, 0x7e, 0xd7, 0x16,
+  0xa2, 0x21, 0x08, 0x27, 0xa0, 0x8c, 0xb2, 0x20, 0x84, 0x6c, 0xee, 0xed,
+  0xd3, 0x85, 0xee, 0x7c, 0x6d, 0xc1, 0x18, 0xf4, 0x55, 0x42, 0xa2, 0x29,
+  0x55, 0x60, 0x27, 0xdb, 0xbd, 0x76, 0x26, 0x7a, 0x8f, 0x98, 0xcd, 0xa2,
+  0xe9, 0xa9, 0x1e, 0xd0, 0x08, 0x4c, 0x26, 0xa8, 0x44, 0x61, 0x89, 0xab,
+  0x01, 0xe1, 0xff, 0xb9, 0xbb, 0xc9, 0xc0, 0x14, 0xff, 0xfb, 0x38, 0xb7,
+  0xcd, 0x04, 0xa1, 0xe5, 0x81, 0x38, 0xd8, 0x0a, 0x14, 0x6a, 0xd7, 0xe9,
+  0x17, 0xb9, 0x25, 0xd0, 0xac, 0xff, 0x0b, 0xff, 0xb4, 0x60, 0xba, 0xbf,
+  0x14, 0x9d, 0xee, 0x9b, 0xb3, 0x5c, 0x36, 0xe1, 0x1b, 0x07, 0x70, 0xec,
+  0x25, 0x04, 0x03, 0x5e, 0x1d, 0x64, 0x4d, 0x3a, 0xb0, 0xdb, 0xab, 0x34,
+  0xf4, 0xff, 0xbc, 0xb0, 0xda, 0x45, 0xa4, 0x96, 0x4f, 0xd8, 0x9b, 0x81,
+  0x7f, 0xcd, 0x7e, 0xb6, 0xfb, 0x82, 0x4d, 0x88, 0x35, 0x25, 0x6c, 0x64,
+  0x17, 0x97, 0x02, 0x29, 0x14, 0x92, 0x11, 0xf3, 0x2f, 0xf5, 0x69, 0x5c,
+  0x40, 0x36, 0x9c, 0xf0, 0x29, 0xc3, 0x40, 0xb6, 0x58, 0x14, 0x27, 0x31,
+  0x42, 0x0a, 0xcd, 0x12, 0x7b, 0x83, 0x82, 0x79, 0x2d, 0x7f, 0x1d, 0x07,
+  0x43, 0x8e, 0x96, 0x8c, 0x98, 0xa0, 0xf3, 0xcf, 0x90, 0x4e, 0x1f, 0x77,
+  0x4a, 0x95, 0xaf, 0x3e, 0x8d, 0x81, 0x9f, 0x79, 0x66, 0x73, 0x92, 0x43,
+  0xb8, 0x07, 0x8b, 0xba, 0xc1, 0xaf, 0xbd, 0xee, 0x7f, 0x99, 0xbf, 0x1c,
+  0xde, 0x07, 0xac, 0xb2, 0x24, 0x83, 0xb2, 0x38, 0x76, 0xca, 0xf0, 0xdc,
+  0x5a, 0xf6, 0xf7, 0xfd, 0xdc, 0xb8, 0xc4, 0xf6, 0xc4, 0x50, 0xe3, 0x48,
+  0x11, 0x4e, 0x64, 0xbd, 0xa7, 0x2e, 0x73, 0x94, 0xaa, 0xc3, 0xe2, 0x3d,
+  0xec, 0x8f, 0xb7, 0xff, 0xe3, 0x30, 0xbe, 0x4e, 0x5d, 0x0d, 0xb1, 0xa1,
+  0xe9, 0xfb, 0x29, 0x07, 0xd8, 0x37, 0xd1, 0xd7, 0xea, 0x2e, 0x3f, 0x5c,
+  0x3a, 0xf0, 0xa9, 0x75, 0xd9, 0x5d, 0x54, 0xbf, 0x2f, 0x9e, 0x9d, 0x2b,
+  0x73, 0x97, 0xe1, 0x88, 0x5c, 0xe2, 0xe2, 0xa2, 0xd8, 0xe4, 0xbc, 0xe4,
+  0xa3, 0x0c, 0x30, 0x25, 0x77, 0x00, 0x88, 0xea, 0x97, 0x2b, 0xfe, 0xae,
+  0xdd, 0xdd, 0x6a, 0x16, 0x26, 0x40, 0xa9, 0xc4, 0x03, 0x2d, 0x89, 0x82,
+  0x06, 0x9a, 0x33, 0xbd, 0x3e, 0x20, 0x8e, 0xc5, 0x8b, 0x63, 0xda, 0xf5,
+  0xed, 0xaf, 0x83, 0xfd, 0xd8, 0x65, 0x62, 0x0e, 0xd2, 0x72, 0xa3, 0x0a,
+  0x1d, 0x90, 0xeb, 0x8e, 0xdd, 0xf7, 0x58, 0xdf, 0x8f, 0x65, 0xec, 0x3b,
+  0x5c, 0x18, 0x8c, 0xb6, 0x22, 0x4a, 0x7d, 0x63, 0x90, 0xc0, 0x9c, 0x3c,
+  0x9c, 0x65, 0x04, 0x7e, 0xc3, 0xe7, 0xa5, 0x12, 0x57, 0x96, 0x63, 0x31,
+  0xeb, 0xe6, 0x29, 0x9e, 0xdc, 0xab, 0x30, 0x3b, 0x18, 0x58, 0x38, 0x28,
+  0x20, 0x40, 0x3e, 0x01, 0x56, 0x41, 0xe2, 0xf2, 0x3f, 0x7b, 0xf3, 0x37,
+  0x60, 0x53, 0x14, 0xd6, 0x75, 0xe8, 0xb1, 0xfe, 0xb7, 0x06, 0x1b, 0x7c,
+  0x36, 0x36, 0xcc, 0x88, 0x94, 0xf5, 0x03, 0x89, 0x09, 0x42, 0x3e, 0x8b,
+  0x8d, 0x58, 0xfd, 0x5c, 0xcd, 0x2f, 0xd9, 0x96, 0xcd, 0xd7, 0x3d, 0x9d,
+  0x88, 0x13, 0x91, 0x16, 0x31, 0x38, 0xaf, 0x47, 0xb5, 0xbd, 0x88, 0x48,
+  0xfd, 0x2f, 0x39, 0xa5, 0xe0, 0x59, 0x31, 0x52, 0x99, 0xbf, 0x23, 0x72,
+  0x3b, 0xf5, 0xbb, 0xd7, 0xdd, 0xda, 0xa6, 0x26, 0x0d, 0x4c, 0x8d, 0x13,
+  0x93, 0xda, 0x52, 0x43, 0x22, 0x02, 0xa1, 0x66, 0xb8, 0x71, 0x7c, 0xad,
+  0x57, 0x9b, 0x65, 0x53, 0x2b, 0x32, 0xa7, 0x04, 0xd1, 0x0c, 0x8e, 0x34,
+  0xf2, 0xcf, 0x88, 0x3c, 0xd2, 0xd1, 0x9f, 0x17, 0xfd, 0x4e, 0x2d, 0xb7,
+  0x62, 0xac, 0x9d, 0xef, 0xb4, 0x96, 0x1b, 0x52, 0x94, 0x16, 0x69, 0xa6,
+  0x65, 0xa4, 0xac, 0x04, 0x94, 0x4f, 0x89, 0xd3, 0x7d, 0xde, 0xe1, 0xba,
+  0xd3, 0x2d, 0x8f, 0x05, 0x19, 0xa2, 0x89, 0x92, 0x3f, 0x10, 0xce, 0xb0,
+  0xf9, 0x5e, 0xfb, 0x3c, 0xb6, 0x59, 0xe5, 0xab, 0xb0, 0x21, 0x7d, 0xb3,
+  0x57, 0xf2, 0x82, 0xbf, 0x63, 0xce, 0x0c, 0x00, 0x16, 0x7e, 0xdb, 0x22,
+  0x0c, 0xb1, 0xa4, 0x72, 0x49, 0x1f, 0xb4, 0x4f, 0x51, 0xb0, 0xe9, 0xba,
+  0x69, 0xb7, 0x6a, 0xc8, 0xc4, 0x57, 0xfc, 0x94, 0xa1, 0xf4, 0x93, 0xd9,
+  0x02, 0xe3, 0xde, 0xde, 0x7f, 0x6a, 0x19, 0x52, 0xa2, 0xd0, 0xc1, 0x87,
+  0x40, 0xe3, 0x00, 0x52, 0xf6, 0x04, 0x85, 0x64, 0xc5, 0xd5, 0xa7, 0x98,
+  0x36, 0xea, 0x7c, 0xce, 0x84, 0x32, 0x93, 0x1c, 0x95, 0x06, 0x38, 0x4b,
+  0xe1, 0xa3, 0xf0, 0x22, 0x4f, 0x3e, 0xa4, 0x0c, 0x19, 0x2f, 0x70, 0x0b,
+  0x50, 0x8a, 0x9a, 0x2d, 0x87, 0x5f, 0xc6, 0xa8, 0x6c, 0xa8, 0xd7, 0xa1,
+  0x46, 0x02, 0xe8, 0x22, 0x4d, 0x01, 0x29, 0x19, 0x7c, 0xf2, 0xdf, 0xcd,
+  0xdc, 0xbb, 0xce, 0x11, 0x93, 0x4a, 0xca, 0x95, 0x58, 0x24, 0x6d, 0x7f,
+  0xf3, 0xd2, 0xdd, 0x16, 0xcb, 0x1f, 0x3c, 0xeb, 0xce, 0x8a, 0x24, 0x44,
+  0xb4, 0xfb, 0x12, 0x46, 0x61, 0x12, 0x32, 0x91, 0xab, 0x27, 0x49, 0x3f,
+  0x31, 0x13, 0xae, 0xba, 0x4f, 0x6f, 0x0a, 0x39, 0x7a, 0xc6, 0x9e, 0x43,
+  0x1f, 0x34, 0x56, 0x00, 0xf1, 0xad, 0x68, 0x63, 0xa5, 0x51, 0x03, 0x09,
+  0x38, 0xd9, 0x1e, 0xdf, 0xd8, 0x39, 0xd7, 0x07, 0x6c, 0x77, 0x51, 0xb8,
+  0x6a, 0xf6, 0x82, 0x3b, 0x46, 0x58, 0xd5, 0x69, 0xd1, 0xf7, 0xf3, 0xef,
+  0xb8, 0xf7, 0xb8, 0x7f, 0xc7, 0x7f, 0x8f, 0xeb, 0xb1, 0xe6, 0x3d, 0x1a,
+  0xcb, 0x0a, 0xc7, 0x0d, 0x3a, 0xbe, 0xb3, 0x2d, 0x00, 0x52, 0x89, 0x85,
+  0xf2, 0x08, 0x50, 0xad, 0xfc, 0x50, 0xa0, 0x25, 0x0f, 0x02, 0x78, 0x82,
+  0x9f, 0xf2, 0x56, 0x86, 0x81, 0x9b, 0xb9, 0x9e, 0x49, 0x23, 0xe2, 0xd3,
+  0x3b, 0x28, 0x9c, 0x32, 0x18, 0x07, 0xcf, 0x32, 0xbc, 0x2f, 0xe4, 0xa0,
+  0xbc, 0x68, 0x08, 0x94, 0x01, 0xe1, 0x0f, 0x33, 0x43, 0x27, 0xf1, 0x68,
+  0x8f, 0xb0, 0xcf, 0x3e, 0x27, 0x2d, 0xd4, 0xd3, 0x2f, 0x3e, 0x17, 0xa9,
+  0x49, 0xa6, 0x08, 0x9a, 0x04, 0xd0, 0xc8, 0xa4, 0xb9, 0xd6, 0x98, 0xdd,
+  0x37, 0xe2, 0x9c, 0xe7, 0x3c, 0x49, 0xc0, 0x58, 0xd4, 0x4e, 0x8e, 0x5f,
+  0xc7, 0xf5, 0x7e, 0x6f, 0xcb, 0x3c, 0x28, 0x4b, 0x58, 0x78, 0x00, 0xa0,
+  0x27, 0x94, 0x12, 0x87, 0x81, 0x67, 0x14, 0x10, 0x82, 0x89, 0xc9, 0xcc,
+  0x4e, 0x85, 0xdd, 0x5a, 0xeb, 0x11, 0xc9, 0x08, 0x28, 0xa9, 0x86, 0x39,
+  0x8c, 0x1b, 0x08, 0x16, 0xc7, 0xfb, 0xb4, 0xd3, 0x98, 0x9f, 0xd5, 0xe8,
+  0x3e, 0x41, 0x30, 0x4b, 0x2c, 0x29, 0x02, 0x4f, 0x81, 0xbf, 0xd1, 0xeb,
+  0x55, 0x7e, 0xc2, 0xcb, 0x84, 0xc1, 0x4f, 0x5c, 0xac, 0x59, 0x94, 0x94,
+  0xb7, 0x86, 0x7f, 0x31, 0xf6, 0xb8, 0xd7, 0x0b, 0x22, 0x7c, 0x47, 0x6c,
+  0xd0, 0xa8, 0xff, 0x6f, 0x82, 0x63, 0x17, 0x6c, 0xa8, 0x09, 0x48, 0x4b,
+  0xc1, 0xab, 0x50, 0xda, 0xa3, 0xaf, 0xfa, 0xe4, 0x2f, 0x7c, 0x83, 0xa4,
+  0x8e, 0xc0, 0xd5, 0xec, 0x70, 0xef, 0x24, 0x8e, 0xe1, 0x2f, 0x29, 0x64,
+  0xef, 0x58, 0xc2, 0xea, 0xf1, 0xe1, 0xb3, 0xce, 0xa9, 0xd4, 0x62, 0x89,
+  0x96, 0x42, 0x9c, 0xa6, 0x72, 0x21, 0x2c, 0xe0, 0xef, 0x9d, 0xbd, 0x6d,
+  0x7f, 0xf8, 0xa7, 0x5e, 0x0f, 0xb2, 0xcb, 0x61, 0x24, 0x51, 0x80, 0x91,
+  0x02, 0x54, 0x12, 0x33, 0xfa, 0x3b, 0x2a, 0x38, 0xb7, 0x97, 0xc0, 0x5b,
+  0x42, 0x8d, 0xed, 0xf8, 0xc8, 0x93, 0x96, 0x0c, 0x14, 0x72, 0xa7, 0x3b,
+  0xd6, 0xa3, 0xf7, 0xf9, 0xff, 0x79, 0xd9, 0x9b, 0x63, 0x83, 0xa4, 0x08,
+  0x67, 0x13, 0x48, 0xa5, 0xe3, 0x9a, 0x13, 0xee, 0x21, 0xab, 0x97, 0x69,
+  0xc3, 0xd0, 0xe8, 0x6b, 0x23, 0x44, 0x23, 0x7b, 0x47, 0x0e, 0x0a, 0x52,
+  0x47, 0xed, 0x2e, 0xe2, 0x5c, 0x6e, 0x75, 0x68, 0xea, 0xf6, 0x02, 0x70,
+  0xf4, 0x86, 0x32, 0xe7, 0x34, 0x32, 0x11, 0xc9, 0xca, 0x85, 0x64, 0x3d,
+  0x2b, 0x5a, 0x80, 0x71, 0x0c, 0x09, 0x78, 0xa6, 0x11, 0xf1, 0x10, 0x4a,
+  0xac, 0x11, 0x03, 0x32, 0x7c, 0xca, 0x80, 0xba, 0x99, 0x92, 0xb2, 0xdd,
+  0x92, 0xfd, 0x33, 0xfb, 0x69, 0x6d, 0x45, 0x0b, 0x76, 0xb7, 0x03, 0x0c,
+  0x84, 0xa6, 0x52, 0x89, 0x22, 0x85, 0xe9, 0xc2, 0x14, 0xe4, 0x4d, 0xa5,
+  0x39, 0xe5, 0x05, 0x09, 0x81, 0x97, 0x0e, 0x52, 0x57, 0xc7, 0x3e, 0x8b,
+  0xec, 0x3d, 0x3d, 0x41, 0xb9, 0x41, 0x23, 0xb2, 0x61, 0x91, 0x9c, 0x25,
+  0x02, 0xe5, 0x1c, 0xa1, 0x3f, 0xb1, 0xab, 0x31, 0x45, 0xe8, 0x97, 0xdb,
+  0x97, 0x9d, 0x19, 0x40, 0x86, 0x5a, 0x43, 0x09, 0x2b, 0xd1, 0x14, 0x3e,
+  0x2e, 0x5f, 0xa6, 0xaa, 0x2c, 0x85, 0x10, 0x68, 0x20, 0x91, 0xf9, 0xc4,
+  0xa7, 0x3f, 0x98, 0x37, 0xa7, 0xe7, 0x82, 0xff, 0x18, 0xb4, 0x38, 0x71,
+  0x43, 0x00, 0x09, 0x59, 0x82, 0x4d, 0xad, 0xbf, 0x59, 0xe7, 0x71, 0x0b,
+  0x09, 0x98, 0x34, 0xd8, 0xee, 0xe4, 0x19, 0x48, 0x37, 0x6a, 0x51, 0x95,
+  0x60, 0x0a, 0xb4, 0x39, 0x05, 0xc3, 0x21, 0x94, 0x8a, 0x18, 0x0a, 0x11,
+  0xa0, 0x04, 0x4c, 0xde, 0xad, 0xe3, 0x5c, 0xe3, 0x5e, 0x5b, 0xa3, 0xba,
+  0x46, 0xbf, 0x63, 0xa1, 0x50, 0xf2, 0x0d, 0xe5, 0xd5, 0x4f, 0xc8, 0xf1,
+  0x5c, 0xde, 0xa2, 0x83, 0xec, 0xcf, 0x3d, 0x5e, 0xfe, 0x56, 0xf3, 0xad,
+  0xe5, 0x57, 0x92, 0xc9, 0xa5, 0x25, 0x4d, 0x97, 0x22, 0x11, 0x67, 0x62,
+  0x4b, 0x46, 0x58, 0x97, 0xd0, 0x13, 0x6f, 0x7f, 0xa7, 0xe5, 0x62, 0xf3,
+  0xc3, 0x00, 0x95, 0x48, 0x69, 0x25, 0x81, 0x7f, 0xc1, 0xee, 0xb0, 0x58,
+  0x6d, 0x79, 0x9f, 0x53, 0x9e, 0xa8, 0xbb, 0x93, 0x90, 0xc2, 0x08, 0x0a,
+  0x22, 0x53, 0xab, 0x53, 0x26, 0x7c, 0xbc, 0x26, 0x9f, 0xe2, 0xc8, 0x78,
+  0x75, 0x3b, 0x08, 0x54, 0xf2, 0x86, 0x44, 0x63, 0x6c, 0x48, 0x9c, 0x67,
+  0xee, 0x3e, 0x01, 0xf0, 0xb6, 0x6c, 0x8d, 0xf9, 0x22, 0xb8, 0xbe, 0xfe,
+  0xb5, 0x7d, 0xda, 0x99, 0x7b, 0xa5, 0x3c, 0x60, 0x8d, 0x24, 0xb1, 0x40,
+  0xf7, 0x26, 0x7e, 0x2b, 0x40, 0x4f, 0x67, 0x4d, 0x90, 0xe6, 0x43, 0x7c,
+  0x53, 0x58, 0x2e, 0x09, 0x3d, 0x89, 0xff, 0xb7, 0x76, 0x5f, 0x8d, 0xf9,
+  0x85, 0x92, 0xe1, 0xbb, 0x50, 0x3b, 0x5e, 0x50, 0x46, 0x7d, 0xa3, 0x1a,
+  0x00, 0x7d, 0x85, 0xd1, 0xce, 0x62, 0x79, 0xf3, 0xaa, 0x93, 0x23, 0x39,
+  0xb8, 0x2a, 0x09, 0x13, 0x94, 0x32, 0x7e, 0x2e, 0xbb, 0x7d, 0x05, 0x4d,
+  0x25, 0x05, 0x53, 0xfd, 0x4d, 0xb8, 0x69, 0xe3, 0xb1, 0x6a, 0x8f, 0x44,
+  0x20, 0x46, 0x4e, 0x7e, 0x07, 0x57, 0x7e, 0xe5, 0xad, 0xfb, 0xcf, 0x79,
+  0xed, 0xd7, 0x09, 0x27, 0xaa, 0x0f, 0x5f, 0xd3, 0xd1, 0x0c, 0xc0, 0xc9,
+  0x95, 0xa9, 0x63, 0x0e, 0xe0, 0x43, 0xa4, 0x77, 0x40, 0xfc, 0xda, 0xa7,
+  0x7d, 0xb6, 0xd4, 0x35, 0xd9, 0x9e, 0x4f, 0x62, 0x45, 0x2b, 0x62, 0x84,
+  0x86, 0xe7, 0x07, 0x70, 0xbb, 0xef, 0x7e, 0x0b, 0x7e, 0xe3, 0xa3, 0xc0,
+  0x74, 0xc0, 0x1d, 0xf0, 0xe5, 0x18, 0x00, 0x08, 0x83, 0x40, 0xe5, 0xca,
+  0x58, 0x4b, 0x7c, 0x36, 0x76, 0x29, 0x65, 0x05, 0x49, 0xf7, 0xdf, 0xe5,
+  0x44, 0xe7, 0x71, 0x74, 0xe7, 0x83, 0x7b, 0x53, 0x0d, 0x3a, 0x78, 0xf2,
+  0x40, 0x22, 0x11, 0x4b, 0x97, 0x88, 0xae, 0xec, 0xa7, 0x3f, 0x21, 0x5a,
+  0x81, 0x9e, 0x9f, 0x4b, 0x7d, 0xb1, 0xa2, 0xa7, 0x08, 0x96, 0x70, 0x96,
+  0xc6, 0xb1, 0x6a, 0x36, 0xe2, 0x15, 0x75, 0xb0, 0xca, 0x95, 0x7e, 0x45,
+  0xc0, 0x45, 0xb2, 0xb4, 0x6b, 0xc3, 0x0c, 0x28, 0x25, 0x64, 0xfe, 0xa2,
+  0x15, 0x03, 0x3f, 0xaa, 0xde, 0xf2, 0xb5, 0xed, 0xe4, 0x03, 0x38, 0x37,
+  0xb2, 0x48, 0xa0, 0x8b, 0x60, 0x28, 0xcb, 0x2d, 0xa7, 0x84, 0x2e, 0x2d,
+  0xe3, 0x0a, 0x37, 0x36, 0xca, 0x1a, 0xaa, 0x03, 0xb4, 0x2f, 0xe5, 0xad,
+  0xf7, 0xc9, 0x0f, 0x8b, 0xab, 0x47, 0x66, 0xcb, 0x99, 0x83, 0x52, 0xc7,
+  0xa0, 0x96, 0x2a, 0xc3, 0x17, 0xbf, 0xe0, 0x62, 0xde, 0xe2, 0x1d, 0x21,
+  0x0b, 0x4f, 0x1d, 0x0c, 0x97, 0xda, 0x8b, 0xc2, 0x9e, 0xea, 0x1e, 0xd5,
+  0x88, 0x1b, 0x4e, 0xec, 0xca, 0xd0, 0x08, 0x0d, 0x20, 0x65, 0x29, 0x48,
+  0x7c, 0xc0, 0x9f, 0xce, 0x3a, 0xaf, 0xe2, 0x5b, 0xfd, 0xfc, 0xb7, 0x63,
+  0xbd, 0x6c, 0x40, 0x10, 0xab, 0xda, 0x72, 0xce, 0x88, 0xca, 0x1f, 0x6d,
+  0x49, 0x02, 0x76, 0x22, 0x5a, 0x27, 0xe2, 0x82, 0xa3, 0x9f, 0xdb, 0xdd,
+  0xa6, 0xfc, 0x09, 0xd6, 0xce, 0xec, 0xde, 0xe9, 0x34, 0xe0, 0x76, 0xa3,
+  0x33, 0x29, 0x83, 0x4d, 0xd0, 0x39, 0x04, 0x19, 0xdf, 0xb5, 0x4f, 0xd8,
+  0x29, 0xe5, 0x21, 0xba, 0x63, 0x67, 0x73, 0x40, 0x13, 0xbc, 0x3d, 0x39,
+  0x94, 0x21, 0x28, 0x43, 0x59, 0x13, 0xe2, 0x7b, 0xdc, 0xb8, 0x0e, 0x75,
+  0xdd, 0x96, 0x7d, 0x63, 0x52, 0xd9, 0x9b, 0x8d, 0xb1, 0xa0, 0x8f, 0x81,
+  0x7e, 0x5f, 0x67, 0xfe, 0xae, 0x20, 0x58, 0xb3, 0x54, 0xe1, 0x9c, 0x98,
+  0x3b, 0xed, 0x13, 0x2c, 0x47, 0x91, 0x38, 0x05, 0x0c, 0x24, 0x20, 0x03,
+  0xc7, 0x83, 0x2f, 0xde, 0x76, 0xd3, 0xa1, 0xfc, 0x83, 0x65, 0xc2, 0xae,
+  0xc6, 0x7f, 0xda, 0x0d, 0x68, 0xa1, 0x03, 0xce, 0x54, 0x75, 0x97, 0xe1,
+  0x46, 0x7c, 0xd7, 0x9b, 0x9e, 0x0f, 0xed, 0x17, 0xb1, 0xf9, 0x7a, 0x86,
+  0xc5, 0x54, 0x8b, 0xd3, 0x92, 0xac, 0x91, 0x83, 0x1e, 0xa2, 0x81, 0xcc,
+  0xe8, 0x94, 0x3e, 0xaf, 0x17, 0x33, 0x37, 0x2f, 0x2b, 0x1f, 0x88, 0x75,
+  0x27, 0x84, 0xda, 0x89, 0x72, 0x10, 0x9a, 0x13, 0x03, 0x19, 0x9e, 0x69,
+  0x1f, 0x03, 0x3a, 0xb4, 0x2b, 0xaf, 0x1c, 0xf4, 0x4e, 0xf4, 0x26, 0xc6,
+  0x14, 0x02, 0xf4, 0x4c, 0x2d, 0x90, 0xe5, 0x8c, 0x95, 0x8f, 0xf5, 0xf9,
+  0x1e, 0x38, 0x1f, 0xc7, 0x57, 0x45, 0xdd, 0xab, 0x14, 0x24, 0x1e, 0x16,
+  0xf3, 0x1c, 0x7b, 0xeb, 0x60, 0x3e, 0xa9, 0x75, 0xe4, 0xbd, 0xe7, 0xa7,
+  0x66, 0x72, 0x2e, 0xec, 0xa1, 0x6a, 0x9d, 0xc9, 0x3c, 0x79, 0xb4, 0x07,
+  0x95, 0x48, 0x88, 0x21, 0xa1, 0xf5, 0x33, 0x26, 0x34, 0x54, 0xf3, 0xc5,
+  0x44, 0x1a, 0x61, 0xea, 0x27, 0x82, 0x84, 0xe4, 0x7e, 0xa9, 0x06, 0x1e,
+  0x49, 0xc7, 0x1a, 0x62, 0x8c, 0x84, 0x33, 0x79, 0xcd, 0xa5, 0xb3, 0xb9,
+  0x4f, 0x1d, 0x1f, 0xab, 0x89, 0x3b, 0xbc, 0x08, 0x64, 0x78, 0x31, 0xd1,
+  0x9d, 0x5e, 0x60, 0x8a, 0x08, 0xf7, 0x31, 0xe7, 0xb3, 0x88, 0x65, 0x73,
+  0x01, 0x46, 0x02, 0x8c, 0xcc, 0xa4, 0x8a, 0x07, 0x2e, 0x59, 0x5f, 0x3c,
+  0x16, 0xcc, 0xda, 0x51, 0x69, 0x04, 0x20, 0xd5, 0x14, 0x8c, 0x26, 0x34,
+  0xbe, 0x39, 0x00, 0x8c, 0x60, 0xc6, 0x83, 0xd0, 0x93, 0x99, 0xf7, 0x29,
+  0x81, 0x0c, 0x31, 0x21, 0x0f, 0x32, 0xc7, 0x00, 0x48, 0x25, 0x9f, 0xb3,
+  0x84, 0x89, 0xe1, 0x3e, 0x90, 0xf8, 0x0d, 0x66, 0x4e, 0xed, 0xc5, 0x3e,
+  0xd3, 0x14, 0xce, 0x55, 0x3e, 0xf6, 0x0d, 0xc5, 0x6d, 0xe3, 0xad, 0x68,
+  0x8a, 0x07, 0x19, 0xf1, 0x8a, 0xca, 0x28, 0xf3, 0x6b, 0x54, 0x31, 0x97,
+  0x8c, 0xf2, 0x90, 0xc2, 0x17, 0xef, 0x13, 0x63, 0x8d, 0xbd, 0x29, 0x8a,
+  0x46, 0x48, 0x63, 0xe5, 0xa5, 0x65, 0xf8, 0x19, 0x92, 0xc5, 0x6d, 0x3a,
+  0x95, 0xd9, 0xce, 0xdc, 0x03, 0x01, 0x9c, 0x28, 0x55, 0x32, 0x49, 0x24,
+  0x0f, 0x39, 0x5d, 0x66, 0x55, 0xac, 0x5b, 0x4d, 0xc3, 0xa7, 0xe7, 0x70,
+  0x9c, 0x57, 0x42, 0xbc, 0x95, 0xa6, 0xa2, 0xc0, 0xa2, 0x4f, 0x64, 0xef,
+  0x38, 0x20, 0xce, 0x2a, 0x0b, 0xf1, 0x74, 0x7f, 0x6f, 0x94, 0xf7, 0xac,
+  0xa0, 0xaf, 0xd3, 0x97, 0xbc, 0xb5, 0x8a, 0x81, 0x18, 0xd8, 0x74, 0x28,
+  0x50, 0xf9, 0xfe, 0xdb, 0x69, 0x9a, 0xfc, 0xb5, 0x3a, 0xbc, 0xa2, 0x89,
+  0x74, 0xb3, 0x92, 0xf0, 0x05, 0x5f, 0xde, 0xd1, 0x0b, 0xea, 0xc1, 0x23,
+  0x31, 0x87, 0xed, 0x24, 0x67, 0x38, 0x00, 0x3f, 0x38, 0xde, 0xba, 0x70,
+  0xbc, 0x57, 0x90, 0x30, 0xa0, 0x66, 0x32, 0x53, 0x43, 0xb2, 0x78, 0x50,
+  0xf3, 0x28, 0x06, 0xf9, 0x94, 0xba, 0x7b, 0xbd, 0xf6, 0x7b, 0x6f, 0xfd,
+  0xce, 0x5f, 0xae, 0xc3, 0x1c, 0x3f, 0x4b, 0x66, 0x25, 0xa2, 0x27, 0x49,
+  0xe6, 0xed, 0x0a, 0x22, 0x84, 0xeb, 0x22, 0xf8, 0xf6, 0xb3, 0xf1, 0xdf,
+  0x9b, 0xa7, 0x17, 0x07, 0x28, 0xd3, 0xc4, 0x93, 0x46, 0x41, 0x06, 0x19,
+  0x39, 0x04, 0x7c, 0x41, 0x16, 0x66, 0xf0, 0x7b, 0x0a, 0x6e, 0x3b, 0xc7,
+  0x3a, 0xc9, 0x3e, 0x3d, 0x5d, 0x2f, 0x4d, 0xdd, 0xea, 0x14, 0x0e, 0x50,
+  0x22, 0x8e, 0x2e, 0x1f, 0x64, 0x4f, 0x0d, 0x58, 0x07, 0x37, 0x5d, 0x84,
+  0x45, 0x69, 0xdc, 0x43, 0xa8, 0x18, 0xd3, 0x92, 0x32, 0x42, 0x68, 0x1a,
+  0xb1, 0x4b, 0x16, 0x70, 0xab, 0x94, 0xa2, 0x89, 0xd6, 0xdc, 0xf7, 0x5f,
+  0xe0, 0x0f, 0xf6, 0xd7, 0x3a, 0xe6, 0x1e, 0x46, 0xca, 0x30, 0xa9, 0xa1,
+  0x90, 0x32, 0xa0, 0x5f, 0x88, 0x27, 0x41, 0x1f, 0xa8, 0x34, 0xd9, 0xe7,
+  0x49, 0x27, 0x68, 0xba, 0x5b, 0x1d, 0x75, 0x13, 0xc9, 0x9c, 0x96, 0x4f,
+  0xc1, 0x37, 0x39, 0xdf, 0xae, 0x4d, 0x6b, 0xe4, 0x84, 0x63, 0x11, 0xf1,
+  0x50, 0x08, 0xf8, 0xc8, 0x50, 0xb1, 0xbe, 0xdf, 0x52, 0x69, 0x89, 0x8a,
+  0x9d, 0xb9, 0x96, 0x30, 0x23, 0x22, 0x18, 0x43, 0x8a, 0xf4, 0xbb, 0x46,
+  0xed, 0x72, 0x67, 0x08, 0x5c, 0x7a, 0x9f, 0xa8, 0x18, 0xf8, 0xc1, 0x21,
+  0x34, 0x67, 0xe9, 0xfa, 0xad, 0xc8, 0x53, 0x18, 0x50, 0x12, 0xa1, 0x21,
+  0x33, 0x92, 0xf0, 0x89, 0xf5, 0x65, 0xfc, 0xba, 0x8a, 0x18, 0xba, 0xba,
+  0x66, 0x06, 0x3e, 0x64, 0x68, 0xb6, 0x83, 0xcf, 0x79, 0x75, 0xf9, 0x90,
+  0x86, 0x4b, 0xc5, 0x5f, 0xff, 0x6c, 0xa3, 0xab, 0x8a, 0x43, 0x28, 0xf4,
+  0x7d, 0x4e, 0x69, 0x13, 0x30, 0x32, 0xea, 0xf4, 0xea, 0xd8, 0xc7, 0xf4,
+  0xcb, 0xff, 0x4b, 0xd3, 0x8a, 0x36, 0x0c, 0xf0, 0x1f, 0x01, 0x4c, 0xd7,
+  0x41, 0x20, 0xc4, 0xde, 0xc7, 0xa5, 0x76, 0xf0, 0x65, 0xf3, 0x03, 0x10,
+  0x8e, 0xda, 0x7f, 0xd9, 0x89, 0x47, 0xce, 0x11, 0x88, 0x45, 0x36, 0x9d,
+  0x4c, 0x65, 0x5b, 0xea, 0xc5, 0xe5, 0x87, 0x75, 0x29, 0xd4, 0xff, 0x15,
+  0x4f, 0x7a, 0x3c, 0x4d, 0x07, 0x62, 0x8e, 0xab, 0x73, 0x26, 0x50, 0x02,
+  0xc6, 0x11, 0xf3, 0x34, 0x3b, 0x82, 0x52, 0xb1, 0xe1, 0x64, 0x9e, 0x9b,
+  0xff, 0x10, 0x40, 0x08, 0x0e, 0x34, 0x01, 0x33, 0x82, 0x6f, 0x4b, 0x46,
+  0x80, 0x42, 0xb2, 0xb1, 0x45, 0xdd, 0xed, 0x99, 0x39, 0x18, 0x28, 0xbc,
+  0xa8, 0xe1, 0xf1, 0x90, 0x4b, 0xfa, 0xf2, 0x6a, 0x9c, 0xa2, 0x06, 0xdc,
+  0xfe, 0x97, 0x20, 0x51, 0x24, 0xb8, 0x07, 0x1a, 0x1c, 0x7d, 0xa4, 0x7b,
+  0x68, 0x93, 0x9e, 0x2e, 0x4c, 0x3b, 0xd9, 0xae, 0x77, 0x97, 0x40, 0xd2,
+  0xd4, 0x92, 0x51, 0x39, 0x2a, 0x19, 0x10, 0x05, 0x91, 0xfc, 0x7f, 0x96,
+  0x34, 0x80, 0x4b, 0x8c, 0x0c, 0x61, 0x46, 0x8f, 0xd1, 0xf7, 0x62, 0xad,
+  0x6a, 0xfd, 0x78, 0xb9, 0x9d, 0x45, 0x8c, 0x95, 0x44, 0x21, 0xdc, 0x35,
+  0xa9, 0x92, 0x31, 0xb5, 0x06, 0x1a, 0x79, 0x46, 0x16, 0x28, 0x51, 0x4b,
+  0x48, 0x56, 0x68, 0x31, 0x45, 0x46, 0xcd, 0x05, 0x0a, 0x18, 0x7c, 0x9f,
+  0x64, 0xec, 0xb6, 0x6a, 0xf4, 0xed, 0x0f, 0x86, 0xd0, 0x28, 0x24, 0x5e,
+  0x86, 0x1c, 0xa5, 0x61, 0x03, 0x95, 0x39, 0x40, 0x17, 0xf9, 0x82, 0xd3,
+  0xf8, 0xc5, 0x2a, 0x8c, 0xde, 0x73, 0xc3, 0x7a, 0x7b, 0x91, 0x61, 0x86,
+  0x83, 0x09, 0xcf, 0xb0, 0x74, 0x3e, 0x7a, 0xc7, 0xe6, 0x76, 0x47, 0x2a,
+  0xf4, 0x7c, 0xe7, 0x0c, 0xc2, 0x63, 0x64, 0xc6, 0x57, 0x80, 0x17, 0x08,
+  0x14, 0x17, 0xe7, 0x21, 0xdb, 0x66, 0x54, 0x18, 0x88, 0x0b, 0x65, 0x42,
+  0x97, 0x46, 0x7d, 0x91, 0x26, 0x5e, 0x59, 0x3c, 0x48, 0x06, 0xbc, 0x20,
+  0x66, 0x89, 0x39, 0x64, 0xd6, 0x5a, 0x7a, 0x05, 0x10, 0x89, 0x44, 0x4a,
+  0x73, 0x98, 0x3e, 0x9f, 0xb0, 0xc3, 0x3c, 0xea, 0x77, 0x95, 0xc6, 0xc5,
+  0x5b, 0x08, 0x07, 0x2b, 0xaa, 0x63, 0x25, 0x4c, 0xf6, 0xa7, 0x08, 0xf9,
+  0x42, 0x4c, 0xc7, 0xa9, 0xe9, 0x58, 0x0a, 0x9e, 0x4a, 0x0e, 0xf6, 0x2b,
+  0xf5, 0x35, 0x20, 0x55, 0x65, 0x46, 0xda, 0x32, 0xdc, 0xb5, 0x29, 0x4a,
+  0x79, 0x2a, 0x1e, 0x20, 0xa3, 0x3f, 0xfb, 0x5c, 0xf7, 0xce, 0x5f, 0x3b,
+  0x96, 0xb9, 0x16, 0xf4, 0x6f, 0xe9, 0x5b, 0x63, 0x86, 0x85, 0xbe, 0x7f,
+  0xe8, 0x3b, 0x30, 0xdb, 0xc0, 0xd4, 0xeb, 0xf8, 0xcd, 0x40, 0x4e, 0x72,
+  0x1f, 0x37, 0x74, 0xb7, 0x28, 0x93, 0xe2, 0x0d, 0xdf, 0x5b, 0x9f, 0xa0,
+  0x1b, 0x82, 0x13, 0x2d, 0x52, 0x3b, 0xdd, 0x17, 0x32, 0x93, 0x36, 0x82,
+  0x5f, 0x68, 0x3c, 0x1d, 0xf3, 0x54, 0xcd, 0x2e, 0x24, 0x5f, 0xcb, 0x73,
+  0x5e, 0xf1, 0x31, 0xf7, 0xb5, 0x3d, 0x6c, 0x43, 0x65, 0x2a, 0x8d, 0xf9,
+  0x05, 0xb2, 0xa4, 0x67, 0x46, 0x50, 0x65, 0x8a, 0xb0, 0xcc, 0xbf, 0xea,
+  0xa5, 0x46, 0xfd, 0x39, 0xb7, 0x75, 0xa8, 0x8f, 0xd3, 0x91, 0x5a, 0x79,
+  0x98, 0x2b, 0x7b, 0xa3, 0x97, 0x49, 0xa1, 0x08, 0xb4, 0x62, 0x97, 0x58,
+  0x13, 0x9b, 0xef, 0x5e, 0x7e, 0xfd, 0x23, 0xf7, 0x6f, 0xf2, 0xfc, 0x79,
+  0x9f, 0x5a, 0x56, 0x33, 0x0d, 0x73, 0x67, 0x9a, 0x9b, 0xed, 0xc0, 0x30,
+  0xe2, 0xa3, 0x5e, 0x12, 0x91, 0x3f, 0x68, 0x95, 0xbf, 0x77, 0xfd, 0xd4,
+  0x4d, 0x8b, 0xd5, 0xf6, 0xb1, 0x4c, 0x95, 0xb7, 0x50, 0xba, 0xb5, 0xf1,
+  0x06, 0x33, 0xd2, 0x9b, 0x32, 0x8b, 0xb9, 0x34, 0x4b, 0xe3, 0x4c, 0x91,
+  0xdc, 0x27, 0xd7, 0xa9, 0x61, 0xe2, 0xfb, 0x41, 0xf7, 0xf6, 0xb9, 0x67,
+  0x3d, 0x38, 0x5a, 0xc7, 0xf5, 0x62, 0xae, 0x9b, 0x86, 0x65, 0x29, 0xa8,
+  0x90, 0x03, 0x3a, 0x27, 0x48, 0xe2, 0x63, 0x0c, 0xaf, 0xa8, 0x26, 0xfd,
+  0x8f, 0xee, 0xb7, 0x22, 0xa9, 0x97, 0x6d, 0x8b, 0xe7, 0x56, 0x56, 0xec,
+  0x50, 0x9d, 0x18, 0x20, 0x59, 0xc8, 0x4c, 0x9d, 0xe8, 0xfd, 0x86, 0x6e,
+  0xb9, 0xfd, 0xa6, 0x95, 0x30, 0x02, 0xa9, 0x4b, 0xb0, 0x83, 0x51, 0x8f,
+  0x6d, 0x00, 0x75, 0xd1, 0x37, 0x85, 0x47, 0xec, 0x75, 0xb3, 0xab, 0xb3,
+  0xf4, 0xd3, 0x62, 0x2d, 0x95, 0x0f, 0xe6, 0xd6, 0xbb, 0x49, 0xc2, 0x08,
+  0x77, 0x4b, 0x91, 0x18, 0xc2, 0xb3, 0x90, 0x99, 0x90, 0x81, 0x2b, 0xc9,
+  0xba, 0x79, 0xe3, 0xca, 0x1b, 0x71, 0x5a, 0x6d, 0xbc, 0xd9, 0x98, 0x92,
+  0xba, 0x7b, 0xe5, 0xeb, 0x9b, 0x29, 0xde, 0x6e, 0x85, 0x20, 0x10, 0x82,
+  0xb0, 0x0a, 0x73, 0x3a, 0xd1, 0xf6, 0x58, 0x5a, 0xd7, 0xc6, 0xb6, 0x29,
+  0x42, 0xca, 0x32, 0x3b, 0x04, 0xa2, 0xd4, 0x09, 0x93, 0xf6, 0xb9, 0x2a,
+  0x12, 0xfb, 0x52, 0x22, 0xfc, 0xbe, 0x66, 0xb3, 0x71, 0xd1, 0xdc, 0xe6,
+  0xf5, 0xd4, 0x09, 0xea, 0xd5, 0x57, 0x35, 0x1d, 0x00, 0x09, 0x44, 0xcc,
+  0x94, 0x65, 0x4a, 0x52, 0xee, 0x44, 0xb5, 0x26, 0xe3, 0x8c, 0xef, 0x61,
+  0x65, 0x73, 0x37, 0xed, 0x4b, 0x8c, 0xa4, 0x08, 0x32, 0x87, 0x21, 0xd1,
+  0x26, 0xad, 0xbf, 0xb4, 0xf6, 0x4e, 0x57, 0x4e, 0x53, 0xa2, 0xed, 0x3c,
+  0xdd, 0xda, 0x70, 0x93, 0xd3, 0x12, 0x9d, 0x69, 0x85, 0x02, 0x06, 0x3c,
+  0x27, 0x27, 0x0b, 0xc9, 0x21, 0xe0, 0x7f, 0xf6, 0xb1, 0x38, 0xe9, 0xbd,
+  0x22, 0x14, 0xd8, 0x83, 0x79, 0x36, 0x90, 0x08, 0x76, 0x50, 0xb0, 0xab,
+  0xc6, 0xd6, 0x75, 0xe5, 0x32, 0x3f, 0xcf, 0xc7, 0x05, 0x7e, 0x98, 0x9b,
+  0xe4, 0x1b, 0xda, 0x72, 0x06, 0xc2, 0x45, 0x5e, 0x9b, 0xf6, 0x6d, 0xcb,
+  0xe7, 0x82, 0x8c, 0xc7, 0xff, 0x56, 0xdc, 0xb2, 0x2f, 0xee, 0x6d, 0xe0,
+  0xd3, 0x5d, 0x87, 0xcc, 0x8a, 0xbc, 0xe3, 0xb5, 0xa3, 0xe9, 0xb2, 0x89,
+  0x82, 0x60, 0xb7, 0x73, 0x74, 0xb0, 0xf0, 0x3b, 0x28, 0x20, 0xb0, 0x1e,
+  0xe3, 0x3f, 0x8b, 0x7f, 0xf7, 0xf6, 0x43, 0x4d, 0x33, 0xb2, 0x02, 0x27,
+  0x4d, 0x8d, 0x80, 0xfc, 0xd1, 0xe0, 0x24, 0xe7, 0x82, 0xdf, 0xe9, 0x1c,
+  0x62, 0x34, 0xd2, 0x9b, 0xd1, 0x9a, 0x5f, 0x61, 0x6a, 0xd4, 0xd9, 0x8f,
+  0x5c, 0x8e, 0xa3, 0x19, 0x6b, 0xd2, 0xda, 0x16, 0x54, 0xc4, 0xf8, 0xb1,
+  0x95, 0x48, 0x3e, 0x26, 0x5c, 0x27, 0x1c, 0xf2, 0xd2, 0x0d, 0x36, 0x3f,
+  0x69, 0x9e, 0x6d, 0x81, 0x86, 0x1f, 0x50, 0xcd, 0xa9, 0x76, 0x08, 0xe1,
+  0xd3, 0xb0, 0xda, 0xfb, 0xd8, 0x5d, 0x93, 0xb1, 0x8e, 0x6d, 0x14, 0xed,
+  0xdf, 0xf7, 0x57, 0xff, 0xff, 0x8c, 0x4d, 0x15, 0x36, 0x21, 0x87, 0x64,
+  0xb0, 0x67, 0xe5, 0x89, 0x90, 0x9a, 0x26, 0x86, 0xa5, 0x2c, 0x20, 0xc3,
+  0xcd, 0x4b, 0x7c, 0x6c, 0xc0, 0xfa, 0x40, 0xca, 0x08, 0x65, 0xa3, 0x40,
+  0x31, 0x9a, 0x59, 0xfb, 0x46, 0xd7, 0xe7, 0xda, 0xa1, 0x46, 0x9b, 0x3c,
+  0x05, 0x40, 0x11, 0x5e, 0x7e, 0xd5, 0x8e, 0x58, 0xaf, 0x43, 0x0c, 0x86,
+  0x5f, 0x88, 0x37, 0x81, 0x4e, 0x7c, 0xea, 0xdf, 0x32, 0xde, 0x9d, 0x7f,
+  0x43, 0x1c, 0x15, 0x96, 0x10, 0xe4, 0xe8, 0x50, 0xab, 0x6f, 0x37, 0x6a,
+  0xf7, 0x6c, 0x68, 0x21, 0xda, 0x19, 0x5d, 0x2d, 0xc7, 0x9d, 0xcc, 0x88,
+  0x18, 0x8c, 0xe3, 0x00, 0x68, 0x05, 0x1c, 0xa2, 0x6a, 0xc3, 0xaf, 0xbd,
+  0xd1, 0xb3, 0xc5, 0xba, 0xa5, 0xb7, 0xc6, 0x91, 0xf3, 0x4f, 0x1c, 0xba,
+  0x10, 0x23, 0x21, 0x2a, 0x4e, 0xd8, 0xf9, 0x72, 0xf1, 0x3a, 0x7b, 0xab,
+  0x9c, 0x2d, 0xec, 0x6f, 0x2b, 0x15, 0xcb, 0x38, 0xa6, 0x60, 0x83, 0x5a,
+  0x08, 0x9d, 0xed, 0x67, 0xb5, 0x27, 0x2b, 0xb9, 0x0b, 0xa0, 0x8f, 0xf6,
+  0xfd, 0x68, 0x27, 0xe6, 0xbb, 0x6b, 0x53, 0x86, 0x30, 0x14, 0x1b, 0x89,
+  0x51, 0x39, 0x5b, 0x38, 0x60, 0xce, 0x8d, 0x65, 0xc7, 0x81, 0xbd, 0x5e,
+  0xd1, 0x08, 0xdd, 0x65, 0x15, 0x1d, 0xff, 0xfa, 0x86, 0x2d, 0x9c, 0x1d,
+  0xf3, 0x01, 0xc3, 0xc3, 0x38, 0x6a, 0x9a, 0x65, 0x38, 0xc2, 0x82, 0x38,
+  0xef, 0xe3, 0x70, 0xc2, 0xc9, 0xf3, 0xc3, 0x99, 0x75, 0x14, 0xa9, 0x85,
+  0x21, 0x5a, 0xd2, 0xd0, 0xd0, 0x4a, 0x26, 0x31, 0xc7, 0x90, 0xee, 0x41,
+  0x9a, 0x8f, 0xbf, 0x9d, 0xaf, 0x4b, 0x7b, 0x56, 0x23, 0x6e, 0xbf, 0x6b,
+  0x87, 0x1a, 0x56, 0x91, 0xe5, 0xec, 0xf9, 0xbe, 0xe1, 0x51, 0xaf, 0x50,
+  0xcb, 0xee, 0x4e, 0x33, 0xdf, 0xb3, 0xbe, 0x8e, 0xed, 0x7a, 0x47, 0x12,
+  0x0e, 0x28, 0xa8, 0xe3, 0x41, 0xb0, 0xdb, 0x12, 0xaf, 0x10, 0x0e, 0x32,
+  0x13, 0x99, 0xf9, 0xf0, 0xf5, 0x48, 0x61, 0xa2, 0xec, 0x3a, 0x8c, 0x5c,
+  0xa8, 0xab, 0xef, 0x77, 0xea, 0xe2, 0x8a, 0xc8, 0xb3, 0x8d, 0xcf, 0x70,
+  0xf0, 0x4d, 0x7e, 0x1c, 0xa2, 0x40, 0x6a, 0x28, 0x50, 0x3e, 0x29, 0x5f,
+  0x76, 0x05, 0x99, 0x90, 0x18, 0xf8, 0x48, 0xa8, 0xb5, 0x77, 0xd9, 0xb8,
+  0xd5, 0xba, 0x6a, 0x58, 0xdb, 0x83, 0x72, 0x62, 0xee, 0xfa, 0x70, 0x4b,
+  0x97, 0x4b, 0x45, 0x00, 0x68, 0xc1, 0x23, 0xdc, 0x09, 0xd8, 0x3c, 0xca,
+  0xb8, 0x73, 0xab, 0x6d, 0x6e, 0x27, 0x95, 0xcd, 0x42, 0x2f, 0x51, 0x2e,
+  0x70, 0x65, 0x1a, 0x06, 0x67, 0x1b, 0x09, 0xf6, 0xf0, 0x02, 0x40, 0x59,
+  0x3a, 0x77, 0x1b, 0x9d, 0x52, 0x3e, 0x46, 0xc7, 0x5a, 0x4e, 0xdc, 0xa6,
+  0x6e, 0x3f, 0x6c, 0xdc, 0x82, 0x1b, 0x16, 0x66, 0x43, 0x23, 0x32, 0xab,
+  0x27, 0x78, 0xb1, 0x5d, 0xad, 0x54, 0x48, 0x9a, 0x3e, 0x7b, 0x49, 0x60,
+  0x6d, 0x2d, 0xd9, 0xbf, 0x29, 0xa1, 0xa7, 0xb7, 0x34, 0x09, 0x94, 0xa0,
+  0x64, 0xbf, 0x04, 0xf7, 0x8f, 0x5b, 0x71, 0xfa, 0xa5, 0x9c, 0xdb, 0x43,
+  0x1c, 0x0c, 0x66, 0x7b, 0x21, 0xd3, 0xe3, 0x69, 0x6e, 0xf8, 0x67, 0x04,
+  0x3c, 0xb1, 0xa6, 0x7c, 0x57, 0xea, 0x83, 0x08, 0x45, 0x2e, 0x5d, 0x1a,
+  0x8d, 0x02, 0xe4, 0xe5, 0xfc, 0x61, 0x50, 0x61, 0x13, 0x9b, 0x6e, 0x54,
+  0x28, 0x0a, 0x09, 0xd7, 0x97, 0x2c, 0x72, 0x27, 0xb6, 0xa8, 0xe5, 0x43,
+  0x27, 0x29, 0xcf, 0xc4, 0x05, 0x2b, 0x78, 0xed, 0x69, 0xe0, 0x20, 0x48,
+  0x8c, 0x02, 0x5f, 0x40, 0x71, 0xfd, 0x39, 0xbe, 0x2f, 0xbb, 0xeb, 0xde,
+  0xbd, 0xb4, 0x2f, 0x97, 0xa0, 0xcc, 0xdb, 0xed, 0x1c, 0x73, 0x5e, 0x70,
+  0x32, 0xdf, 0x45, 0xcc, 0xf2, 0xbe, 0x80, 0xed, 0xf6, 0xce, 0x60, 0xeb,
+  0x66, 0x4a, 0x4b, 0x17, 0x87, 0xf1, 0x8c, 0x46, 0x0b, 0x5a, 0x74, 0x13,
+  0xcf, 0x51, 0x4c, 0xfa, 0x37, 0xb8, 0xe7, 0xf7, 0xf8, 0xbf, 0xb7, 0x0e,
+  0xee, 0x74, 0xff, 0x3e, 0x35, 0x0c, 0x3e, 0x5b, 0x64, 0x82, 0x27, 0x63,
+  0x27, 0x24, 0xa1, 0xf6, 0x0d, 0x99, 0xae, 0x3a, 0xe7, 0xe2, 0xf7, 0xdc,
+  0x47, 0x45, 0x00, 0x93, 0x0d, 0x9b, 0x37, 0xba, 0xce, 0x1c, 0x80, 0x44,
+  0x81, 0x4a, 0x28, 0x9a, 0xc1, 0xce, 0x2d, 0x49, 0xea, 0xe2, 0x73, 0xe7,
+  0xb0, 0x4c, 0xe3, 0x0d, 0x4e, 0xf7, 0x9a, 0x5c, 0x1d, 0xa0, 0xa2, 0xf4,
+  0x06, 0x12, 0x0f, 0x3d, 0x2d, 0x3f, 0xb7, 0xe5, 0xbf, 0xff, 0x60, 0x84,
+  0x94, 0x7a, 0xef, 0xce, 0xd2, 0x15, 0x1a, 0x80, 0x75, 0x18, 0x28, 0xb0,
+  0x9a, 0x08, 0x48, 0x43, 0x84, 0x6f, 0x83, 0xdb, 0xb0, 0xd0, 0x51, 0xf5,
+  0x15, 0x19, 0xc2, 0xc2, 0x53, 0xf9, 0xbf, 0x93, 0x37, 0xfc, 0xcb, 0x3a,
+  0x2f, 0x16, 0x6a, 0x54, 0x67, 0xa7, 0xa6, 0xe4, 0xd1, 0x25, 0xe0, 0x30,
+  0x06, 0x13, 0x00, 0x0a, 0x2e, 0x11, 0xf1, 0x33, 0x9e, 0xb4, 0xe7, 0x1c,
+  0xe3, 0x0c, 0x91, 0xfb, 0x52, 0x62, 0x46, 0xcd, 0xed, 0x77, 0x12, 0xff,
+  0x15, 0x7b, 0xd7, 0x3b, 0x22, 0xcd, 0xd7, 0xf4, 0x0c, 0xe1, 0x85, 0x68,
+  0x0a, 0x24, 0xd0, 0x07, 0x0e, 0xf5, 0x68, 0x5d, 0x55, 0xb5, 0xe3, 0x28,
+  0x68, 0x23, 0x40, 0xec, 0x0d, 0x94, 0x8c, 0xa8, 0x09, 0x77, 0x16, 0xe5,
+  0xab, 0xc5, 0xe8, 0x53, 0xe2, 0xc1, 0xce, 0x5c, 0xa9, 0x55, 0x10, 0xea,
+  0x9b, 0x3e, 0x8a, 0x1d, 0xae, 0x60, 0x1d, 0x09, 0xc7, 0xf7, 0xf5, 0xca,
+  0x92, 0x02, 0x5f, 0x35, 0x96, 0x74, 0x72, 0x85, 0x29, 0xf8, 0x04, 0x20,
+  0x70, 0xf7, 0xb9, 0x34, 0x46, 0x3a, 0xb2, 0x92, 0x05, 0x1f, 0xa3, 0x05,
+  0x5d, 0xb0, 0x10, 0x15, 0xbe, 0x01, 0x21, 0x03, 0x57, 0x46, 0xef, 0x43,
+  0x80, 0x10, 0xc9, 0x78, 0xf2, 0x33, 0x39, 0xd3, 0xc0, 0x6a, 0x92, 0xd9,
+  0x69, 0x22, 0xbf, 0xd9, 0xd1, 0xf4, 0xda, 0xb5, 0xe9, 0xe8, 0x65, 0x1a,
+  0x60, 0x3b, 0x19, 0xbd, 0x44, 0xe8, 0x89, 0x77, 0x28, 0xb9, 0xbb, 0xcd,
+  0x2d, 0xfb, 0x7b, 0xf0, 0x74, 0x32, 0xbf, 0x6f, 0x4c, 0x74, 0xf8, 0x0a,
+  0x0f, 0x31, 0x24, 0x51, 0xfa, 0x01, 0x51, 0xe3, 0x8d, 0x4f, 0xfe, 0x08,
+  0x8d, 0x02, 0xd8, 0x71, 0xa3, 0xfd, 0xc8, 0x19, 0x7b, 0xd1, 0x87, 0x6c,
+  0x72, 0x73, 0x7f, 0x9e, 0x31, 0xb7, 0xbf, 0xc3, 0x6f, 0xcf, 0xd3, 0xd9,
+  0x7a, 0x3a, 0x76, 0xc5, 0xe5, 0xb9, 0x7b, 0x20, 0x13, 0xa3, 0x2d, 0xa1,
+  0x7a, 0xa2, 0x60, 0x49, 0xfd, 0xba, 0x2f, 0x2c, 0xb9, 0x48, 0x49, 0xfe,
+  0x80, 0x8e, 0xc4, 0xd0, 0x96, 0x92, 0xf7, 0x0e, 0x4e, 0x6d, 0x8c, 0x32,
+  0x1a, 0x3f, 0x14, 0xf8, 0x2d, 0x63, 0x44, 0x1d, 0x1d, 0xba, 0xc2, 0xcc,
+  0xa6, 0x36, 0x8b, 0x48, 0xd5, 0xea, 0x8e, 0x87, 0xce, 0x0c, 0xfb, 0x46,
+  0x0e, 0xb9, 0xa4, 0x68, 0x0c, 0x9f, 0xa6, 0xb3, 0xfd, 0x39, 0xad, 0x69,
+  0x2e, 0x53, 0x48, 0x9c, 0x02, 0xac, 0x51, 0xd8, 0x19, 0x24, 0x82, 0x1e,
+  0x24, 0x91, 0x52, 0x0f, 0xba, 0x53, 0x25, 0x07, 0x0e, 0x83, 0xe0, 0x09,
+  0x72, 0xa2, 0x32, 0x2c, 0xee, 0x0e, 0x88, 0x5b, 0x42, 0x25, 0x3c, 0x69,
+  0xb7, 0xc5, 0x9a, 0x07, 0xc0, 0x6b, 0x94, 0x28, 0x01, 0x39, 0x34, 0xd1,
+  0xab, 0xf4, 0x32, 0x55, 0x82, 0x3c, 0x07, 0x2a, 0x11, 0x7a, 0x10, 0xc9,
+  0x55, 0xaa, 0x84, 0x39, 0xd8, 0x3c, 0x4e, 0x09, 0x65, 0xe9, 0x03, 0x39,
+  0xd0, 0xf1, 0x79, 0x70, 0x83, 0x07, 0x68, 0x72, 0x4f, 0x3f, 0x8e, 0x05,
+  0xe1, 0x41, 0xe4, 0xf8, 0x1b, 0xc6, 0x13, 0xd4, 0x95, 0xed, 0xe5, 0x2f,
+  0xab, 0x97, 0xaf, 0xa9, 0x6b, 0x59, 0x3c, 0x09, 0xe3, 0x3d, 0x26, 0xdb,
+  0x04, 0x72, 0x19, 0x05, 0x28, 0x1f, 0x00, 0x67, 0x29, 0x2a, 0xe1, 0x7b,
+  0xdb, 0x8b, 0xfb, 0x71, 0xde, 0x13, 0x5f, 0xe1, 0xb6, 0x91, 0x99, 0x90,
+  0x99, 0x4a, 0xf8, 0xf0, 0x79, 0xe2, 0x2d, 0x76, 0x9b, 0x1e, 0x29, 0xed,
+  0xf7, 0x8b, 0xa2, 0x1c, 0xf9, 0xec, 0xde, 0xf4, 0x35, 0x40, 0xca, 0x4c,
+  0xf0, 0x30, 0x4a, 0xcb, 0x9f, 0x72, 0x0f, 0xfe, 0x06, 0xcd, 0x54, 0xb0,
+  0x5d, 0x30, 0x59, 0xd6, 0x0d, 0x7e, 0x7e, 0x71, 0x45, 0xb6, 0xc3, 0xac,
+  0x5b, 0x76, 0xa7, 0xc6, 0x67, 0x08, 0x2d, 0xd1, 0xa7, 0x32, 0x1a, 0x90,
+  0x83, 0xc1, 0x55, 0x6a, 0xca, 0x9c, 0x8e, 0xb3, 0x7b, 0x8f, 0xc5, 0x05,
+  0x4f, 0x91, 0xef, 0xee, 0xa5, 0x7d, 0xcd, 0xd6, 0xb0, 0xad, 0xc1, 0x94,
+  0x98, 0x20, 0x04, 0x26, 0x54, 0xd6, 0x72, 0xb4, 0x28, 0xe4, 0xe4, 0xdf,
+  0x43, 0x7e, 0xfd, 0x15, 0x17, 0x8d, 0xd9, 0xd4, 0x62, 0xa9, 0x62, 0x47,
+  0x6d, 0x32, 0x26, 0x11, 0x41, 0x04, 0x6f, 0x50, 0x3c, 0xd2, 0x9a, 0xeb,
+  0x76, 0x2e, 0x7e, 0xcf, 0xfe, 0xbc, 0xbd, 0xae, 0x5f, 0x23, 0x77, 0x86,
+  0x9c, 0xf1, 0x99, 0xa7, 0x8c, 0xd9, 0x21, 0x58, 0x07, 0x9b, 0x3b, 0xfa,
+  0xe4, 0xc1, 0x72, 0xd9, 0x01, 0xc5, 0xe5, 0xb8, 0xc0, 0xe8, 0xb9, 0x11,
+  0x96, 0xcf, 0x39, 0x8c, 0x8a, 0x77, 0x3e, 0xd7, 0x8d, 0x27, 0xf1, 0x0b,
+  0xfc, 0xa0, 0xa7, 0x7a, 0x61, 0x44, 0xcc, 0xfc, 0x15, 0xea, 0x0b, 0xf7,
+  0x74, 0x9b, 0xa7, 0xda, 0x73, 0x9b, 0xec, 0x62, 0x43, 0x19, 0xbb, 0x16,
+  0xba, 0x0d, 0x1e, 0xd6, 0xa1, 0x4c, 0xbd, 0x58, 0xac, 0xcf, 0x79, 0x9d,
+  0xf2, 0xbd, 0xfa, 0x9c, 0xfd, 0x79, 0x81, 0x0c, 0x7d, 0xb8, 0xe9, 0xf9,
+  0x99, 0x64, 0xee, 0xa9, 0xa4, 0xe9, 0xcc, 0x94, 0x09, 0x6c, 0x3d, 0x7e,
+  0x59, 0x55, 0x80, 0x5e, 0xf1, 0xf5, 0xff, 0x5d, 0x74, 0xf2, 0xea, 0xe6,
+  0xfa, 0xb1, 0x7a, 0x48, 0xeb, 0x72, 0x53, 0x18, 0x60, 0x14, 0xfb, 0x54,
+  0x72, 0xab, 0x04, 0x13, 0xa7, 0x47, 0xfb, 0xbb, 0x21, 0x14, 0x3d, 0xd3,
+  0x56, 0x53, 0x89, 0xa4, 0x6b, 0x02, 0x79, 0x83, 0x74, 0x85, 0x2e, 0x9c,
+  0xbe, 0x03, 0xf4, 0x0b, 0xa2, 0xdc, 0xf2, 0xdb, 0x57, 0x2a, 0x25, 0x5b,
+  0x63, 0x01, 0x67, 0x18, 0xc4, 0x1c, 0xa7, 0xfa, 0x99, 0xc2, 0x3d, 0x26,
+  0xaf, 0x9b, 0x9f, 0x9f, 0x4c, 0x03, 0x73, 0xb9, 0xd7, 0x98, 0x22, 0x67,
+  0x0e, 0x5c, 0x60, 0xc8, 0xf8, 0xc0, 0x54, 0x9b, 0xfb, 0x4c, 0xd9, 0x38,
+  0xf8, 0xfc, 0x90, 0x78, 0x5b, 0xeb, 0xf0, 0xe9, 0x3f, 0xa5, 0x32, 0xc8,
+  0x28, 0xc3, 0xf8, 0x6f, 0x63, 0x62, 0x59, 0x54, 0xf1, 0x81, 0xc9, 0xa1,
+  0xf3, 0x97, 0xdf, 0x1f, 0xff, 0xfb, 0x75, 0xe3, 0xf2, 0xc3, 0x2d, 0x7c,
+  0x6f, 0x41, 0xa1, 0xa0, 0x1d, 0xc8, 0x34, 0x44, 0xca, 0x15, 0x93, 0xde,
+  0xda, 0xb9, 0x17, 0x93, 0x7f, 0x17, 0x5a, 0xfe, 0xe1, 0x3b, 0x94, 0x4c,
+  0xd9, 0x54, 0x27, 0x08, 0x13, 0x9c, 0x04, 0x89, 0x65, 0x51, 0xee, 0x41,
+  0xd7, 0x93, 0x1b, 0xef, 0x40, 0x6f, 0xac, 0xc5, 0x55, 0xe5, 0xad, 0x42,
+  0xa2, 0x65, 0xf7, 0x7a, 0xc3, 0xae, 0x99, 0xc8, 0xd3, 0x44, 0x7d, 0x36,
+  0x47, 0xaa, 0xe2, 0xd9, 0xe2, 0xa0, 0xcf, 0x34, 0xb7, 0xca, 0x0f, 0x2e,
+  0x9f, 0xa5, 0x21, 0x07, 0xf6, 0x70, 0x32, 0x34, 0xf2, 0xcf, 0x19, 0x19,
+  0xa2, 0x28, 0x4b, 0xea, 0x0f, 0x34, 0xbb, 0x4a, 0x27, 0x17, 0x35, 0xc7,
+  0x27, 0x12, 0xda, 0xd7, 0x9d, 0xde, 0x30, 0x71, 0xda, 0x0c, 0x6a, 0xbe,
+  0x72, 0x0c, 0x6b, 0x00, 0xa6, 0xb7, 0xc5, 0x3a, 0x43, 0xfb, 0x3b, 0xe4,
+  0x20, 0x5a, 0x79, 0x10, 0xa9, 0x9e, 0xfc, 0x84, 0x48, 0xc6, 0x2b, 0xa0,
+  0xa4, 0x5a, 0x90, 0x13, 0x9e, 0xf1, 0x5f, 0x0f, 0x97, 0x0e, 0x5e, 0x10,
+  0xe2, 0x42, 0x1f, 0x22, 0x73, 0xe4, 0xe0, 0xa5, 0x2a, 0x0c, 0x7c, 0xae,
+  0x95, 0x57, 0x95, 0xb1, 0x40, 0x76, 0xc7, 0x0d, 0xa2, 0xe0, 0x30, 0x62,
+  0x77, 0x07, 0x07, 0x65, 0xd6, 0xef, 0x23, 0x8d, 0xac, 0x3c, 0xc9, 0x45,
+  0xe5, 0x21, 0xe2, 0x1f, 0xee, 0x96, 0x60, 0xae, 0x6f, 0x51, 0x3f, 0x11,
+  0x0c, 0xcd, 0x1a, 0x7b, 0x32, 0xa1, 0xda, 0xe3, 0x90, 0x05, 0x0a, 0xa9,
+  0x27, 0xaf, 0xc8, 0x39, 0xbe, 0xe1, 0x7a, 0xf7, 0x94, 0x22, 0x1a, 0xd2,
+  0xad, 0xc6, 0xa7, 0xb8, 0x77, 0x5b, 0x93, 0xe5, 0x4e, 0x50, 0x30, 0x8c,
+  0x0e, 0x12, 0x0f, 0x34, 0xb6, 0x7b, 0xe0, 0xef, 0x3b, 0xbb, 0xb6, 0x92,
+  0xe8, 0xfc, 0xd4, 0x1d, 0x67, 0x18, 0x8a, 0x50, 0x9a, 0x48, 0x81, 0x4f,
+  0x2f, 0x54, 0x12, 0xbe, 0xdb, 0xd2, 0x67, 0xae, 0x1d, 0x2a, 0x5f, 0x8d,
+  0x0f, 0x55, 0xbf, 0x40, 0x00, 0x00, 0x01, 0x0a
+};
+
+void
+vc1_get_video_info (VideoDecodeInfo * info)
+{
+  info->profile = GST_VAAPI_PROFILE_VC1_ADVANCED;
+  info->width = VC1_CLIP_WIDTH;
+  info->height = VC1_CLIP_HEIGHT;
+  info->data = vc1_clip;
+  info->data_size = VC1_CLIP_DATA_SIZE;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-vc1.h b/subprojects/gstreamer-vaapi/tests/internal/test-vc1.h
new file mode 100644 (file)
index 0000000..3b94864
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ *  test-vc1.h - VC-1 test data
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#ifndef TEST_VC1_H
+#define TEST_VC1_H
+
+#include <glib.h>
+#include "test-decode.h"
+
+void vc1_get_video_info(VideoDecodeInfo *info);
+
+#endif /* TEST_VC1_H */
diff --git a/subprojects/gstreamer-vaapi/tests/internal/test-windows.c b/subprojects/gstreamer-vaapi/tests/internal/test-windows.c
new file mode 100644 (file)
index 0000000..66f4e04
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ *  test-windows.c - Test GstVaapiWindow
+ *
+ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@splitted-desktop.com>
+ *  Copyright (C) 2012-2013 Intel Corporation
+ *    Author: Gwenole Beauchesne <gwenole.beauchesne@intel.com>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ *  Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include <gst/vaapi/gstvaapisurface.h>
+#include <gst/vaapi/gstvaapiimage.h>
+#if GST_VAAPI_USE_DRM
+# include <gst/vaapi/gstvaapidisplay_drm.h>
+# include <gst/vaapi/gstvaapiwindow_drm.h>
+#endif
+#if GST_VAAPI_USE_X11
+# include <gst/vaapi/gstvaapidisplay_x11.h>
+# include <gst/vaapi/gstvaapiwindow_x11.h>
+#endif
+#if GST_VAAPI_USE_WAYLAND
+# include <gst/vaapi/gstvaapidisplay_wayland.h>
+# include <gst/vaapi/gstvaapiwindow_wayland.h>
+#endif
+#if GST_VAAPI_USE_EGL
+# include <gst/vaapi/gstvaapidisplay_egl.h>
+# include <gst/vaapi/gstvaapiwindow_egl.h>
+#endif
+#include "image.h"
+
+static inline void
+pause (void)
+{
+  g_print ("Press any key to continue...\n");
+  getchar ();
+}
+
+static GstVaapiSurface *
+create_test_surface (GstVaapiDisplay * display, guint width, guint height)
+{
+  GstVaapiImage *image = NULL;
+  GstVaapiSurface *surface;
+  guint i;
+
+  static const GstVaapiChromaType chroma_type = GST_VAAPI_CHROMA_TYPE_YUV420;
+  static const GstVideoFormat image_formats[] = {
+    GST_VIDEO_FORMAT_NV12,
+    GST_VIDEO_FORMAT_YV12,
+    GST_VIDEO_FORMAT_I420,
+    GST_VIDEO_FORMAT_VUYA,
+    GST_VIDEO_FORMAT_ARGB,
+    GST_VIDEO_FORMAT_BGRA,
+    GST_VIDEO_FORMAT_RGBA,
+    GST_VIDEO_FORMAT_ABGR,
+    GST_VIDEO_FORMAT_UNKNOWN
+  };
+
+  surface = gst_vaapi_surface_new (display, chroma_type, width, height);
+  if (!surface)
+    g_error ("could not create Gst/VA surface");
+
+  for (i = 0; image_formats[i] != GST_VIDEO_FORMAT_UNKNOWN; i++) {
+    const GstVideoFormat format = image_formats[i];
+
+    image = image_generate (display, format, width, height);
+    if (!image)
+      break;
+    if (image_upload (image, surface))
+      break;
+  }
+  if (!image)
+    g_error ("could not create Gst/VA image");
+
+  if (!gst_vaapi_surface_sync (surface))
+    g_error ("could not complete image upload");
+
+  gst_vaapi_image_unref (image);
+  return surface;
+}
+
+int
+main (int argc, char *argv[])
+{
+  GstVaapiDisplay *display;
+  GstVaapiWindow *window;
+  GstVaapiSurface *surface;
+  guint flags = GST_VAAPI_PICTURE_STRUCTURE_FRAME;
+
+  static const guint width = 320;
+  static const guint height = 240;
+  static const guint win_width = 640;
+  static const guint win_height = 480;
+
+  gst_init (&argc, &argv);
+
+#if GST_VAAPI_USE_DRM
+  display = gst_vaapi_display_drm_new (NULL);
+  if (!display)
+    g_error ("could not create Gst/VA (DRM) display");
+
+  surface = create_test_surface (display, width, height);
+  if (!surface)
+    g_error ("could not create Gst/VA surface");
+
+  g_print ("#\n");
+  g_print ("# Create window with gst_vaapi_window_drm_new()\n");
+  g_print ("#\n");
+  {
+    window = gst_vaapi_window_drm_new (display, win_width, win_height);
+    if (!window)
+      g_error ("could not create dummy window");
+
+    gst_vaapi_window_show (window);
+
+    if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL, flags))
+      g_error ("could not render surface");
+
+    pause ();
+    gst_object_unref (window);
+  }
+
+  gst_vaapi_surface_unref (surface);
+  gst_object_unref (display);
+#endif
+
+#if GST_VAAPI_USE_X11
+  display = gst_vaapi_display_x11_new (NULL);
+  if (!display)
+    g_error ("could not create Gst/VA display");
+
+  surface = create_test_surface (display, width, height);
+  if (!surface)
+    g_error ("could not create Gst/VA surface");
+
+  g_print ("#\n");
+  g_print ("# Create window with gst_vaapi_window_x11_new()\n");
+  g_print ("#\n");
+  {
+    window = gst_vaapi_window_x11_new (display, win_width, win_height);
+    if (!window)
+      g_error ("could not create window");
+
+    gst_vaapi_window_show (window);
+
+    if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL, flags))
+      g_error ("could not render surface");
+
+    pause ();
+    gst_object_unref (window);
+  }
+
+  g_print ("#\n");
+  g_print ("# Create window with gst_vaapi_window_x11_new_with_xid()\n");
+  g_print ("#\n");
+  {
+    Display *const dpy =
+        gst_vaapi_display_x11_get_display (GST_VAAPI_DISPLAY_X11 (display));
+    Window rootwin, win;
+    int screen;
+    unsigned long white_pixel, black_pixel;
+
+    screen = DefaultScreen (dpy);
+    rootwin = RootWindow (dpy, screen);
+    white_pixel = WhitePixel (dpy, screen);
+    black_pixel = BlackPixel (dpy, screen);
+
+    win = XCreateSimpleWindow (dpy,
+        rootwin, 0, 0, win_width, win_height, 0, black_pixel, white_pixel);
+    if (!win)
+      g_error ("could not create X window");
+
+    window = gst_vaapi_window_x11_new_with_xid (display, win);
+    if (!window)
+      g_error ("could not create window");
+
+    gst_vaapi_window_show (window);
+
+    if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL, flags))
+      g_error ("could not render surface");
+
+    pause ();
+    gst_object_unref (window);
+    XUnmapWindow (dpy, win);
+    XDestroyWindow (dpy, win);
+  }
+
+  gst_vaapi_surface_unref (surface);
+  gst_object_unref (display);
+#endif
+
+#if GST_VAAPI_USE_WAYLAND
+  display = gst_vaapi_display_wayland_new (NULL);
+  if (!display)
+    g_error ("could not create Gst/VA (Wayland) display");
+
+  surface = create_test_surface (display, width, height);
+  if (!surface)
+    g_error ("could not create Gst/VA surface");
+
+  g_print ("#\n");
+  g_print ("# Create window with gst_vaapi_window_wayland_new()\n");
+  g_print ("#\n");
+  {
+    window = gst_vaapi_window_wayland_new (display, win_width, win_height);
+    if (!window)
+      g_error ("could not create window");
+
+    gst_vaapi_window_show (window);
+
+    if (!gst_vaapi_window_put_surface (window, surface, NULL, NULL, flags))
+      g_error ("could not render surface");
+
+    pause ();
+    gst_object_unref (window);
+  }
+
+  gst_vaapi_surface_unref (surface);
+  gst_object_unref (display);
+#endif
+
+  gst_deinit ();
+  return 0;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/y4mreader.c b/subprojects/gstreamer-vaapi/tests/internal/y4mreader.c
new file mode 100644 (file)
index 0000000..76847bb
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ * y4mreader.c - Y4M parser
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include "gst/vaapi/sysdeps.h"
+#include "y4mreader.h"
+
+/* format documentation:
+ * http://wiki.multimedia.cx/index.php?title=YUV4MPEG2 */
+
+static inline gboolean
+parse_int (const gchar * str, guint * out_value_ptr)
+{
+  gint saved_errno;
+  glong value;
+  gboolean ret;
+
+  if (!str)
+    return FALSE;
+  str += 1;
+  if (*str == '\0')
+    return FALSE;
+
+  saved_errno = errno;
+  errno = 0;
+  value = strtol (str, NULL, 0);
+  ret = (errno == 0);
+  errno = saved_errno;
+  if (value > 0 && value <= G_MAXUINT)
+    *out_value_ptr = value;
+  else
+    ret = FALSE;
+
+  return ret;
+}
+
+static gboolean
+parse_header (Y4MReader * file)
+{
+  gint i, j, b;
+  guint8 header[BUFSIZ];
+  size_t s;
+  gchar *str;
+
+  memset (header, 0, BUFSIZ);
+  s = fread (header, 1, 9, file->fp);
+  if (s < 9)
+    return FALSE;
+
+  if (memcmp (header, "YUV4MPEG2", 9) != 0)
+    return FALSE;
+
+  for (i = 9; i < BUFSIZ - 1; i++) {
+    b = fgetc (file->fp);
+    if (b == EOF)
+      return FALSE;
+    if (b == 0xa)
+      break;
+    header[i] = b;
+  }
+
+  if (i == BUFSIZ - 1)
+    return FALSE;
+
+  j = 9;
+  while (j < i) {
+    if ((header[j] != 0x20) && (header[j - 1] == 0x20)) {
+      switch (header[j]) {
+        case 'W':
+          if (!parse_int ((gchar *) & header[j], &file->width))
+            return FALSE;
+          break;
+        case 'H':
+          if (!parse_int ((gchar *) & header[j], &file->height))
+            return FALSE;
+          break;
+        case 'C':
+          str = (char *) &header[j + 1];
+          if (strncmp (str, "420", 3) != 0) {
+            g_warning ("Unsupported chroma subsampling.");
+            return FALSE;       /* unsupported chroma subsampling */
+          }
+          break;
+        case 'I':
+          str = (char *) &header[j + 1];
+          if (*str != 'p' && *str != '?') {
+            g_warning ("Interlaced content are not supported.");
+            return FALSE;       /* interlaced is unsupported */
+          }
+          break;
+        case 'F':              /* frame rate ratio */
+        {
+          guint num, den;
+
+          if (!parse_int ((gchar *) & header[j], &num))
+            return FALSE;
+          while ((header[j] != ':') && (j < i))
+            j++;
+          if (!parse_int ((gchar *) & header[j], &den))
+            return FALSE;
+
+          if (num <= 0 || den <= 0) {
+            file->fps_n = 30;   /* default to 30 fps */
+            file->fps_d = 1;
+          } else {
+            file->fps_n = num;
+            file->fps_d = den;
+          }
+          break;
+        }
+        case 'A':              /* sample aspect ration */
+          break;
+        case 'X':              /* metadata */
+          break;
+        default:
+          break;
+      }
+    }
+    j++;
+  }
+
+  return TRUE;
+}
+
+Y4MReader *
+y4m_reader_open (const gchar * filename)
+{
+  Y4MReader *imagefile;
+
+  imagefile = g_slice_new0 (Y4MReader);
+
+  if (filename) {
+    imagefile->fp = fopen (filename, "r");
+    if (!imagefile->fp) {
+      g_warning ("open file %s error", filename);
+      goto bail;
+    }
+  } else {
+    imagefile->fp = stdin;
+  }
+
+  if (!parse_header (imagefile))
+    goto bail;
+
+  return imagefile;
+
+bail:
+  if (imagefile->fp && imagefile->fp != stdin)
+    fclose (imagefile->fp);
+
+  g_slice_free (Y4MReader, imagefile);
+  return NULL;
+}
+
+void
+y4m_reader_close (Y4MReader * file)
+{
+  g_return_if_fail (file);
+
+  if (file->fp && file->fp != stdin)
+    fclose (file->fp);
+
+  g_slice_free (Y4MReader, file);
+}
+
+static gboolean
+skip_frame_header (Y4MReader * file)
+{
+  gint i, b;
+  guint8 header[BUFSIZ];
+  size_t s;
+
+  memset (header, 0, BUFSIZ);
+  s = fread (header, 1, 5, file->fp);
+  if (s < 5)
+    return FALSE;
+
+  if (memcmp (header, "FRAME", 5) != 0)
+    return FALSE;
+
+  for (i = 5; i < BUFSIZ - 1; i++) {
+    b = fgetc (file->fp);
+    if (b == EOF)
+      return FALSE;
+    if (b == 0xa)
+      break;
+    header[i] = b;
+  }
+
+  return (i < BUFSIZ - 1);
+}
+
+gboolean
+y4m_reader_load_image (Y4MReader * file, GstVaapiImage * image)
+{
+  guint8 *plane;
+  size_t s;
+  guint frame_size, stride, i;
+
+  g_return_val_if_fail (gst_vaapi_image_is_mapped (image), FALSE);
+  g_return_val_if_fail (file && file->fp, FALSE);
+
+  /* only valid for I420 */
+  frame_size = file->height * file->width * 3 / 2;
+  if (gst_vaapi_image_get_data_size (image) < frame_size)
+    return FALSE;
+  if (gst_vaapi_image_get_plane_count (image) != 3)
+    return FALSE;
+
+  if (!skip_frame_header (file))
+    return FALSE;
+
+  /* Y plane */
+  plane = gst_vaapi_image_get_plane (image, 0);
+  stride = gst_vaapi_image_get_pitch (image, 0);
+  for (i = 0; i < file->height; i++) {
+    s = fread (plane, 1, file->width, file->fp);
+    if (s != file->width)
+      return FALSE;
+    plane += stride;
+  }
+
+  /* U plane */
+  plane = gst_vaapi_image_get_plane (image, 1);
+  stride = gst_vaapi_image_get_pitch (image, 1);
+  for (i = 0; i < file->height / 2; i++) {
+    s = fread (plane, 1, file->width / 2, file->fp);
+    if (s != file->width / 2)
+      return FALSE;
+    plane += stride;
+  }
+
+  /* V plane */
+  plane = gst_vaapi_image_get_plane (image, 2);
+  stride = gst_vaapi_image_get_pitch (image, 2);
+  for (i = 0; i < file->height / 2; i++) {
+    s = fread (plane, 1, file->width / 2, file->fp);
+    if (s != file->width / 2)
+      return FALSE;
+    plane += stride;
+  }
+
+  return TRUE;
+}
diff --git a/subprojects/gstreamer-vaapi/tests/internal/y4mreader.h b/subprojects/gstreamer-vaapi/tests/internal/y4mreader.h
new file mode 100644 (file)
index 0000000..369efb6
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * y4mreader.h - Y4M parser
+ *
+ * Copyright (C) 2015 Intel Corporation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ */
+
+#include <gst/gst.h>
+#include <stdio.h>
+#include <gst/vaapi/gstvaapiimage.h>
+
+typedef struct _Y4MReader Y4MReader;
+
+struct _Y4MReader
+{
+  FILE *fp;
+  guint width;
+  guint height;
+  gint fps_n;
+  gint fps_d;
+};
+
+Y4MReader *y4m_reader_open (const gchar * filename);
+
+void y4m_reader_close (Y4MReader * file);
+
+gboolean y4m_reader_load_image (Y4MReader * file, GstVaapiImage * image);
diff --git a/subprojects/gstreamer-vaapi/tests/meson.build b/subprojects/gstreamer-vaapi/tests/meson.build
new file mode 100644 (file)
index 0000000..2b8b815
--- /dev/null
@@ -0,0 +1,8 @@
+if not get_option('tests').disabled() and gstcheck_dep.found()
+  subdir('check')
+endif
+
+if not get_option('examples').disabled()
+  subdir('examples')
+  subdir('internal')
+endif