[packages/gstreamer-vaapi] Added patch for gstreamer 1.2 (note: new sonames), release 2

wiget wiget at pld-linux.org
Sat Sep 28 13:19:03 CEST 2013


commit f29a028ed0435565f3e63914821dfaab34cce5bc
Author: Artur Frysiak <artur at frysiak.net>
Date:   Sat Sep 28 13:18:21 2013 +0200

    Added patch for gstreamer 1.2 (note: new sonames), release 2

 git.patch            | 2163 ++++++++++++++++++++++++++++++++++++++++++++++++++
 gstreamer-vaapi.spec |   73 +-
 2 files changed, 2203 insertions(+), 33 deletions(-)
---
diff --git a/gstreamer-vaapi.spec b/gstreamer-vaapi.spec
index f5ae2bc..e66b432 100644
--- a/gstreamer-vaapi.spec
+++ b/gstreamer-vaapi.spec
@@ -2,23 +2,26 @@
 # Conditional build:
 %bcond_without	static_libs	# static libraries
 #
+%define		gstapi	1.2
+#
 Summary:	GStreamer plugin to support Video Acceleration API
 Summary(pl.UTF-8):	Wtyczka GStreamera obsługująca Video Acceleration API
 Name:		gstreamer-vaapi
 Version:	0.5.6
-Release:	1
+Release:	2
 License:	LGPL v2.1+
 Group:		Libraries
 Source0:	http://www.freedesktop.org/software/vaapi/releases/gstreamer-vaapi/%{name}-%{version}.tar.bz2
 # Source0-md5:	0a3e645d12c8f275e8ea221ecb89f981
+Patch0:		git.patch
 URL:		http://www.freedesktop.org/wiki/Software/vaapi/
 BuildRequires:	Mesa-libGL-devel
 BuildRequires:	autoconf >= 2.66
 BuildRequires:	automake >= 1:1.11
 BuildRequires:	glib2-devel >= 1:2.28.0
-BuildRequires:	gstreamer-devel >= 1.0.0
-BuildRequires:	gstreamer-plugins-bad-devel >= 1.0.0
-BuildRequires:	gstreamer-plugins-base-devel >= 1.0.0
+BuildRequires:	gstreamer-devel >= 1.2.0
+BuildRequires:	gstreamer-plugins-bad-devel >= 1.2.0
+BuildRequires:	gstreamer-plugins-base-devel >= 1.2.0
 BuildRequires:	gtk-doc >= 1.12
 BuildRequires:	libdrm-devel
 BuildRequires:	libtool >= 2:2.2
@@ -59,8 +62,8 @@ Summary:	Header files for GStreamer VA-API libraries
 Summary(pl.UTF-8):	Pliki nagłówkowe bibliotek VA-API GStreamera
 Group:		Development/Libraries
 Requires:	%{name} = %{version}-%{release}
-Requires:	gstreamer-devel >= 1.0.0
-Requires:	gstreamer-plugins-base-devel >= 1.0.0
+Requires:	gstreamer-devel >= 1.2.0
+Requires:	gstreamer-plugins-base-devel >= 1.2.0
 Requires:	libva-drm-devel >= 1.1.0
 Requires:	libva-glx-devel >= 1.0.9
 Requires:	libva-wayland-devel >= 1.1.0
@@ -86,6 +89,7 @@ Statyczne biblioteki VA-API GStreamera.
 
 %prep
 %setup -q
+%patch0 -p1
 
 %build
 %{__libtoolize}
@@ -95,7 +99,8 @@ Statyczne biblioteki VA-API GStreamera.
 %{__automake}
 %configure \
 	--disable-silent-rules \
-	%{!?with_static_libs:--disable-static}
+	%{!?with_static_libs:--disable-static} \
+	--with-gstreamer-api=%{gstapi}
 
 %{__make}
 
@@ -119,38 +124,40 @@ rm -rf $RPM_BUILD_ROOT
 %files
 %defattr(644,root,root,755)
 %doc AUTHORS NEWS README
-%attr(755,root,root) %{_libdir}/libgstvaapi-1.0.so.*.*.*
-%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-1.0.so.2
-%attr(755,root,root) %{_libdir}/libgstvaapi-drm-1.0.so.*.*.*
-%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-drm-1.0.so.2
-%attr(755,root,root) %{_libdir}/libgstvaapi-glx-1.0.so.*.*.*
-%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-glx-1.0.so.2
-%attr(755,root,root) %{_libdir}/libgstvaapi-wayland-1.0.so.*.*.*
-%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-wayland-1.0.so.2
-%attr(755,root,root) %{_libdir}/libgstvaapi-x11-1.0.so.*.*.*
-%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-x11-1.0.so.2
+%attr(755,root,root) %{_libdir}/libgstvaapi-%{gstapi}.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-%{gstapi}.so.0
+%attr(755,root,root) %{_libdir}/libgstvaapi-drm-%{gstapi}.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-drm-%{gstapi}.so.0
+%attr(755,root,root) %{_libdir}/libgstvaapi-glx-%{gstapi}.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-glx-%{gstapi}.so.0
+%attr(755,root,root) %{_libdir}/libgstvaapi-wayland-%{gstapi}.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-wayland-%{gstapi}.so.0
+%attr(755,root,root) %{_libdir}/libgstvaapi-x11-%{gstapi}.so.*.*.*
+%attr(755,root,root) %ghost %{_libdir}/libgstvaapi-x11-%{gstapi}.so.0
 %attr(755,root,root) %{_libdir}/gstreamer-1.0/libgstvaapi.so
 
 %files devel
 %defattr(644,root,root,755)
-%attr(755,root,root) %{_libdir}/libgstvaapi-1.0.so
-%attr(755,root,root) %{_libdir}/libgstvaapi-drm-1.0.so
-%attr(755,root,root) %{_libdir}/libgstvaapi-glx-1.0.so
-%attr(755,root,root) %{_libdir}/libgstvaapi-wayland-1.0.so
-%attr(755,root,root) %{_libdir}/libgstvaapi-x11-1.0.so
-%{_includedir}/gstreamer-1.0/gst/vaapi
-%{_pkgconfigdir}/gstreamer-vaapi-1.0.pc
-%{_pkgconfigdir}/gstreamer-vaapi-drm-1.0.pc
-%{_pkgconfigdir}/gstreamer-vaapi-glx-1.0.pc
-%{_pkgconfigdir}/gstreamer-vaapi-wayland-1.0.pc
-%{_pkgconfigdir}/gstreamer-vaapi-x11-1.0.pc
+%attr(755,root,root) %{_libdir}/libgstvaapi-%{gstapi}.so
+%attr(755,root,root) %{_libdir}/libgstvaapi-drm-%{gstapi}.so
+%attr(755,root,root) %{_libdir}/libgstvaapi-glx-%{gstapi}.so
+%attr(755,root,root) %{_libdir}/libgstvaapi-wayland-%{gstapi}.so
+%attr(755,root,root) %{_libdir}/libgstvaapi-x11-%{gstapi}.so
+%dir %{_includedir}/gstreamer-%{gstapi}
+%dir %{_includedir}/gstreamer-%{gstapi}/gst
+%{_includedir}/gstreamer-%{gstapi}/gst/vaapi
+%{_pkgconfigdir}/gstreamer-vaapi-%{gstapi}.pc
+%{_pkgconfigdir}/gstreamer-vaapi-drm-%{gstapi}.pc
+%{_pkgconfigdir}/gstreamer-vaapi-glx-%{gstapi}.pc
+%{_pkgconfigdir}/gstreamer-vaapi-wayland-%{gstapi}.pc
+%{_pkgconfigdir}/gstreamer-vaapi-x11-%{gstapi}.pc
 
 %if %{with static_libs}
 %files static
 %defattr(644,root,root,755)
-%{_libdir}/libgstvaapi-1.0.a
-%{_libdir}/libgstvaapi-drm-1.0.a
-%{_libdir}/libgstvaapi-glx-1.0.a
-%{_libdir}/libgstvaapi-wayland-1.0.a
-%{_libdir}/libgstvaapi-x11-1.0.a
+%{_libdir}/libgstvaapi-%{gstapi}.a
+%{_libdir}/libgstvaapi-drm-%{gstapi}.a
+%{_libdir}/libgstvaapi-glx-%{gstapi}.a
+%{_libdir}/libgstvaapi-wayland-%{gstapi}.a
+%{_libdir}/libgstvaapi-x11-%{gstapi}.a
 %endif
diff --git a/git.patch b/git.patch
new file mode 100644
index 0000000..836cbdb
--- /dev/null
+++ b/git.patch
@@ -0,0 +1,2163 @@
+diff --git a/configure.ac b/configure.ac
+index ac37510..f9029e3 100644
+--- a/configure.ac
++++ b/configure.ac
+@@ -1,8 +1,8 @@
+ # gstreamer-vaapi package version number
+ m4_define([gst_vaapi_major_version], [0])
+ m4_define([gst_vaapi_minor_version], [5])
+-m4_define([gst_vaapi_micro_version], [6])
+-m4_define([gst_vaapi_pre_version],   [0])
++m4_define([gst_vaapi_micro_version], [7])
++m4_define([gst_vaapi_pre_version],   [1])
+ m4_define([gst_vaapi_version],
+           [gst_vaapi_major_version.gst_vaapi_minor_version.gst_vaapi_micro_version])
+ m4_if(gst_vaapi_pre_version, [0], [], [
+@@ -13,6 +13,7 @@ m4_append([gst_vaapi_version], gst_vaapi_pre_version, [.pre])
+ m4_define([gst_vaapi_lt_current],       [4])
+ m4_define([gst0_vaapi_lt_current_bias], [0])
+ m4_define([gst1_vaapi_lt_current_bias], [2])
++m4_define([gst2_vaapi_lt_current_bias], [4])
+ m4_define([gst_vaapi_lt_revision],      [0])
+ m4_define([gst_vaapi_lt_age],           [0])
+ 
+@@ -27,6 +28,9 @@ m4_define([gst0_plugins_bad_version],   [0.10.22])
+ m4_define([gst1_version],               [1.0.0])
+ m4_define([gst1_plugins_base_version],  [1.0.0])
+ m4_define([gst1_plugins_bad_version],   [1.0.0])
++m4_define([gst12_version],              [1.1.90])
++m4_define([gst12_plugins_base_version], [1.1.0])
++m4_define([gst12_plugins_bad_version],  [1.1.0])
+ 
+ # Wayland minimum version number
+ m4_define([wayland_api_version], [1.0.0])
+@@ -158,6 +162,11 @@ case $GST_API_VERSION in
+     GST_PLUGINS_BASE_VERSION_REQUIRED=gst1_plugins_base_version
+     GST_PLUGINS_BAD_VERSION_REQUIRED=gst1_plugins_bad_version
+     ;;
++1.2)
++    GST_VERSION_REQUIRED=gst12_version
++    GST_PLUGINS_BASE_VERSION_REQUIRED=gst12_plugins_base_version
++    GST_PLUGINS_BAD_VERSION_REQUIRED=gst12_plugins_bad_version
++    ;;
+ *)
+     AC_MSG_ERROR([unsupported GStreamer API version $GST_API_VERSION])
+     ;;
+@@ -169,18 +178,29 @@ AC_SUBST(GST_PLUGINS_BAD_VERSION_REQUIRED)
+ 
+ USE_GST_API_0_10="no"
+ USE_GST_API_1_0p="no"
++USE_GST_API_1_2p="no"
+ AS_VERSION_COMPARE([$GST_API_VERSION], [0.10],
+     [], [USE_GST_API_0_10="yes"], [])
+ AS_VERSION_COMPARE([$GST_API_VERSION], [1.0],
+     [], [USE_GST_API_1_0p="yes"], [USE_GST_API_1_0p="yes"])
++AS_VERSION_COMPARE([$GST_API_VERSION], [1.2],
++    [], [USE_GST_API_1_2p="yes"], [USE_GST_API_1_2p="yes"])
+ AM_CONDITIONAL([USE_GST_API_0_10], [test "$USE_GST_API_0_10" = "yes"])
+ AM_CONDITIONAL([USE_GST_API_1_0p], [test "$USE_GST_API_1_0p" = "yes"])
++AM_CONDITIONAL([USE_GST_API_1_2p], [test "$USE_GST_API_1_2p" = "yes"])
++
++dnl GStreamer 1.2.x APIs don't have their own namespace
++GST_PKG_VERSION="$GST_API_VERSION"
++if test "$USE_GST_API_1_2p" = "yes"; then
++    GST_PKG_VERSION="1.0"
++fi
++AC_SUBST([GST_PKG_VERSION])
+ 
+ dnl GStreamer Core
+ PKG_CHECK_MODULES([GST],
+-    [gstreamer-$GST_API_VERSION >= $GST_VERSION_REQUIRED])
++    [gstreamer-$GST_PKG_VERSION >= $GST_VERSION_REQUIRED])
+ PKG_CHECK_MODULES([GST_BASE],
+-    [gstreamer-base-$GST_API_VERSION >= $GST_VERSION_REQUIRED])
++    [gstreamer-base-$GST_PKG_VERSION >= $GST_VERSION_REQUIRED])
+ 
+ AC_CACHE_CHECK([for GstBaseSink::query hook], ac_cv_have_gst_base_sink_query, [
+     saved_CPPFLAGS="$CPPFLAGS"
+@@ -203,15 +223,15 @@ fi
+ 
+ dnl GStreamer -base plugins
+ PKG_CHECK_MODULES([GST_PLUGINS_BASE],
+-    [gstreamer-plugins-base-$GST_API_VERSION >= $GST_PLUGINS_BASE_VERSION_REQUIRED])
++    [gstreamer-plugins-base-$GST_PKG_VERSION >= $GST_PLUGINS_BASE_VERSION_REQUIRED])
+ if test "$GST_API_VERSION" = "0.10"; then
+ PKG_CHECK_MODULES([GST_INTERFACES],
+-    [gstreamer-interfaces-$GST_API_VERSION >= $GST_PLUGINS_BASE_VERSION_REQUIRED])
++    [gstreamer-interfaces-$GST_PKG_VERSION >= $GST_PLUGINS_BASE_VERSION_REQUIRED])
+ fi
+ 
+ dnl ... GstVideoOverlayComposition (gstreamer-video)
+ PKG_CHECK_MODULES([GST_VIDEO],
+-    [gstreamer-video-$GST_API_VERSION >= $GST_PLUGINS_BASE_VERSION_REQUIRED])
++    [gstreamer-video-$GST_PKG_VERSION >= $GST_PLUGINS_BASE_VERSION_REQUIRED])
+ 
+ AC_CACHE_CHECK([for GstVideoOverlayComposition],
+     ac_cv_have_gst_video_overlay_composition, [
+@@ -288,9 +308,11 @@ AC_CACHE_CHECK([for GstVideoDecoder],
+ AM_CONDITIONAL([USE_LOCAL_GST_VIDEO_DECODER],
+     [test "$ac_cv_have_gst_video_decoder" != "yes"])
+ 
+-dnl GStreamer -bad plugins
++dnl GStreamer -bad plugins (deprecated in GStreamer v1.2)
++if test "$USE_GST_API_1_2p" != "yes"; then
+ PKG_CHECK_MODULES([GST_BASEVIDEO],
+-    [gstreamer-basevideo-$GST_API_VERSION >= $GST_PLUGINS_BAD_VERSION_REQUIRED])
++    [gstreamer-basevideo-$GST_PKG_VERSION >= $GST_PLUGINS_BAD_VERSION_REQUIRED])
++fi
+ 
+ dnl ... bitstream parsers
+ if test "$enable_builtin_codecparsers" = "yes"; then
+@@ -299,7 +321,7 @@ if test "$enable_builtin_codecparsers" = "yes"; then
+     ac_cv_have_gst_jpeg_parser="no"
+ else
+ PKG_CHECK_MODULES([GST_CODEC_PARSERS],
+-    [gstreamer-codecparsers-$GST_API_VERSION >= $GST_PLUGINS_BAD_VERSION_REQUIRED])
++    [gstreamer-codecparsers-$GST_PKG_VERSION >= $GST_PLUGINS_BAD_VERSION_REQUIRED])
+ fi
+ 
+ dnl ... MPEG-2 parser, with the required extensions
+@@ -378,6 +400,7 @@ AM_CONDITIONAL([USE_LOCAL_CODEC_PARSERS_JPEG],
+ case $GST_API_VERSION in
+ 0.10)   lt_bias=gst0_vaapi_lt_current_bias;;
+ 1.0)    lt_bias=gst1_vaapi_lt_current_bias;;
++1.2)    lt_bias=gst2_vaapi_lt_current_bias;;
+ esac
+ GST_VAAPI_MAJOR_VERSION=`expr gst_vaapi_lt_current - "$lt_bias"`
+ AC_SUBST(GST_VAAPI_MAJOR_VERSION)
+@@ -410,13 +433,14 @@ AC_MSG_CHECKING([for GStreamer plugins directory])
+ case $GST_API_VERSION in
+ 0.10)   _gst_plugin_path="$GST_PLUGIN_PATH";;
+ 1.0)    _gst_plugin_path="$GST_PLUGIN_PATH_1_0";;
++1.2)    _gst_plugin_path="$GST_PLUGIN_PATH_1_0";;
+ esac
+ if test -d "$_gst_plugin_path"; then
+     GST_PLUGINS_DIR="$_gst_plugin_path"
+ else
+-    GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_API_VERSION --variable pluginsdir`
++    GST_PLUGINS_DIR=`$PKG_CONFIG gstreamer-$GST_PKG_VERSION --variable pluginsdir`
+     if test -z "$GST_PLUGINS_DIR"; then
+-        GST_PLUGINS_DIR="\$(libdir)/gstreamer-$GST_API_VERSION"
++        GST_PLUGINS_DIR="\$(libdir)/gstreamer-$GST_PKG_VERSION"
+     fi
+ fi
+ AC_MSG_RESULT([$GST_PLUGINS_DIR])
+diff --git a/debian.upstream/control.in b/debian.upstream/control.in
+index 2ee6225..9897e9d 100644
+--- a/debian.upstream/control.in
++++ b/debian.upstream/control.in
+@@ -5,9 +5,9 @@ Maintainer: Gwenole Beauchesne <gwenole.beauchesne at intel.com>
+ Build-Depends: debhelper (>= 5),
+ 	       cdbs,
+ 	       libglib2.0-dev (>= @GLIB_VERSION_REQUIRED@),
+-	       libgstreamer at GST_API_VERSION@-dev (>= @GST_VERSION_REQUIRED@),
+-	       libgstreamer-plugins-base at GST_API_VERSION@-dev (>= @GST_PLUGINS_BASE_VERSION_REQUIRED@),
+-	       libgstreamer-plugins-bad at GST_API_VERSION@-dev (>= @GST_PLUGINS_BAD_VERSION_REQUIRED@),
++	       libgstreamer at GST_PKG_VERSION@-dev (>= @GST_VERSION_REQUIRED@),
++	       libgstreamer-plugins-base at GST_PKG_VERSION@-dev (>= @GST_PLUGINS_BASE_VERSION_REQUIRED@),
++	       libgstreamer-plugins-bad at GST_PKG_VERSION@-dev (>= @GST_PLUGINS_BAD_VERSION_REQUIRED@),
+ @USE_DRM_TRUE@	       libdrm-dev, libudev-dev,
+ @USE_X11_TRUE@	       libx11-dev, libxrandr-dev,
+ @USE_GLX_TRUE@	       libgl-dev,
+diff --git a/gst-libs/gst/vaapi/gstvaapidecoder.c b/gst-libs/gst/vaapi/gstvaapidecoder.c
+index 7870291..76a46ff 100644
+--- a/gst-libs/gst/vaapi/gstvaapidecoder.c
++++ b/gst-libs/gst/vaapi/gstvaapidecoder.c
+@@ -85,6 +85,7 @@ parser_state_prepare(GstVaapiParserState *ps, GstAdapter *adapter)
+ 
+ reset:
+     ps->current_adapter = adapter;
++    ps->input_offset1 = -1;
+     ps->input_offset2 = -1;
+ }
+ 
+diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c
+index 9e62778..c3655f0 100644
+--- a/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c
++++ b/gst-libs/gst/vaapi/gstvaapidecoder_jpeg.c
+@@ -47,6 +47,19 @@
+ 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;
+@@ -55,9 +68,9 @@ struct _GstVaapiDecoderJpegPrivate {
+     GstJpegFrameHdr             frame_hdr;
+     GstJpegHuffmanTables        huf_tables;
+     GstJpegQuantTables          quant_tables;
+-    gboolean                    has_huf_table;
+-    gboolean                    has_quant_table;
+     guint                       mcu_restart;
++    guint                       parser_state;
++    guint                       decoder_state;
+     guint                       is_opened       : 1;
+     guint                       profile_changed : 1;
+ };
+@@ -83,14 +96,17 @@ struct _GstVaapiDecoderJpegClass {
+     GstVaapiDecoderClass parent_class;
+ };
+ 
+-typedef struct _GstJpegScanSegment GstJpegScanSegment;
+-struct _GstJpegScanSegment {
+-    guint                       header_offset;
+-    guint                       header_size;
+-    guint                       data_offset;
+-    guint                       data_size;
+-    guint                       is_valid        : 1;
+-};
++static inline void
++unit_set_marker_code(GstVaapiDecoderUnit *unit, GstJpegMarkerCode marker)
++{
++    unit->parsed_info = GSIZE_TO_POINTER(marker);
++}
++
++static inline GstJpegMarkerCode
++unit_get_marker_code(GstVaapiDecoderUnit *unit)
++{
++    return GPOINTER_TO_SIZE(unit->parsed_info);
++}
+ 
+ static void
+ gst_vaapi_decoder_jpeg_close(GstVaapiDecoderJpeg *decoder)
+@@ -110,8 +126,12 @@ gst_vaapi_decoder_jpeg_close(GstVaapiDecoderJpeg *decoder)
+ 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;
+ }
+ 
+@@ -182,70 +202,90 @@ ensure_context(GstVaapiDecoderJpeg *decoder)
+     return GST_VAAPI_DECODER_STATUS_SUCCESS;
+ }
+ 
+-static gboolean
++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;
+-    gboolean success = TRUE;
+-
+-    if (picture) {
+-        if (!gst_vaapi_picture_decode(picture))
+-            success = FALSE;
+-        else if (!gst_vaapi_picture_output(picture))
+-            success = FALSE;
+-        gst_vaapi_picture_replace(&priv->current_picture, NULL);
+-    }
+-    return success;
++
++    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;
++
++error:
++    gst_vaapi_picture_replace(&priv->current_picture, NULL);
++    return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
++
++drop_frame:
++    priv->decoder_state = 0;
++    return GST_VAAPI_DECODER_STATUS_DROP_FRAME;
+ }
+ 
+ static gboolean
+ fill_picture(
+     GstVaapiDecoderJpeg *decoder, 
+     GstVaapiPicture     *picture,
+-    GstJpegFrameHdr     *jpeg_frame_hdr
++    GstJpegFrameHdr     *frame_hdr
+ )
+ {
+-    VAPictureParameterBufferJPEGBaseline *pic_param = picture->param;
++    VAPictureParameterBufferJPEGBaseline * const pic_param = picture->param;
+     guint i;
+ 
+-    g_assert(pic_param);
+-
+     memset(pic_param, 0, sizeof(VAPictureParameterBufferJPEGBaseline));
+-    pic_param->picture_width    = jpeg_frame_hdr->width;
+-    pic_param->picture_height   = jpeg_frame_hdr->height;
++    pic_param->picture_width    = frame_hdr->width;
++    pic_param->picture_height   = frame_hdr->height;
+ 
+-    pic_param->num_components   = jpeg_frame_hdr->num_components;
+-    if (jpeg_frame_hdr->num_components > 4)
++    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 =
+-            jpeg_frame_hdr->components[i].identifier;
++            frame_hdr->components[i].identifier;
+         pic_param->components[i].h_sampling_factor =
+-            jpeg_frame_hdr->components[i].horizontal_factor;
++            frame_hdr->components[i].horizontal_factor;
+         pic_param->components[i].v_sampling_factor =
+-            jpeg_frame_hdr->components[i].vertical_factor;
++            frame_hdr->components[i].vertical_factor;
+         pic_param->components[i].quantiser_table_selector =
+-            jpeg_frame_hdr->components[i].quant_table_selector;
++            frame_hdr->components[i].quant_table_selector;
+     }
+     return TRUE;
+ }
+ 
+-static gboolean
+-fill_quantization_table(
+-    GstVaapiDecoderJpeg *decoder, 
+-    GstVaapiPicture     *picture
+-)
++static GstVaapiDecoderStatus
++fill_quantization_table(GstVaapiDecoderJpeg *decoder, GstVaapiPicture *picture)
+ {
+     GstVaapiDecoderJpegPrivate * const priv = &decoder->priv;
+     VAIQMatrixBufferJPEGBaseline *iq_matrix;
+     guint i, j, num_tables;
+ 
+-    if (!priv->has_quant_table)
++    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);
+-    g_assert(picture->iq_matrix);
++    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),
+@@ -259,32 +299,51 @@ fill_quantization_table(
+         if (!iq_matrix->load_quantiser_table[i])
+             continue;
+ 
+-        g_assert(quant_table->quant_precision == 0);
++        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 TRUE;
++    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+ }
+ 
+ static gboolean
+-fill_huffman_table(
+-    GstVaapiDecoderJpeg *decoder, 
+-    GstVaapiPicture     *picture
+-)
++huffman_tables_updated(const GstJpegHuffmanTables *huf_tables)
+ {
+-    GstVaapiDecoderJpegPrivate * const priv = &decoder->priv;
+-    GstJpegHuffmanTables * const huf_tables = &priv->huf_tables;
+-    VAHuffmanTableBufferJPEGBaseline *huffman_table;
+-    guint i, num_tables;
++    guint i;
+ 
+-    if (!priv->has_huf_table)
+-        gst_jpeg_get_default_huffman_tables(&priv->huf_tables);
+-    
+-    picture->huf_table = GST_VAAPI_HUFFMAN_TABLE_NEW(JPEGBaseline, decoder);
+-    g_assert(picture->huf_table);
+-    huffman_table = picture->huf_table->param;
++    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);
+@@ -311,85 +370,71 @@ fill_huffman_table(
+                0,
+                sizeof(huffman_table->huffman_table[i].pad));
+     }
+-    return TRUE;
+ }
+ 
+-static guint
+-get_max_horizontal_samples(GstJpegFrameHdr *frame_hdr)
++static void
++get_max_sampling_factors(const GstJpegFrameHdr *frame_hdr,
++    guint *h_max_ptr, guint *v_max_ptr)
+ {
+-    guint i, max_factor = 0;
++    guint h_max = frame_hdr->components[0].horizontal_factor;
++    guint v_max = frame_hdr->components[0].vertical_factor;
++    guint i;
+ 
+-    for (i = 0; i < frame_hdr->num_components; i++) {
+-        if (frame_hdr->components[i].horizontal_factor > max_factor)
+-            max_factor = frame_hdr->components[i].horizontal_factor;
++    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;
+     }
+-    return max_factor;
++
++    if (h_max_ptr)
++        *h_max_ptr = h_max;
++    if (v_max_ptr)
++        *v_max_ptr = v_max;
+ }
+ 
+-static guint
+-get_max_vertical_samples(GstJpegFrameHdr *frame_hdr)
++static const GstJpegFrameComponent *
++get_component(const GstJpegFrameHdr *frame_hdr, guint selector)
+ {
+-    guint i, max_factor = 0;
++    guint i;
+ 
+     for (i = 0; i < frame_hdr->num_components; i++) {
+-        if (frame_hdr->components[i].vertical_factor > max_factor)
+-            max_factor = frame_hdr->components[i].vertical_factor;
++        const GstJpegFrameComponent * const fcp = &frame_hdr->components[i];
++        if (fcp->identifier == selector)
++            return fcp;
+     }
+-    return max_factor;
++    return NULL;
+ }
+ 
+ static GstVaapiDecoderStatus
+-decode_picture(
+-    GstVaapiDecoderJpeg *decoder, 
+-    guint8               profile,
+-    const guchar        *buf,
+-    guint                buf_size
+-)
++decode_picture(GstVaapiDecoderJpeg *decoder, GstJpegMarkerSegment *seg,
++    const guchar *buf)
+ {
+     GstVaapiDecoderJpegPrivate * const priv = &decoder->priv;
+     GstJpegFrameHdr * const frame_hdr = &priv->frame_hdr;
+-    GstVaapiPicture *picture;
+-    GstVaapiDecoderStatus status;
+ 
+-    switch (profile) {
++    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", profile);
++        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_parse_frame_hdr(frame_hdr, buf, buf_size, 0)) {
++    if (!gst_jpeg_parse_frame_hdr(frame_hdr, buf + seg->offset, seg->size, 0)) {
+         GST_ERROR("failed to parse image");
+         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+     }
+     priv->height = frame_hdr->height;
+     priv->width  = frame_hdr->width;
+ 
+-    status = ensure_context(decoder);
+-    if (status != GST_VAAPI_DECODER_STATUS_SUCCESS) {
+-        GST_ERROR("failed to reset context");
+-        return status;
+-    }
+-
+-    if (priv->current_picture && !decode_current_picture(decoder))
+-        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+-
+-    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, frame_hdr))
+-        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+-
+-    /* Update presentation time */
+-    picture->pts = GST_VAAPI_DECODER_CODEC_FRAME(decoder)->pts;
++    priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOF;
+     return GST_VAAPI_DECODER_STATUS_SUCCESS;
+ }
+ 
+@@ -402,11 +447,15 @@ decode_huffman_table(
+ {
+     GstVaapiDecoderJpegPrivate * const priv = &decoder->priv;
+ 
++    if (!VALID_STATE(decoder, GOT_SOI))
++        return GST_VAAPI_DECODER_STATUS_SUCCESS;
++
+     if (!gst_jpeg_parse_huffman_table(&priv->huf_tables, buf, buf_size, 0)) {
+-        GST_DEBUG("failed to parse Huffman table");
++        GST_ERROR("failed to parse Huffman table");
+         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+     }
+-    priv->has_huf_table = TRUE;
++
++    priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_HUF_TABLE;
+     return GST_VAAPI_DECODER_STATUS_SUCCESS;
+ }
+ 
+@@ -419,11 +468,15 @@ decode_quant_table(
+ {
+     GstVaapiDecoderJpegPrivate * const priv = &decoder->priv;
+ 
++    if (!VALID_STATE(decoder, GOT_SOI))
++        return GST_VAAPI_DECODER_STATUS_SUCCESS;
++
+     if (!gst_jpeg_parse_quant_table(&priv->quant_tables, buf, buf_size, 0)) {
+-        GST_DEBUG("failed to parse quantization table");
++        GST_ERROR("failed to parse quantization table");
+         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+     }
+-    priv->has_quant_table = TRUE;
++
++    priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_IQ_TABLE;
+     return GST_VAAPI_DECODER_STATUS_SUCCESS;
+ }
+ 
+@@ -436,55 +489,64 @@ decode_restart_interval(
+ {
+     GstVaapiDecoderJpegPrivate * const priv = &decoder->priv;
+ 
++    if (!VALID_STATE(decoder, GOT_SOI))
++        return GST_VAAPI_DECODER_STATUS_SUCCESS;
++
+     if (!gst_jpeg_parse_restart_interval(&priv->mcu_restart, buf, buf_size, 0)) {
+-        GST_DEBUG("failed to parse restart interval");
++        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,
+-    const guchar        *scan_header,
+-    guint                scan_header_size,
+-    const guchar        *scan_data,
+-    guint                scan_data_size
+-)
++decode_scan(GstVaapiDecoderJpeg *decoder, GstJpegMarkerSegment *seg,
++    const guchar *buf)
+ {
+     GstVaapiDecoderJpegPrivate * const priv = &decoder->priv;
+-    GstVaapiPicture *picture = priv->current_picture;
++    GstVaapiPicture * const picture = priv->current_picture;
++    GstVaapiSlice *slice;
+     VASliceParameterBufferJPEGBaseline *slice_param;
+-    GstVaapiSlice *gst_slice;
+-    guint total_h_samples, total_v_samples;
+-    GstJpegScanHdr  scan_hdr;
+-    guint i;
++    GstJpegScanHdr scan_hdr;
++    guint scan_hdr_size, scan_data_size;
++    guint i, h_max, v_max, mcu_width, mcu_height;
+ 
+-    if (!picture) {
+-        GST_ERROR("There is no VAPicture before decoding scan.");
+-        return GST_VAAPI_DECODER_STATUS_ERROR_INVALID_SURFACE;
+-    }
+-
+-    if (!fill_quantization_table(decoder, picture)) {
+-        GST_ERROR("failed to fill in quantization table");
+-        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+-    }
++    if (!VALID_STATE(decoder, GOT_SOF))
++        return GST_VAAPI_DECODER_STATUS_SUCCESS;
+ 
+-    if (!fill_huffman_table(decoder, picture)) {
+-        GST_ERROR("failed to fill in huffman table");
+-        return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+-    }
++    scan_hdr_size = (buf[seg->offset] << 8) | buf[seg->offset + 1];
++    scan_data_size = seg->size - scan_hdr_size;
+ 
+     memset(&scan_hdr, 0, sizeof(scan_hdr));
+-    if (!gst_jpeg_parse_scan_hdr(&scan_hdr, scan_header, scan_header_size, 0)) {
+-        GST_DEBUG("Jpeg parsed scan failed.");
++    if (!gst_jpeg_parse_scan_hdr(&scan_hdr, buf + seg->offset, seg->size, 0)) {
++        GST_ERROR("failed to parse scan header");
+         return GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+     }
+ 
+-    gst_slice = GST_VAAPI_SLICE_NEW(JPEGBaseline, decoder, scan_data, scan_data_size);
+-    gst_vaapi_picture_add_slice(picture, gst_slice);
++    slice = GST_VAAPI_SLICE_NEW(JPEGBaseline, decoder,
++        buf + 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);
+ 
+-    slice_param = gst_slice->param;
++    // 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 =
+@@ -495,142 +557,73 @@ decode_scan(
+             scan_hdr.components[i].ac_selector;
+     }
+     slice_param->restart_interval = priv->mcu_restart;
+-    if (scan_hdr.num_components == 1) { /*non-interleaved*/
+-        slice_param->slice_horizontal_position = 0;
+-        slice_param->slice_vertical_position = 0;
+-        /* Y mcu numbers*/
+-        if (slice_param->components[0].component_selector == priv->frame_hdr.components[0].identifier) {
+-            slice_param->num_mcus = (priv->frame_hdr.width/8)*(priv->frame_hdr.height/8);
+-        } else { /*Cr, Cb mcu numbers*/
+-            slice_param->num_mcus = (priv->frame_hdr.width/16)*(priv->frame_hdr.height/16);
++    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;
+         }
+-    } else { /* interleaved */
+-        slice_param->slice_horizontal_position = 0;
+-        slice_param->slice_vertical_position = 0;
+-        total_v_samples = get_max_vertical_samples(&priv->frame_hdr);
+-        total_h_samples = get_max_horizontal_samples(&priv->frame_hdr);
+-        slice_param->num_mcus = ((priv->frame_hdr.width + total_h_samples*8 - 1)/(total_h_samples*8)) *
+-                                ((priv->frame_hdr.height + total_v_samples*8 -1)/(total_v_samples*8));
++        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);
+ 
+-    if (picture->slices && picture->slices->len)
+-        return GST_VAAPI_DECODER_STATUS_SUCCESS;
+-    return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
++    priv->decoder_state |= GST_JPEG_VIDEO_STATE_GOT_SOS;
++    return GST_VAAPI_DECODER_STATUS_SUCCESS;
+ }
+ 
+ static GstVaapiDecoderStatus
+-decode_buffer(GstVaapiDecoderJpeg *decoder, const guchar *buf, guint buf_size)
++decode_segment(GstVaapiDecoderJpeg *decoder, GstJpegMarkerSegment *seg,
++    const guchar *buf)
+ {
+     GstVaapiDecoderJpegPrivate * const priv = &decoder->priv;
+-    GstVaapiDecoderStatus status = GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+-    GstJpegMarkerSegment seg;
+-    GstJpegScanSegment scan_seg;
+-    guint ofs;
+-    gboolean append_ecs;
+-
+-    memset(&scan_seg, 0, sizeof(scan_seg));
+-
+-    ofs = 0;
+-    while (gst_jpeg_parse(&seg, buf, buf_size, ofs)) {
+-        if (seg.size < 0) {
+-            GST_DEBUG("buffer to short for parsing");
+-            return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+-        }
+-        ofs += seg.size;
+-
+-        /* Decode scan, if complete */
+-        if (seg.marker == GST_JPEG_MARKER_EOI && scan_seg.header_size > 0) {
+-            scan_seg.data_size = seg.offset - scan_seg.data_offset;
+-            scan_seg.is_valid  = TRUE;
+-        }
+-        if (scan_seg.is_valid) {
+-            status = decode_scan(
+-                decoder,
+-                buf + scan_seg.header_offset,
+-                scan_seg.header_size,
+-                buf + scan_seg.data_offset,
+-                scan_seg.data_size
+-            );
+-            if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+-                break;
+-            memset(&scan_seg, 0, sizeof(scan_seg));
+-        }
+-
+-        append_ecs = TRUE;
+-        switch (seg.marker) {
+-        case GST_JPEG_MARKER_SOI:
+-            priv->has_quant_table = FALSE;
+-            priv->has_huf_table   = FALSE;
+-            priv->mcu_restart     = 0;
+-            status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+-            break;
+-        case GST_JPEG_MARKER_EOI:
+-            if (decode_current_picture(decoder)) {
+-                /* Get out of the loop, trailing data is not needed */
+-                status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+-                goto end;
+-            }
+-            status = GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+-            break;
+-        case GST_JPEG_MARKER_DHT:
+-            status = decode_huffman_table(decoder, buf + seg.offset, seg.size);
+-            break;
+-        case GST_JPEG_MARKER_DQT:
+-            status = decode_quant_table(decoder, buf + seg.offset, seg.size);
+-            break;
+-        case GST_JPEG_MARKER_DRI:
+-            status = decode_restart_interval(decoder, buf + seg.offset, seg.size);
+-            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_SOS:
+-            scan_seg.header_offset = seg.offset;
+-            scan_seg.header_size   = seg.size;
+-            scan_seg.data_offset   = seg.offset + seg.size;
+-            scan_seg.data_size     = 0;
+-            append_ecs             = FALSE;
+-            break;
+-        default:
+-            /* Restart marker */
+-            if (seg.marker >= GST_JPEG_MARKER_RST_MIN &&
+-                seg.marker <= GST_JPEG_MARKER_RST_MAX) {
+-                append_ecs = FALSE;
+-                break;
+-            }
+-
+-            /* Frame header */
+-            if (seg.marker >= GST_JPEG_MARKER_SOF_MIN &&
+-                seg.marker <= GST_JPEG_MARKER_SOF_MAX) {
+-                status = decode_picture(
+-                    decoder,
+-                    seg.marker,
+-                    buf + seg.offset, seg.size
+-                );
+-                break;
+-            }
+-
+-            /* Application segments */
+-            if (seg.marker >= GST_JPEG_MARKER_APP_MIN &&
+-                seg.marker <= GST_JPEG_MARKER_APP_MAX) {
+-                status = GST_VAAPI_DECODER_STATUS_SUCCESS;
+-                break;
+-            }
+-
+-            GST_WARNING("unsupported marker (0x%02x)", seg.marker);
+-            status = GST_VAAPI_DECODER_STATUS_ERROR_BITSTREAM_PARSER;
+-            break;
+-        }
+-
+-        /* Append entropy coded segments */
+-        if (append_ecs)
+-            scan_seg.data_size = seg.offset - scan_seg.data_offset;
++    GstVaapiDecoderStatus status;
+ 
+-        if (status != GST_VAAPI_DECODER_STATUS_SUCCESS)
+-            break;
++    // 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, buf + seg->offset, seg->size);
++        break;
++    case GST_JPEG_MARKER_DQT:
++        status = decode_quant_table(decoder, buf + seg->offset, seg->size);
++        break;
++    case GST_JPEG_MARKER_DRI:
++        status = decode_restart_interval(decoder, buf + seg->offset, seg->size);
++        break;
++    case GST_JPEG_MARKER_SOS:
++        status = decode_scan(decoder, seg, buf);
++        break;
++    default:
++        // SOFn segments
++        if (seg->marker >= GST_JPEG_MARKER_SOF_MIN &&
++            seg->marker <= GST_JPEG_MARKER_SOF_MAX)
++            status = decode_picture(decoder, seg, buf);
++        break;
+     }
+-end:
+     return status;
+ }
+ 
+@@ -647,11 +640,11 @@ ensure_decoder(GstVaapiDecoderJpeg *decoder)
+     return GST_VAAPI_DECODER_STATUS_SUCCESS;
+ }
+ 
+-static inline gint
+-scan_for_start_code(GstAdapter *adapter, guint ofs, guint size, guint32 *scp)
++static gboolean
++is_scan_complete(GstJpegMarkerCode marker)
+ {
+-    return (gint)gst_adapter_masked_scan_uint32_peek(adapter,
+-        0xffff0000, 0xffd80000, ofs, size, scp);
++    // 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
+@@ -660,40 +653,129 @@ gst_vaapi_decoder_jpeg_parse(GstVaapiDecoder *base_decoder,
+ {
+     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;
+-    guint size, buf_size, flags = 0;
+-    gint ofs;
++    GstJpegMarkerCode marker;
++    GstJpegMarkerSegment 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 4 bytes, SOI .. EOI */
+-    size = gst_adapter_available(adapter);
+-    if (size < 4)
++    /* 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;
+ 
+-    ofs = scan_for_start_code(adapter, 0, size, NULL);
+-    if (ofs < 0)
++    buf = gst_adapter_map(adapter, buf_size);
++    if (!buf)
+         return GST_VAAPI_DECODER_STATUS_ERROR_NO_DATA;
+-    gst_adapter_flush(adapter, ofs);
+-    size -= ofs;
+-
+-    ofs = G_UNLIKELY(size < 4) ? -1 :
+-        scan_for_start_code(adapter, 2, size - 2, 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;
+ 
+-    unit->size = buf_size;
++    ofs1 = ps->input_offset1 - 2;
++    if (ofs1 < 0)
++        ofs1 = 0;
+ 
+-    flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_START;
+-    flags |= GST_VAAPI_DECODER_UNIT_FLAG_FRAME_END;
+-    flags |= GST_VAAPI_DECODER_UNIT_FLAG_SLICE;
++    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;
+ }
+@@ -705,6 +787,7 @@ gst_vaapi_decoder_jpeg_decode(GstVaapiDecoder *base_decoder,
+     GstVaapiDecoderJpeg * const decoder =
+         GST_VAAPI_DECODER_JPEG_CAST(base_decoder);
+     GstVaapiDecoderStatus status;
++    GstJpegMarkerSegment seg;
+     GstBuffer * const buffer =
+         GST_VAAPI_DECODER_CODEC_FRAME(decoder)->input_buffer;
+     GstMapInfo map_info;
+@@ -718,13 +801,65 @@ gst_vaapi_decoder_jpeg_decode(GstVaapiDecoder *base_decoder,
+         return GST_VAAPI_DECODER_STATUS_ERROR_UNKNOWN;
+     }
+ 
+-    status = decode_buffer(decoder, map_info.data + unit->offset, unit->size);
++    seg.marker = unit_get_marker_code(unit);
++    seg.offset = unit->offset;
++    seg.size = unit->size;
++
++    status = decode_segment(decoder, &seg, map_info.data);
+     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_class_init(GstVaapiDecoderJpegClass *klass)
+ {
+@@ -739,6 +874,8 @@ gst_vaapi_decoder_jpeg_class_init(GstVaapiDecoderJpegClass *klass)
+     decoder_class->destroy      = gst_vaapi_decoder_jpeg_destroy;
+     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 inline const GstVaapiDecoderClass *
+diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_objects.c b/gst-libs/gst/vaapi/gstvaapidecoder_objects.c
+index fbbe5f7..218b512 100644
+--- a/gst-libs/gst/vaapi/gstvaapidecoder_objects.c
++++ b/gst-libs/gst/vaapi/gstvaapidecoder_objects.c
+@@ -291,6 +291,11 @@ gst_vaapi_picture_decode(GstVaapiPicture *picture)
+         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;
+@@ -396,6 +401,9 @@ gst_vaapi_slice_destroy(GstVaapiSlice *slice)
+ {
+     VADisplay const va_display = GET_VA_DISPLAY(slice);
+ 
++    gst_vaapi_mini_object_replace((GstVaapiMiniObject **)&slice->huf_table,
++        NULL);
++
+     vaapi_destroy_buffer(va_display, &slice->data_id);
+     vaapi_destroy_buffer(va_display, &slice->param_id);
+     slice->param = NULL;
+diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_objects.h b/gst-libs/gst/vaapi/gstvaapidecoder_objects.h
+index 90e8f04..3d595ae 100644
+--- a/gst-libs/gst/vaapi/gstvaapidecoder_objects.h
++++ b/gst-libs/gst/vaapi/gstvaapidecoder_objects.h
+@@ -216,6 +216,9 @@ struct _GstVaapiSlice {
+     VABufferID                  param_id;
+     VABufferID                  data_id;
+     gpointer                    param;
++
++    /* Per-slice overrides */
++    GstVaapiHuffmanTable       *huf_table;
+ };
+ 
+ G_GNUC_INTERNAL
+diff --git a/gst-libs/gst/vaapi/gstvaapidecoder_priv.h b/gst-libs/gst/vaapi/gstvaapidecoder_priv.h
+index a86b4a1..8b6d897 100644
+--- a/gst-libs/gst/vaapi/gstvaapidecoder_priv.h
++++ b/gst-libs/gst/vaapi/gstvaapidecoder_priv.h
+@@ -168,6 +168,7 @@ struct _GstVaapiParserState {
+     GstVideoCodecFrame *current_frame;
+     GstAdapter         *current_adapter;
+     GstAdapter         *input_adapter;
++    gint                input_offset1;
+     gint                input_offset2;
+     GstAdapter         *output_adapter;
+     GstVaapiDecoderUnit next_unit;
+diff --git a/gst/vaapi/Makefile.am b/gst/vaapi/Makefile.am
+index 1b89467..0b8a45e 100644
+--- a/gst/vaapi/Makefile.am
++++ b/gst/vaapi/Makefile.am
+@@ -33,38 +33,60 @@ libgstvaapi_source_c = \
+ 	gstvaapi.c		\
+ 	gstvaapidecode.c	\
+ 	gstvaapipluginutil.c	\
+-	gstvaapipostproc.c	\
+ 	gstvaapisink.c		\
+ 	gstvaapiuploader.c	\
+ 	gstvaapivideobuffer.c	\
++	gstvaapivideocontext.c	\
+ 	gstvaapivideometa.c	\
+ 	$(NULL)
+ 
+ libgstvaapi_source_h = \
+ 	gstvaapidecode.h	\
+ 	gstvaapipluginutil.h	\
+-	gstvaapipostproc.h	\
+ 	gstvaapisink.h		\
+ 	gstvaapiuploader.h	\
+ 	gstvaapivideobuffer.h	\
++	gstvaapivideocontext.h	\
+ 	gstvaapivideometa.h	\
+ 	$(NULL)
+ 
++if !USE_GST_API_1_2p
++libgstvaapi_source_c += gstvaapipostproc.c
++libgstvaapi_source_h += gstvaapipostproc.h
++endif
++
+ libgstvaapi_x11_source_c = gstvaapivideoconverter_x11.c
+ libgstvaapi_x11_source_h = gstvaapivideoconverter_x11.h
+ 
+ if USE_X11
++if !USE_GST_API_1_2p
+ libgstvaapi_source_c += $(libgstvaapi_x11_source_c)
+ libgstvaapi_source_h += $(libgstvaapi_x11_source_h)
+ endif
++endif
+ 
+ libgstvaapi_glx_source_c = gstvaapivideoconverter_glx.c
+ libgstvaapi_glx_source_h = gstvaapivideoconverter_glx.h
+ 
+ if USE_GLX
++if !USE_GST_API_1_2p
+ libgstvaapi_source_c += $(libgstvaapi_glx_source_c)
+ libgstvaapi_source_h += $(libgstvaapi_glx_source_h)
+ endif
++endif
++
++libgstvaapi_1_2p_source_c = \
++	gstvaapivideometa_texture.c \
++	$(NULL)
++
++libgstvaapi_1_2p_source_h = \
++	gstvaapivideometa_texture.h \
++	$(NULL)
++
++if USE_GST_API_1_2p
++libgstvaapi_source_c += $(libgstvaapi_1_2p_source_c)
++libgstvaapi_source_h += $(libgstvaapi_1_2p_source_h)
++endif
+ 
+ libgstvaapi_1_0p_source_c = \
+ 	gstvaapivideobufferpool.c \
+@@ -126,6 +148,8 @@ libgstvaapi_la_LIBTOOLFLAGS = --tag=disable-static
+ EXTRA_DIST = \
+ 	$(libgstvaapi_glx_source_c)	\
+ 	$(libgstvaapi_glx_source_h)	\
++	$(libgstvaapi_1_2p_source_c)	\
++	$(libgstvaapi_1_2p_source_h)	\
+ 	$(libgstvaapi_1_0p_source_c)	\
+ 	$(libgstvaapi_1_0p_source_h)	\
+ 	$(libgstvaapi_0_10_source_c)	\
+diff --git a/gst/vaapi/gstvaapi.c b/gst/vaapi/gstvaapi.c
+index 3000b22..7d12a66 100644
+--- a/gst/vaapi/gstvaapi.c
++++ b/gst/vaapi/gstvaapi.c
+@@ -47,9 +47,11 @@ plugin_init (GstPlugin *plugin)
+     gst_element_register(plugin, "vaapidecode",
+                          GST_RANK_PRIMARY,
+                          GST_TYPE_VAAPIDECODE);
++#if !GST_CHECK_VERSION(1,1,0)
+     gst_element_register(plugin, "vaapipostproc",
+                          GST_RANK_PRIMARY,
+                          GST_TYPE_VAAPIPOSTPROC);
++#endif
+     gst_element_register(plugin, "vaapisink",
+                          GST_RANK_PRIMARY,
+                          GST_TYPE_VAAPISINK);
+diff --git a/gst/vaapi/gstvaapidecode.c b/gst/vaapi/gstvaapidecode.c
+index 68cc58f..597a3fb 100644
+--- a/gst/vaapi/gstvaapidecode.c
++++ b/gst/vaapi/gstvaapidecode.c
+@@ -30,11 +30,14 @@
+ 
+ #include "gst/vaapi/sysdeps.h"
+ #include <gst/vaapi/gstvaapidisplay.h>
+-#include <gst/video/videocontext.h>
+ 
+ #include "gstvaapidecode.h"
+ #include "gstvaapipluginutil.h"
++#include "gstvaapivideocontext.h"
+ #include "gstvaapivideobuffer.h"
++#if GST_CHECK_VERSION(1,1,0)
++#include "gstvaapivideometa_texture.h"
++#endif
+ #if GST_CHECK_VERSION(1,0,0)
+ #include "gstvaapivideobufferpool.h"
+ #include "gstvaapivideomemory.h"
+@@ -67,7 +70,15 @@ static const char gst_vaapidecode_sink_caps_str[] =
+     ;
+ 
+ static const char gst_vaapidecode_src_caps_str[] =
++#if GST_CHECK_VERSION(1,1,0)
++    GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
++        GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, GST_VIDEO_FORMATS_ALL) ";"
++    GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
++        GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
++        GST_VIDEO_FORMATS_ALL);
++#else
+     GST_VAAPI_SURFACE_CAPS;
++#endif
+ 
+ static GstStaticPadTemplate gst_vaapidecode_sink_factory =
+     GST_STATIC_PAD_TEMPLATE(
+@@ -102,6 +113,7 @@ gst_vaapidecode_implements_iface_init(GstImplementsInterfaceClass *iface)
+ #endif
+ 
+ /* GstVideoContext interface */
++#if !GST_CHECK_VERSION(1,1,0)
+ static void
+ gst_vaapidecode_set_video_context(GstVideoContext *context, const gchar *type,
+     const GValue *value)
+@@ -117,6 +129,8 @@ gst_video_context_interface_init(GstVideoContextInterface *iface)
+ }
+ 
+ #define GstVideoContextClass GstVideoContextInterface
++#endif
++
+ G_DEFINE_TYPE_WITH_CODE(
+     GstVaapiDecode,
+     gst_vaapidecode,
+@@ -125,8 +139,11 @@ G_DEFINE_TYPE_WITH_CODE(
+     G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
+                           gst_vaapidecode_implements_iface_init);
+ #endif
++#if !GST_CHECK_VERSION(1,1,0)
+     G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
+-                          gst_video_context_interface_init))
++                          gst_video_context_interface_init)
++#endif
++    )
+ 
+ static gboolean
+ gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
+@@ -174,6 +191,9 @@ gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
+     }
+     gst_video_codec_state_unref(state);
+ 
++#if GST_CHECK_VERSION(1,1,0)
++    state->caps = gst_video_info_to_caps(&vis);
++#else
+     /* XXX: gst_video_info_to_caps() from GStreamer 0.10 does not
+        reconstruct suitable caps for "encoded" video formats */
+     state->caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS_NAME);
+@@ -194,6 +214,7 @@ gst_vaapidecode_update_src_caps(GstVaapiDecode *decode,
+             gst_caps_get_structure(state->caps, 0);
+         gst_structure_set_interlaced(structure, TRUE);
+     }
++#endif
+     gst_caps_replace(&decode->srcpad_caps, state->caps);
+     return TRUE;
+ }
+@@ -328,6 +349,11 @@ gst_vaapidecode_push_decoded_frame(GstVideoDecoder *vdec)
+                 crop_meta->height = crop_rect->height;
+             }
+         }
++
++#if GST_CHECK_VERSION(1,1,0)
++        if (decode->has_texture_upload_meta)
++            gst_buffer_add_texture_upload_meta(out_frame->output_buffer);
++#endif
+ #else
+         out_frame->output_buffer =
+             gst_vaapi_video_buffer_new_with_surface_proxy(proxy);
+@@ -514,6 +540,18 @@ gst_vaapidecode_decide_allocation(GstVideoDecoder *vdec, GstQuery *query)
+         gst_buffer_pool_set_config(pool, config);
+     }
+ 
++    decode->has_texture_upload_meta = FALSE;
++    if (gst_query_find_allocation_meta(query, GST_VIDEO_META_API_TYPE, NULL)) {
++        config = gst_buffer_pool_get_config(pool);
++        gst_buffer_pool_config_add_option(config,
++            GST_BUFFER_POOL_OPTION_VIDEO_META);
++        gst_buffer_pool_set_config(pool, config);
++#if GST_CHECK_VERSION(1,1,0)
++        decode->has_texture_upload_meta = gst_query_find_allocation_meta(query,
++            GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, NULL);
++#endif
++    }
++
+     if (update_pool)
+         gst_query_set_nth_allocation_pool(query, 0, pool, size, min, max);
+     else
+@@ -536,6 +574,20 @@ error_create_pool:
+ }
+ #endif
+ 
++#if GST_CHECK_VERSION(1,1,0)
++static void
++gst_vaapidecode_set_context(GstElement *element, GstContext *context)
++{
++    GstVaapiDecode * const decode = GST_VAAPIDECODE(element);
++    GstVaapiDisplay *display = NULL;
++
++    if (gst_vaapi_video_context_get_display(context, &display)) {
++        GST_INFO_OBJECT(element, "set display %p", display);
++        gst_vaapi_display_replace(&decode->display, display);
++    }
++}
++#endif
++
+ static inline gboolean
+ gst_vaapidecode_ensure_display(GstVaapiDecode *decode)
+ {
+@@ -607,6 +659,8 @@ gst_vaapidecode_reset_full(GstVaapiDecode *decode, GstCaps *caps, gboolean hard)
+ {
+     GstVaapiCodec codec;
+ 
++    decode->has_texture_upload_meta = FALSE;
++
+     /* Reset timers if hard reset was requested (e.g. seek) */
+     if (hard) {
+         decode->render_time_base = 0;
+@@ -769,6 +823,10 @@ gst_vaapidecode_class_init(GstVaapiDecodeClass *klass)
+         GST_DEBUG_FUNCPTR(gst_vaapidecode_decide_allocation);
+ #endif
+ 
++#if GST_CHECK_VERSION(1,1,0)
++    element_class->set_context = GST_DEBUG_FUNCPTR(gst_vaapidecode_set_context);
++#endif
++
+     gst_element_class_set_static_metadata(element_class,
+         "VA-API decoder",
+         "Codec/Decoder/Video",
+@@ -858,10 +916,12 @@ gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
+         GST_VAAPIDECODE(gst_pad_get_parent_element(pad));
+     gboolean res;
+ 
+-    GST_DEBUG("sharing display %p", decode->display);
++    GST_INFO_OBJECT(decode, "query type %s", GST_QUERY_TYPE_NAME(query));
+ 
+-    if (gst_vaapi_reply_to_query(query, decode->display))
++    if (gst_vaapi_reply_to_query(query, decode->display)) {
++        GST_DEBUG("sharing display %p", decode->display);
+         res = TRUE;
++    }
+     else if (GST_PAD_IS_SINK(pad)) {
+         switch (GST_QUERY_TYPE(query)) {
+ #if GST_CHECK_VERSION(1,0,0)
+@@ -873,6 +933,24 @@ gst_vaapidecode_query(GST_PAD_QUERY_FUNCTION_ARGS)
+             break;
+         }
+ #endif
++#if GST_CHECK_VERSION(1,1,0)
++        case GST_QUERY_CONTEXT: {
++            const gchar *context_type = NULL;
++
++            if (gst_query_parse_context_type(query, &context_type) &&
++                !g_strcmp0(context_type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME) &&
++                decode->display) {
++                GstContext *context;
++
++                context = gst_vaapi_video_context_new_with_display(
++                    decode->display, FALSE);
++                gst_query_set_context(query, context);
++                gst_context_unref(context);
++                return TRUE;
++            }
++            // fall-through
++        }
++#endif
+         default:
+             res = GST_PAD_QUERY_FUNCTION_CALL(decode->sinkpad_query,
+                 decode->sinkpad, parent, query);
+diff --git a/gst/vaapi/gstvaapidecode.h b/gst/vaapi/gstvaapidecode.h
+index 23991cf..161937b 100644
+--- a/gst/vaapi/gstvaapidecode.h
++++ b/gst/vaapi/gstvaapidecode.h
+@@ -79,6 +79,7 @@ struct _GstVaapiDecode {
+     gint64              render_time_base;
+     GstClockTime        last_buffer_time;
+     guint               current_frame_size;
++    guint               has_texture_upload_meta : 1;
+ };
+ 
+ struct _GstVaapiDecodeClass {
+diff --git a/gst/vaapi/gstvaapipluginutil.c b/gst/vaapi/gstvaapipluginutil.c
+index ac48d01..43b1fc5 100644
+--- a/gst/vaapi/gstvaapipluginutil.c
++++ b/gst/vaapi/gstvaapipluginutil.c
+@@ -22,7 +22,7 @@
+  */
+ 
+ #include "gst/vaapi/sysdeps.h"
+-#include <gst/video/videocontext.h>
++#include "gstvaapivideocontext.h"
+ #if USE_DRM
+ # include <gst/vaapi/gstvaapidisplay_drm.h>
+ #endif
+@@ -130,7 +130,7 @@ gst_vaapi_ensure_display(
+     context = GST_VIDEO_CONTEXT(element);
+     g_return_val_if_fail(context != NULL, FALSE);
+ 
+-    gst_video_context_prepare(context, display_types);
++    gst_vaapi_video_context_prepare(context, display_types);
+ 
+     /* Neighbour found and it updated the display */
+     if (*display_ptr)
+@@ -141,6 +141,8 @@ gst_vaapi_ensure_display(
+ 
+     if (display_ptr)
+         *display_ptr = display;
++
++    gst_vaapi_video_context_propagate(context, display);
+     return display != NULL;
+ }
+ 
+@@ -217,6 +219,9 @@ gst_vaapi_set_display(
+ gboolean
+ gst_vaapi_reply_to_query(GstQuery *query, GstVaapiDisplay *display)
+ {
++#if GST_CHECK_VERSION(1,1,0)
++    return FALSE;
++#else
+     GstVaapiDisplayType display_type;
+     const gchar **types;
+     const gchar *type;
+@@ -305,6 +310,7 @@ gst_vaapi_reply_to_query(GstQuery *query, GstVaapiDisplay *display)
+         }
+     }
+     return res;
++#endif /* !GST_CHECK_VERSION(1,1,0) */
+ }
+ 
+ gboolean
+diff --git a/gst/vaapi/gstvaapisink.c b/gst/vaapi/gstvaapisink.c
+index ae39a51..b6ffca3 100644
+--- a/gst/vaapi/gstvaapisink.c
++++ b/gst/vaapi/gstvaapisink.c
+@@ -32,7 +32,7 @@
+ #include "gst/vaapi/sysdeps.h"
+ #include <gst/gst.h>
+ #include <gst/video/video.h>
+-#include <gst/video/videocontext.h>
++
+ #include <gst/vaapi/gstvaapivalue.h>
+ #if USE_DRM
+ # include <gst/vaapi/gstvaapidisplay_drm.h>
+@@ -69,6 +69,7 @@
+ 
+ #include "gstvaapisink.h"
+ #include "gstvaapipluginutil.h"
++#include "gstvaapivideocontext.h"
+ #include "gstvaapivideometa.h"
+ #if GST_CHECK_VERSION(1,0,0)
+ #include "gstvaapivideobufferpool.h"
+@@ -83,6 +84,13 @@ GST_DEBUG_CATEGORY_STATIC(gst_debug_vaapisink);
+ 
+ /* Default template */
+ static const char gst_vaapisink_sink_caps_str[] =
++#if GST_CHECK_VERSION(1,1,0)
++    GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
++        GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE, GST_VIDEO_FORMATS_ALL) ";"
++    GST_VIDEO_CAPS_MAKE_WITH_FEATURES(
++        GST_CAPS_FEATURE_META_GST_VIDEO_GL_TEXTURE_UPLOAD_META,
++        GST_VIDEO_FORMATS_ALL);
++#else
+ #if GST_CHECK_VERSION(1,0,0)
+     GST_VIDEO_CAPS_MAKE(GST_VIDEO_FORMATS_ALL) "; "
+ #else
+@@ -91,6 +99,7 @@ static const char gst_vaapisink_sink_caps_str[] =
+     "height = (int) [ 1, MAX ]; "
+ #endif
+     GST_VAAPI_SURFACE_CAPS;
++#endif
+ 
+ static GstStaticPadTemplate gst_vaapisink_sink_factory =
+     GST_STATIC_PAD_TEMPLATE(
+@@ -119,6 +128,7 @@ gst_vaapisink_implements_iface_init(GstImplementsInterfaceClass *iface)
+ #endif
+ 
+ /* GstVideoContext interface */
++#if !GST_CHECK_VERSION(1,1,0)
+ static void
+ gst_vaapisink_set_video_context(GstVideoContext *context, const gchar *type,
+     const GValue *value)
+@@ -132,6 +142,7 @@ gst_vaapisink_video_context_iface_init(GstVideoContextInterface *iface)
+ {
+     iface->set_context = gst_vaapisink_set_video_context;
+ }
++#endif
+ 
+ static void
+ gst_vaapisink_video_overlay_iface_init(GstVideoOverlayInterface *iface);
+@@ -144,8 +155,10 @@ G_DEFINE_TYPE_WITH_CODE(
+     G_IMPLEMENT_INTERFACE(GST_TYPE_IMPLEMENTS_INTERFACE,
+                           gst_vaapisink_implements_iface_init);
+ #endif
++#if !GST_CHECK_VERSION(1,1,0)
+     G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_CONTEXT,
+                           gst_vaapisink_video_context_iface_init);
++#endif
+     G_IMPLEMENT_INTERFACE(GST_TYPE_VIDEO_OVERLAY,
+                           gst_vaapisink_video_overlay_iface_init))
+ 
+@@ -714,14 +727,20 @@ gst_vaapisink_get_caps_impl(GstBaseSink *base_sink)
+     GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
+     GstCaps *out_caps, *yuv_caps;
+ 
++#if GST_CHECK_VERSION(1,1,0)
++    out_caps = gst_static_pad_template_get_caps(&gst_vaapisink_sink_factory);
++#else
+     out_caps = gst_caps_from_string(GST_VAAPI_SURFACE_CAPS);
++#endif
+     if (!out_caps)
+         return NULL;
+ 
+     if (gst_vaapisink_ensure_uploader(sink)) {
+         yuv_caps = gst_vaapi_uploader_get_caps(sink->uploader);
+-        if (yuv_caps)
++        if (yuv_caps) {
++            out_caps = gst_caps_make_writable(out_caps);
+             gst_caps_append(out_caps, gst_caps_copy(yuv_caps));
++	}
+     }
+     return out_caps;
+ }
+@@ -1323,15 +1342,55 @@ gst_vaapisink_buffer_alloc(
+ }
+ #endif
+ 
++#if GST_CHECK_VERSION(1,1,0)
++static void
++gst_vaapisink_set_context(GstElement *element, GstContext *context)
++{
++    GstVaapiSink * const sink = GST_VAAPISINK(element);
++    GstVaapiDisplay *display = NULL;
++
++    if (gst_vaapi_video_context_get_display(context, &display)) {
++        GST_INFO_OBJECT(element, "set display %p", display);
++        gst_vaapi_display_replace(&sink->display, display);
++    }
++}
++#endif
++
+ static gboolean
+ gst_vaapisink_query(GstBaseSink *base_sink, GstQuery *query)
+ {
+     GstVaapiSink * const sink = GST_VAAPISINK(base_sink);
+ 
++    GST_INFO_OBJECT(sink, "query type %s", GST_QUERY_TYPE_NAME(query));
++
+     if (gst_vaapi_reply_to_query(query, sink->display)) {
+         GST_DEBUG("sharing display %p", sink->display);
+         return TRUE;
+     }
++
++    switch(GST_QUERY_TYPE(query)) {
++#if GST_CHECK_VERSION(1,1,0)
++      case GST_QUERY_CONTEXT: {
++          const gchar *context_type = NULL;
++
++          if (gst_query_parse_context_type(query, &context_type) &&
++              !g_strcmp0(context_type, GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME) &&
++              sink->display) {
++              GstContext *context;
++
++              context = gst_vaapi_video_context_new_with_display(
++                  sink->display, FALSE);
++              gst_query_set_context(query, context);
++              gst_context_unref(context);
++              return TRUE;
++          }
++          // fall-through
++      }
++#endif
++      default:
++          break;
++    }
++
+     return GST_BASE_SINK_CLASS(gst_vaapisink_parent_class)->query(base_sink,
+         query);
+ }
+@@ -1448,6 +1507,10 @@ gst_vaapisink_class_init(GstVaapiSinkClass *klass)
+     basesink_class->buffer_alloc = gst_vaapisink_buffer_alloc;
+ #endif
+ 
++#if GST_CHECK_VERSION(1,1,0)
++    element_class->set_context = gst_vaapisink_set_context;
++#endif
++
+     gst_element_class_set_static_metadata(element_class,
+         "VA-API sink",
+         "Sink/Video",
+diff --git a/gst/vaapi/gstvaapivideobuffer.c b/gst/vaapi/gstvaapivideobuffer.c
+index 19926d3..40c11e8 100644
+--- a/gst/vaapi/gstvaapivideobuffer.c
++++ b/gst/vaapi/gstvaapivideobuffer.c
+@@ -27,14 +27,20 @@
+ 
+ #include "gst/vaapi/sysdeps.h"
+ #include "gstvaapivideobuffer.h"
+-#if USE_X11
++#if USE_X11 && !GST_CHECK_VERSION(1,1,0)
+ # include "gstvaapivideoconverter_x11.h"
+ #endif
+-#if USE_GLX
++#if USE_GLX && !GST_CHECK_VERSION(1,1,0)
+ # include "gstvaapivideoconverter_glx.h"
+ #endif
+ 
+-#if GST_CHECK_VERSION(1,0,0)
++#if GST_CHECK_VERSION(1,1,0)
++static inline GstBuffer *
++gst_surface_buffer_new(void)
++{
++    return gst_buffer_new();
++}
++#elif GST_CHECK_VERSION(1,0,0)
+ #include <gst/video/gstsurfacemeta.h>
+ 
+ #define GST_VAAPI_SURFACE_META_CAST(obj) \
+@@ -263,12 +269,12 @@ get_surface_converter(GstVaapiDisplay *display)
+     GFunc func;
+ 
+     switch (gst_vaapi_display_get_display_type(display)) {
+-#if USE_X11
++#if USE_X11 && !GST_CHECK_VERSION(1,1,0)
+     case GST_VAAPI_DISPLAY_TYPE_X11:
+         func = (GFunc)gst_vaapi_video_converter_x11_new;
+         break;
+ #endif
+-#if USE_GLX
++#if USE_GLX && !GST_CHECK_VERSION(1,1,0)
+     case GST_VAAPI_DISPLAY_TYPE_GLX:
+         func = (GFunc)gst_vaapi_video_converter_glx_new;
+         break;
+diff --git a/gst/vaapi/gstvaapivideocontext.c b/gst/vaapi/gstvaapivideocontext.c
+new file mode 100644
+index 0000000..1331d4b
+--- /dev/null
++++ b/gst/vaapi/gstvaapivideocontext.c
+@@ -0,0 +1,163 @@
++/*
++ *  gstvaapivideocontext.c - GStreamer/VA video context
++ *
++ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
++ *  Copyright (C) 2011-2013 Intel Corporation
++ *  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 "gst/vaapi/sysdeps.h"
++#include "gstvaapivideocontext.h"
++
++#if GST_CHECK_VERSION(1,1,0)
++
++GST_DEBUG_CATEGORY_STATIC(GST_CAT_CONTEXT);
++
++#define GST_VAAPI_TYPE_DISPLAY \
++    gst_vaapi_display_get_type()
++
++GType
++gst_vaapi_display_get_type(void) G_GNUC_CONST;
++
++G_DEFINE_BOXED_TYPE(GstVaapiDisplay, gst_vaapi_display,
++    (GBoxedCopyFunc)gst_vaapi_display_ref,
++    (GBoxedFreeFunc)gst_vaapi_display_unref)
++
++GstContext *
++gst_vaapi_video_context_new_with_display(GstVaapiDisplay *display,
++    gboolean persistent)
++{
++    GstContext *context;
++    GstStructure *structure;
++
++    context = gst_context_new(GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME, persistent);
++    structure = gst_context_writable_structure(context);
++    gst_structure_set(structure, "display", GST_VAAPI_TYPE_DISPLAY,
++        display, NULL);
++    return context;
++}
++
++gboolean
++gst_vaapi_video_context_get_display(GstContext *context,
++    GstVaapiDisplay **display_ptr)
++{
++    const GstStructure *structure;
++
++    g_return_val_if_fail(GST_IS_CONTEXT(context), FALSE);
++    g_return_val_if_fail(g_strcmp0(gst_context_get_context_type(context),
++                  GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME) == 0, FALSE);
++
++    structure = gst_context_get_structure(context);
++    return gst_structure_get(structure, "display", GST_VAAPI_TYPE_DISPLAY,
++        display_ptr, NULL);
++}
++
++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;
++    }
++
++    GST_CAT_INFO_OBJECT(GST_CAT_CONTEXT, pad, "context pad peer query failed");
++    return TRUE;
++}
++
++static gboolean
++run_context_query(GstElement *element, GstQuery *query)
++{
++    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 downstream neighbour */
++    it = gst_element_iterate_src_pads(element);
++    while (gst_iterator_fold(it, func, &res, query) == GST_ITERATOR_RESYNC)
++        gst_iterator_resync(it);
++    gst_iterator_free(it);
++
++    /* Ignore upstream neighbours */
++    return g_value_get_boolean(&res);
++}
++
++void
++gst_vaapi_video_context_prepare(GstElement *element, const gchar **types)
++{
++    GstContext *context;
++    GstQuery *query;
++
++    if (!GST_CAT_CONTEXT)
++        GST_DEBUG_CATEGORY_GET(GST_CAT_CONTEXT, "GST_CONTEXT");
++
++    /* (2) Query downstream with GST_QUERY_CONTEXT for the context and
++       check if downstream already has a context of the specified type */
++    context = NULL;
++    query = gst_query_new_context(GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME);
++    if (run_context_query(element, query)) {
++        gst_query_parse_context(query, &context);
++        GST_CAT_INFO_OBJECT(GST_CAT_CONTEXT, element,
++            "found context (%p) in query", context);
++        gst_element_set_context(element, context);
++    }
++    else {
++        /* (3) Post a GST_MESSAGE_NEED_CONTEXT message on the bus with
++           the required context types and afterwards check if a usable
++           context was set now as in (1). The message could be handled
++           by the parent bins of the element and the application */
++        GstMessage *msg;
++
++        GST_CAT_INFO_OBJECT(GST_CAT_CONTEXT, element,
++            "posting `need-context' message");
++        msg = gst_message_new_need_context(GST_OBJECT_CAST(element),
++            GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME);
++        gst_element_post_message(element, msg);
++    }
++    gst_query_unref(query);
++}
++
++/* (4) Create context by itself and post a GST_MESSAGE_HAVE_CONTEXT
++   message and send a GST_EVENT_CONTEXT event downstream, thus
++   containing the complete context information at this time */
++void
++gst_vaapi_video_context_propagate(GstElement *element, GstVaapiDisplay *display)
++{
++    GstContext *context;
++    GstMessage *msg;
++
++    if (!display) {
++        GST_ERROR_OBJECT(element, "failed to get VA-API display connection");
++        return;
++    }
++
++    context = gst_vaapi_video_context_new_with_display(display, FALSE);
++
++    GST_CAT_INFO_OBJECT(GST_CAT_CONTEXT, element,
++        "posting `have-context' (%p) message with display (%p)",
++        context, display);
++    msg = gst_message_new_have_context(GST_OBJECT_CAST(element), context);
++    gst_element_post_message(GST_ELEMENT_CAST(element), msg);
++}
++
++#endif
+diff --git a/gst/vaapi/gstvaapivideocontext.h b/gst/vaapi/gstvaapivideocontext.h
+new file mode 100644
+index 0000000..3ef5849
+--- /dev/null
++++ b/gst/vaapi/gstvaapivideocontext.h
+@@ -0,0 +1,75 @@
++/*
++ *  gstvaapivideocontext.h - GStreamer/VA video context
++ *
++ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
++ *  Copyright (C) 2011-2013 Intel Corporation
++ *  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
++ */
++
++#ifndef GST_VAAPI_VIDEO_CONTEXT_H
++#define GST_VAAPI_VIDEO_CONTEXT_H
++
++#include <gst/vaapi/gstvaapidisplay.h>
++
++#if GST_CHECK_VERSION(1,1,0)
++
++#define GST_VAAPI_DISPLAY_CONTEXT_TYPE_NAME "gst.vaapi.Display"
++
++/* Fake GstVideoContext symbols */
++#define GST_VIDEO_CONTEXT(obj)          (GST_ELEMENT(obj))
++#define GST_IS_VIDEO_CONTEXT(obj)       (GST_IS_ELEMENT(obj))
++#define GstVideoContext                 GstElement
++#define gst_video_context_prepare       gst_vaapi_video_context_prepare
++
++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,
++    GstVaapiDisplay **display_ptr);
++
++G_GNUC_INTERNAL
++void
++gst_vaapi_video_context_prepare(GstElement *element, const gchar **types);
++
++G_GNUC_INTERNAL
++void
++gst_vaapi_video_context_propagate(GstElement *element,
++    GstVaapiDisplay *display);
++
++#else
++#include <gst/video/videocontext.h>
++
++static inline void
++gst_vaapi_video_context_prepare(GstVideoContext *context, const gchar **types)
++{
++    gst_video_context_prepare(context, types);
++}
++
++static inline void
++gst_vaapi_video_context_propagate(GstVideoContext *context,
++    GstVaapiDisplay *display)
++{
++}
++
++#endif
++
++#endif /* GST_VAAPI_VIDEO_CONTEXT_H */
+diff --git a/gst/vaapi/gstvaapivideomemory.h b/gst/vaapi/gstvaapivideomemory.h
+index a169930..a82742b 100644
+--- a/gst/vaapi/gstvaapivideomemory.h
++++ b/gst/vaapi/gstvaapivideomemory.h
+@@ -42,6 +42,10 @@ typedef struct _GstVaapiVideoAllocatorClass     GstVaapiVideoAllocatorClass;
+ 
+ #define GST_VAAPI_VIDEO_MEMORY_NAME             "GstVaapiVideoMemory"
+ 
++#if GST_CHECK_VERSION(1,1,0)
++#define GST_CAPS_FEATURE_MEMORY_VAAPI_SURFACE   "memory:VASurface"
++#endif
++
+ /**
+  * GstVaapiVideoMemoryMapType:
+  * @GST_VAAPI_VIDEO_MEMORY_MAP_TYPE_SURFACE: map with gst_buffer_map()
+diff --git a/gst/vaapi/gstvaapivideometa_texture.c b/gst/vaapi/gstvaapivideometa_texture.c
+new file mode 100644
+index 0000000..17b19a0
+--- /dev/null
++++ b/gst/vaapi/gstvaapivideometa_texture.c
+@@ -0,0 +1,92 @@
++/*
++ *  gstvaapivideometa_texture.c - GStreamer/VA video meta (GLTextureUpload)
++ *
++ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
++ *  Copyright (C) 2011-2013 Intel Corporation
++ *  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 "gst/vaapi/sysdeps.h"
++#include "gstvaapivideometa.h"
++#include "gstvaapivideometa_texture.h"
++#include "gstvaapipluginutil.h"
++
++#if GST_CHECK_VERSION(1,1,0) && USE_GLX
++static void
++gst_vaapi_texure_upload_free(gpointer data)
++{
++    GstVaapiTexture * const texture = data;
++
++    if (texture)
++        gst_vaapi_texture_unref(texture);
++}
++
++static gboolean
++gst_vaapi_texture_upload(GstVideoGLTextureUploadMeta *meta, guint texture_id[4])
++{
++    GstVaapiVideoMeta * const vmeta =
++        gst_buffer_get_vaapi_video_meta(meta->buffer);
++    GstVaapiTexture *texture = meta->user_data;
++    GstVaapiSurface * const surface = gst_vaapi_video_meta_get_surface(vmeta);
++    GstVaapiDisplay * const dpy =
++        gst_vaapi_object_get_display(GST_VAAPI_OBJECT(surface));
++
++    if (gst_vaapi_display_get_display_type(dpy) != GST_VAAPI_DISPLAY_TYPE_GLX)
++        return FALSE;
++
++    if (texture) {
++        GstVaapiDisplay * const tex_dpy =
++            gst_vaapi_object_get_display(GST_VAAPI_OBJECT(texture));
++        if (tex_dpy != dpy)
++            gst_vaapi_texture_replace(&texture, NULL);
++    }
++
++    if (!texture) {
++        /* FIXME: should we assume target? */
++        texture = gst_vaapi_texture_new_with_texture(dpy, texture_id[0],
++            GL_TEXTURE_2D, GL_RGBA);
++        meta->user_data = texture;
++    }
++
++    if (!gst_vaapi_apply_composition(surface, meta->buffer))
++        GST_WARNING("could not update subtitles");
++
++    return gst_vaapi_texture_put_surface(texture, surface,
++        gst_vaapi_video_meta_get_render_flags(vmeta));
++}
++#endif
++
++#if GST_CHECK_VERSION(1,1,0)
++gboolean
++gst_buffer_add_texture_upload_meta(GstBuffer *buffer)
++{
++    GstVideoGLTextureUploadMeta *meta = NULL;
++    GstVideoGLTextureType tex_type[] = { GST_VIDEO_GL_TEXTURE_TYPE_RGBA };
++
++    if (!buffer)
++        return FALSE;
++
++#if USE_GLX
++    meta = gst_buffer_add_video_gl_texture_upload_meta(buffer,
++        GST_VIDEO_GL_TEXTURE_ORIENTATION_X_NORMAL_Y_NORMAL,
++        1, tex_type, gst_vaapi_texture_upload,
++        NULL, NULL, gst_vaapi_texure_upload_free);
++#endif
++    return meta != NULL;
++}
++#endif
+diff --git a/gst/vaapi/gstvaapivideometa_texture.h b/gst/vaapi/gstvaapivideometa_texture.h
+new file mode 100644
+index 0000000..2f95434
+--- /dev/null
++++ b/gst/vaapi/gstvaapivideometa_texture.h
+@@ -0,0 +1,37 @@
++/*
++ *  gstvaapivideometa_texture.h - GStreamer/VA video meta (GLTextureUpload)
++ *
++ *  Copyright (C) 2010-2011 Splitted-Desktop Systems
++ *  Copyright (C) 2011-2013 Intel Corporation
++ *  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
++ */
++
++#ifndef GST_VAAPI_VIDEO_META_TEXTURE_H
++#define GST_VAAPI_VIDEO_META_TEXTURE_H
++
++#include <gst/vaapi/gstvaapitexture.h>
++
++G_BEGIN_DECLS
++
++G_GNUC_INTERNAL
++gboolean
++gst_buffer_add_texture_upload_meta(GstBuffer *buffer);
++
++G_END_DECLS
++
++#endif /* GST_VAAPI_VIDEO_META_TEXTURE_H */
+diff --git a/tests/simple-decoder.c b/tests/simple-decoder.c
+index 5b50c87..3c434d0 100644
+--- a/tests/simple-decoder.c
++++ b/tests/simple-decoder.c
+@@ -498,7 +498,7 @@ renderer_process(App *app, RenderFrame *rfp)
+     ensure_window_size(app, surface);
+ 
+     crop_rect = gst_vaapi_surface_proxy_get_crop_rect(rfp->proxy);
+-    if (!ensure_pixmaps(app, surface, crop_rect))
++    if (g_use_pixmap && !ensure_pixmaps(app, surface, crop_rect))
+         SEND_ERROR("failed to create intermediate pixmaps");
+ 
+     if (!gst_vaapi_surface_sync(surface))
================================================================

---- gitweb:

http://git.pld-linux.org/gitweb.cgi/packages/gstreamer-vaapi.git/commitdiff/f29a028ed0435565f3e63914821dfaab34cce5bc



More information about the pld-cvs-commit mailing list