Re: [FFmpeg-devel] [PATCH v3 1/5] libavutil: some VAAPI infrastructure

2016-01-19 Thread wm4
On Mon, 18 Jan 2016 22:49:51 +
Mark Thompson  wrote:

> ---
>  configure  |   4 +
>  libavutil/Makefile |   1 +
>  libavutil/vaapi.c  | 497 
> +
>  libavutil/vaapi.h  | 123 +
>  4 files changed, 625 insertions(+)
>  create mode 100644 libavutil/vaapi.c
>  create mode 100644 libavutil/vaapi.h
> 

Trying to do a more thorough review.

> diff --git a/configure b/configure
> index 7cef6f5..1c77015 100755
> --- a/configure
> +++ b/configure
> @@ -5739,6 +5739,10 @@ enabled vaapi && enabled xlib &&
>  check_lib2 "va/va.h va/va_x11.h" vaGetDisplay -lva -lva-x11 &&
>  enable vaapi_x11
> 
> +enabled vaapi &&
> +check_lib2 "va/va.h va/va_drm.h" vaGetDisplayDRM -lva -lva-drm &&
> +enable vaapi_drm
> +
>  enabled vdpau &&
>  check_cpp_condition vdpau/vdpau.h "defined 
> VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
>  disable vdpau
> diff --git a/libavutil/Makefile b/libavutil/Makefile
> index bf8c713..8025f9f 100644
> --- a/libavutil/Makefile
> +++ b/libavutil/Makefile
> @@ -146,6 +146,7 @@ OBJS-$(!HAVE_ATOMICS_NATIVE)+= atomic.o   
>   \
> 
>  OBJS-$(CONFIG_LZO)  += lzo.o
>  OBJS-$(CONFIG_OPENCL)   += opencl.o opencl_internal.o
> +OBJS-$(CONFIG_VAAPI)+= vaapi.o
> 
>  OBJS += $(COMPAT_OBJS:%=../compat/%)
> 
> diff --git a/libavutil/vaapi.c b/libavutil/vaapi.c
> new file mode 100644
> index 000..8a9a524
> --- /dev/null
> +++ b/libavutil/vaapi.c
> @@ -0,0 +1,497 @@
> +/*
> + * VAAPI helper functions.
> + *
> + * Copyright (C) 2016 Mark Thompson 
> + *
> + * This file is part of FFmpeg.
> + *
> + * FFmpeg is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * FFmpeg is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with FFmpeg; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
> USA
> + */
> +
> +#include "vaapi.h"
> +
> +#include "avassert.h"
> +#include "imgutils.h"
> +#include "pixfmt.h"
> +
> +
> +void av_vaapi_lock_hardware_context(AVVAAPIHardwareContext *ctx)
> +{
> +if(ctx->lock)
> +ctx->lock();
> +}
> +
> +void av_vaapi_unlock_hardware_context(AVVAAPIHardwareContext *ctx)
> +{
> +if(ctx->unlock)
> +ctx->unlock();
> +}

The lock callbacks should take some sort of opaque context pointer.

> +
> +static const AVClass vaapi_pipeline_class = {
> +.class_name = "VAAPI/pipeline",
> +.item_name  = av_default_item_name,
> +.version= LIBAVUTIL_VERSION_INT,
> +};
> +
> +static int vaapi_create_surfaces(AVVAAPIPipelineContext *ctx,
> + AVVAAPISurfaceConfig *config,
> + AVVAAPISurface *surfaces,
> + VASurfaceID *ids)
> +{
> +VAStatus vas;
> +int i;
> +
> +vas = vaCreateSurfaces(ctx->hardware_context->display, config->rt_format,
> +   config->width, config->height, ids, config->count,
> +   config->attributes, config->attribute_count);
> +if(vas != VA_STATUS_SUCCESS) {
> +av_log(ctx, AV_LOG_ERROR, "Failed to create "
> +   "surfaces: %d (%s).\n", vas, vaErrorStr(vas));
> +return AVERROR(EINVAL);
> +}
> +
> +for(i = 0; i < config->count; i++) {
> +surfaces[i].id   = ids[i];
> +surfaces[i].refcount = 0;
> +surfaces[i].hardware_context = ctx->hardware_context;
> +surfaces[i].config   = config;
> +}
> +
> +return 0;
> +}
> +
> +static void vaapi_destroy_surfaces(AVVAAPIPipelineContext *ctx,
> +   AVVAAPISurfaceConfig *config,
> +   AVVAAPISurface *surfaces,
> +   VASurfaceID *ids)
> +{
> +VAStatus vas;
> +int i;
> +
> +for(i = 0; i < config->count; i++) {
> +av_assert0(surfaces[i].id == ids[i]);
> +if(surfaces[i].refcount > 0)
> +av_log(ctx, AV_LOG_WARNING, "Destroying surface %#x which is "
> +   "still in use.\n", surfaces[i].id);
> +av_assert0(surfaces[i].hardware_context == ctx->hardware_context);
> +av_assert0(surfaces[i].config == config);
> +}
> +
> +vas = vaDestroySurfaces(ctx->hardware_context->display,
> +ids, config->count);
> +if(vas != VA_STATUS_SUCCESS) {
> +

Re: [FFmpeg-devel] [PATCH v3 1/5] libavutil: some VAAPI infrastructure

2016-01-19 Thread wm4
On Tue, 19 Jan 2016 13:19:36 +
Mark Thompson  wrote:

> ...
> >> +
> >> +static void vaapi_codec_release_surface(void *opaque, uint8_t *data)
> >> +{
> >> +AVVAAPISurface *surface = opaque;
> >> +
> >> +av_assert0(surface->refcount > 0);
> >> +--surface->refcount;
> >> +}  
> > 
> > Maybe that's just me, but I think vaapi surfaces shouldn't break what
> > is guaranteed by AVFrame:
> > 
> > - unreffing them is thread-safe
> > - unreffing the last AVFrame will also unref whatever manages the
> >   surfaces (or alternatively, if the vaapi state is not refcounted, kill
> >   the process if there are still AVFrames referencing the vaapi state,
> >   as these AVFrames would essentially have dangling pointers)
> > 
> > That's a bit more complex, but IMO worth it.  
> 
> Unref being thread safe is a bit annoying because of the locking - if the 
> lock were recursive then it could work, but that pushes me into pthreadland 
> to do it.  Is that ok?

There could be a second lock which is not user-visible, and which
protects the surface pool only.

> 
> I'm not sure what you mean by the second point.  What do you want to also go 
> when the last AVFrame gets unreferenced?

Imagine someone holding an AVFrame referencing the surface in the pool
at a time when the surface pool should be destroyed.

In my own vaapi code, I keep the pool alive until all frames are
unreferenced, even if the decoder is destroyed before. Helps with
making format changes simpler.

> 
> I know the AVFrame setup is all a bit dubious because I still don't really 
> "get" how AVFrames are meant to be used.  I will think about it further.

Some explanation: AVFrames are refcounted via AVFrame.buf[]. Each
AVBufferRef is a refcounted memory region, and the AVFrame.data[]
pointers are supposed to point into one of the buffers. (All planes can
point into memory covered by AVFrame.buf[0], but it's also possible to
have each plane its own buffer.) If you create a reference to an
AVFrame with e.g. av_frame_ref(), new AVBufferRefs are created, which
increases the refcount of the internal buffer. Calling av_frame_unref()
deletes the AVBufferRefs and decrease the AVBuffer refcount. If the
AVBuffer's refcount reaches 0, the user-provided free callback is
invoked. (If there's no free callback, av_free() is called on the
original buffer data pointer.)

With hwaccels, the situation is a bit more confusing. There are no data
pointers, only an ID casted to a pointer. So it's harder to reason what
exactly AVBufferRef.data should be. But everything else can work in the
same way.

If the AVFrame is used in a different thread than the decoder, then it
can easily happen that the free callback is invoked in a different
thread.

> >> +
> >> +static int vaapi_get_surface(AVVAAPIPipelineContext *ctx,
> >> + AVVAAPISurfaceConfig *config,
> >> + AVVAAPISurface *surfaces, AVFrame *frame)
> >> +{
> >> +AVVAAPISurface *surface;
> >> +int i;
> >> +
> >> +for(i = 0; i < config->count; i++) {
> >> +if(surfaces[i].refcount == 0)
> >> +break;
> >> +}
> >> +if(i >= config->count) {
> >> +av_log(ctx, AV_LOG_ERROR, "Failed to allocate surface "
> >> +   "(%d in use).\n", config->count);
> >> +return AVERROR(ENOMEM);
> >> +}
> >> +surface = [i];
> >> +
> >> +++surface->refcount;
> >> +frame->data[3] = (uint8_t*)(uintptr_t)surface->id;
> >> +frame->buf[0] = av_buffer_create((uint8_t*)surface, 0,
> >> + _codec_release_surface,
> >> + surface, AV_BUFFER_FLAG_READONLY);
> >> +if(!frame->buf[0]) {
> >> +av_log(ctx, AV_LOG_ERROR, "Failed to allocate dummy buffer "
> >> +   "for surface %#x.\n", surface->id);
> >> +return AVERROR(ENOMEM);
> >> +}
> >> +
> >> +frame->format = AV_PIX_FMT_VAAPI;
> >> +frame->width  = config->width;
> >> +frame->height = config->height;
> >> +
> >> +return 0;
> >> +}
> >> +
> >> +int ff_vaapi_get_input_surface(AVVAAPIPipelineContext *ctx, AVFrame 
> >> *frame)
> >> +{
> >> +return vaapi_get_surface(ctx, ctx->input, ctx->input_surfaces, frame);
> >> +}
> >> +
> >> +int ff_vaapi_get_output_surface(AVVAAPIPipelineContext *ctx, AVFrame 
> >> *frame)
> >> +{
> >> +return vaapi_get_surface(ctx, ctx->output, ctx->output_surfaces, 
> >> frame);
> >> +}  
> > 
> > I wonder if vaapi_get_surface() could instead be some sort of
> > independent frame pool? (But maybe the way you did is already elegant
> > wrt. how vaapi works?)  
> 
> The only trickiness here is that you have to declare all of the surfaces you 
> are going to use for output when you create the pipeline context.
> 
> So yes, probably, if I understood AVFrames better...  Will consider along 
> with the previous point.

Side note: it might also be possible to recreate the decoder and
recreate all surfaces if 

Re: [FFmpeg-devel] [PATCH v3 1/5] libavutil: some VAAPI infrastructure

2016-01-19 Thread Mark Thompson
On 19/01/16 11:54, wm4 wrote:
> On Mon, 18 Jan 2016 22:49:51 +
> Mark Thompson  wrote:
> 
>> ---
>>  configure  |   4 +
>>  libavutil/Makefile |   1 +
>>  libavutil/vaapi.c  | 497 
>> +
>>  libavutil/vaapi.h  | 123 +
>>  4 files changed, 625 insertions(+)
>>  create mode 100644 libavutil/vaapi.c
>>  create mode 100644 libavutil/vaapi.h
>>
> 
> Trying to do a more thorough review.

Thanks :)

>> diff --git a/configure b/configure
>> index 7cef6f5..1c77015 100755
>> --- a/configure
>> +++ b/configure
>> @@ -5739,6 +5739,10 @@ enabled vaapi && enabled xlib &&
>>  check_lib2 "va/va.h va/va_x11.h" vaGetDisplay -lva -lva-x11 &&
>>  enable vaapi_x11
>>
>> +enabled vaapi &&
>> +check_lib2 "va/va.h va/va_drm.h" vaGetDisplayDRM -lva -lva-drm &&
>> +enable vaapi_drm
>> +
>>  enabled vdpau &&
>>  check_cpp_condition vdpau/vdpau.h "defined 
>> VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
>>  disable vdpau
>> diff --git a/libavutil/Makefile b/libavutil/Makefile
>> index bf8c713..8025f9f 100644
>> --- a/libavutil/Makefile
>> +++ b/libavutil/Makefile
>> @@ -146,6 +146,7 @@ OBJS-$(!HAVE_ATOMICS_NATIVE)+= atomic.o  
>>\
>>
>>  OBJS-$(CONFIG_LZO)  += lzo.o
>>  OBJS-$(CONFIG_OPENCL)   += opencl.o opencl_internal.o
>> +OBJS-$(CONFIG_VAAPI)+= vaapi.o
>>
>>  OBJS += $(COMPAT_OBJS:%=../compat/%)
>>
>> diff --git a/libavutil/vaapi.c b/libavutil/vaapi.c
>> new file mode 100644
>> index 000..8a9a524
>> --- /dev/null
>> +++ b/libavutil/vaapi.c
>> @@ -0,0 +1,497 @@
>> +/*
>> + * VAAPI helper functions.
>> + *
>> + * Copyright (C) 2016 Mark Thompson 
>> + *
>> + * This file is part of FFmpeg.
>> + *
>> + * FFmpeg is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU Lesser General Public
>> + * License as published by the Free Software Foundation; either
>> + * version 2.1 of the License, or (at your option) any later version.
>> + *
>> + * FFmpeg is distributed in the hope that it will be useful,
>> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
>> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
>> + * Lesser General Public License for more details.
>> + *
>> + * You should have received a copy of the GNU Lesser General Public
>> + * License along with FFmpeg; if not, write to the Free Software
>> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 
>> USA
>> + */
>> +
>> +#include "vaapi.h"
>> +
>> +#include "avassert.h"
>> +#include "imgutils.h"
>> +#include "pixfmt.h"
>> +
>> +
>> +void av_vaapi_lock_hardware_context(AVVAAPIHardwareContext *ctx)
>> +{
>> +if(ctx->lock)
>> +ctx->lock();
>> +}
>> +
>> +void av_vaapi_unlock_hardware_context(AVVAAPIHardwareContext *ctx)
>> +{
>> +if(ctx->unlock)
>> +ctx->unlock();
>> +}
> 
> The lock callbacks should take some sort of opaque context pointer.

Ok; will add.

>> +
>> +static const AVClass vaapi_pipeline_class = {
>> +.class_name = "VAAPI/pipeline",
>> +.item_name  = av_default_item_name,
>> +.version= LIBAVUTIL_VERSION_INT,
>> +};
>> +
>> +static int vaapi_create_surfaces(AVVAAPIPipelineContext *ctx,
>> + AVVAAPISurfaceConfig *config,
>> + AVVAAPISurface *surfaces,
>> + VASurfaceID *ids)
>> +{
>> +VAStatus vas;
>> +int i;
>> +
>> +vas = vaCreateSurfaces(ctx->hardware_context->display, 
>> config->rt_format,
>> +   config->width, config->height, ids, 
>> config->count,
>> +   config->attributes, config->attribute_count);
>> +if(vas != VA_STATUS_SUCCESS) {
>> +av_log(ctx, AV_LOG_ERROR, "Failed to create "
>> +   "surfaces: %d (%s).\n", vas, vaErrorStr(vas));
>> +return AVERROR(EINVAL);
>> +}
>> +
>> +for(i = 0; i < config->count; i++) {
>> +surfaces[i].id   = ids[i];
>> +surfaces[i].refcount = 0;
>> +surfaces[i].hardware_context = ctx->hardware_context;
>> +surfaces[i].config   = config;
>> +}
>> +
>> +return 0;
>> +}
>> +
>> +static void vaapi_destroy_surfaces(AVVAAPIPipelineContext *ctx,
>> +   AVVAAPISurfaceConfig *config,
>> +   AVVAAPISurface *surfaces,
>> +   VASurfaceID *ids)
>> +{
>> +VAStatus vas;
>> +int i;
>> +
>> +for(i = 0; i < config->count; i++) {
>> +av_assert0(surfaces[i].id == ids[i]);
>> +if(surfaces[i].refcount > 0)
>> +av_log(ctx, AV_LOG_WARNING, "Destroying surface %#x which is "
>> +   "still in use.\n", surfaces[i].id);
>> +av_assert0(surfaces[i].hardware_context == ctx->hardware_context);
>> +

Re: [FFmpeg-devel] [PATCH v3 1/5] libavutil: some VAAPI infrastructure

2016-01-18 Thread Mark Thompson
On 19/01/16 00:18, Michael Niedermayer wrote:
> On Mon, Jan 18, 2016 at 10:49:51PM +, Mark Thompson wrote:
>>
>> ---
>>  configure  |   4 +
>>  libavutil/Makefile |   1 +
>>  libavutil/vaapi.c  | 497 
>> +
>>  libavutil/vaapi.h  | 123 +
>>  4 files changed, 625 insertions(+)
>>  create mode 100644 libavutil/vaapi.c
>>  create mode 100644 libavutil/vaapi.h
> 
> breaks build
> make distclean ; ./configure && make -j12
> ...
> 
> CC  libavutil/time.o
> CC  libavutil/timecode.o
> CC  libavutil/tree.o
> CC  libavutil/twofish.o
> CC  libavutil/utils.o
> CC  libavutil/vaapi.o
> CC  libavutil/x86/cpu.o
> In file included from libavutil/vaapi.c:23:0:
> libavutil/vaapi.h:63:5: error: unknown type name ‘VASurfaceAttrib’
> libavutil/vaapi.c: In function ‘vaapi_create_surfaces’:
> libavutil/vaapi.c:59:28: warning: passing argument 5 of ‘vaCreateSurfaces’ 
> makes integer from pointer without a cast [enabled by default]
> /usr/include/va/va.h:432:10: note: expected ‘int’ but argument is of type 
> ‘VASurfaceID *’
> libavutil/vaapi.c:59:28: warning: passing argument 6 of ‘vaCreateSurfaces’ 
> makes pointer from integer without a cast [enabled by default]
> /usr/include/va/va.h:432:10: note: expected ‘VASurfaceID *’ but argument is 
> of type ‘unsigned int’
> libavutil/vaapi.c:59:28: error: too many arguments to function 
> ‘vaCreateSurfaces’
> /usr/include/va/va.h:432:10: note: declared here
> libavutil/vaapi.c: In function ‘ff_vaapi_copy_to_surface’:
> libavutil/vaapi.c:447:9: error: ‘VA_FOURCC_BGRX’ undeclared (first use in 
> this function)
> libavutil/vaapi.c:447:9: note: each undeclared identifier is reported only 
> once for each function it appears in
> make: *** [libavutil/vaapi.o] Error 1
> make: *** Waiting for unfinished jobs
> 

Given the old vaCreateSurfaces you must have libva < 1.2.  libva >= 1.6 was 
stated as the requirement for now in the first email, though even done properly 
your setup would have everything here disabled at configure time.

I think the configure test will be looking for libva 1.2.1 / VAAPI 0.34 for 
most of this and libva 1.6.0 / VAAPI 0.37 for H.265 (with suitable ifdefs), 
though more testing is needed to know that those do actually always work.  (I 
have been using libva 1.6.2 / VAAPI 0.38.)

I'll write something sensible for that test and associated conditionals in the 
next version, even if it isn't exactly correct.

- Mark

___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


Re: [FFmpeg-devel] [PATCH v3 1/5] libavutil: some VAAPI infrastructure

2016-01-18 Thread Michael Niedermayer
On Mon, Jan 18, 2016 at 10:49:51PM +, Mark Thompson wrote:
> 
> ---
>  configure  |   4 +
>  libavutil/Makefile |   1 +
>  libavutil/vaapi.c  | 497 
> +
>  libavutil/vaapi.h  | 123 +
>  4 files changed, 625 insertions(+)
>  create mode 100644 libavutil/vaapi.c
>  create mode 100644 libavutil/vaapi.h

breaks build
make distclean ; ./configure && make -j12
...

CC  libavutil/time.o
CC  libavutil/timecode.o
CC  libavutil/tree.o
CC  libavutil/twofish.o
CC  libavutil/utils.o
CC  libavutil/vaapi.o
CC  libavutil/x86/cpu.o
In file included from libavutil/vaapi.c:23:0:
libavutil/vaapi.h:63:5: error: unknown type name ‘VASurfaceAttrib’
libavutil/vaapi.c: In function ‘vaapi_create_surfaces’:
libavutil/vaapi.c:59:28: warning: passing argument 5 of ‘vaCreateSurfaces’ 
makes integer from pointer without a cast [enabled by default]
/usr/include/va/va.h:432:10: note: expected ‘int’ but argument is of type 
‘VASurfaceID *’
libavutil/vaapi.c:59:28: warning: passing argument 6 of ‘vaCreateSurfaces’ 
makes pointer from integer without a cast [enabled by default]
/usr/include/va/va.h:432:10: note: expected ‘VASurfaceID *’ but argument is of 
type ‘unsigned int’
libavutil/vaapi.c:59:28: error: too many arguments to function 
‘vaCreateSurfaces’
/usr/include/va/va.h:432:10: note: declared here
libavutil/vaapi.c: In function ‘ff_vaapi_copy_to_surface’:
libavutil/vaapi.c:447:9: error: ‘VA_FOURCC_BGRX’ undeclared (first use in this 
function)
libavutil/vaapi.c:447:9: note: each undeclared identifier is reported only once 
for each function it appears in
make: *** [libavutil/vaapi.o] Error 1
make: *** Waiting for unfinished jobs


[...]
-- 
Michael GnuPG fingerprint: 9FF2128B147EF6730BADF133611EC787040B0FAB

I am the wisest man alive, for I know one thing, and that is that I know
nothing. -- Socrates


signature.asc
Description: Digital signature
___
ffmpeg-devel mailing list
ffmpeg-devel@ffmpeg.org
http://ffmpeg.org/mailman/listinfo/ffmpeg-devel


[FFmpeg-devel] [PATCH v3 1/5] libavutil: some VAAPI infrastructure

2016-01-18 Thread Mark Thompson

---
 configure  |   4 +
 libavutil/Makefile |   1 +
 libavutil/vaapi.c  | 497 +
 libavutil/vaapi.h  | 123 +
 4 files changed, 625 insertions(+)
 create mode 100644 libavutil/vaapi.c
 create mode 100644 libavutil/vaapi.h

diff --git a/configure b/configure
index 7cef6f5..1c77015 100755
--- a/configure
+++ b/configure
@@ -5739,6 +5739,10 @@ enabled vaapi && enabled xlib &&
 check_lib2 "va/va.h va/va_x11.h" vaGetDisplay -lva -lva-x11 &&
 enable vaapi_x11

+enabled vaapi &&
+check_lib2 "va/va.h va/va_drm.h" vaGetDisplayDRM -lva -lva-drm &&
+enable vaapi_drm
+
 enabled vdpau &&
 check_cpp_condition vdpau/vdpau.h "defined 
VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
 disable vdpau
diff --git a/libavutil/Makefile b/libavutil/Makefile
index bf8c713..8025f9f 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -146,6 +146,7 @@ OBJS-$(!HAVE_ATOMICS_NATIVE)+= atomic.o 
\

 OBJS-$(CONFIG_LZO)  += lzo.o
 OBJS-$(CONFIG_OPENCL)   += opencl.o opencl_internal.o
+OBJS-$(CONFIG_VAAPI)+= vaapi.o

 OBJS += $(COMPAT_OBJS:%=../compat/%)

diff --git a/libavutil/vaapi.c b/libavutil/vaapi.c
new file mode 100644
index 000..8a9a524
--- /dev/null
+++ b/libavutil/vaapi.c
@@ -0,0 +1,497 @@
+/*
+ * VAAPI helper functions.
+ *
+ * Copyright (C) 2016 Mark Thompson 
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "vaapi.h"
+
+#include "avassert.h"
+#include "imgutils.h"
+#include "pixfmt.h"
+
+
+void av_vaapi_lock_hardware_context(AVVAAPIHardwareContext *ctx)
+{
+if(ctx->lock)
+ctx->lock();
+}
+
+void av_vaapi_unlock_hardware_context(AVVAAPIHardwareContext *ctx)
+{
+if(ctx->unlock)
+ctx->unlock();
+}
+
+
+static const AVClass vaapi_pipeline_class = {
+.class_name = "VAAPI/pipeline",
+.item_name  = av_default_item_name,
+.version= LIBAVUTIL_VERSION_INT,
+};
+
+static int vaapi_create_surfaces(AVVAAPIPipelineContext *ctx,
+ AVVAAPISurfaceConfig *config,
+ AVVAAPISurface *surfaces,
+ VASurfaceID *ids)
+{
+VAStatus vas;
+int i;
+
+vas = vaCreateSurfaces(ctx->hardware_context->display, config->rt_format,
+   config->width, config->height, ids, config->count,
+   config->attributes, config->attribute_count);
+if(vas != VA_STATUS_SUCCESS) {
+av_log(ctx, AV_LOG_ERROR, "Failed to create "
+   "surfaces: %d (%s).\n", vas, vaErrorStr(vas));
+return AVERROR(EINVAL);
+}
+
+for(i = 0; i < config->count; i++) {
+surfaces[i].id   = ids[i];
+surfaces[i].refcount = 0;
+surfaces[i].hardware_context = ctx->hardware_context;
+surfaces[i].config   = config;
+}
+
+return 0;
+}
+
+static void vaapi_destroy_surfaces(AVVAAPIPipelineContext *ctx,
+   AVVAAPISurfaceConfig *config,
+   AVVAAPISurface *surfaces,
+   VASurfaceID *ids)
+{
+VAStatus vas;
+int i;
+
+for(i = 0; i < config->count; i++) {
+av_assert0(surfaces[i].id == ids[i]);
+if(surfaces[i].refcount > 0)
+av_log(ctx, AV_LOG_WARNING, "Destroying surface %#x which is "
+   "still in use.\n", surfaces[i].id);
+av_assert0(surfaces[i].hardware_context == ctx->hardware_context);
+av_assert0(surfaces[i].config == config);
+}
+
+vas = vaDestroySurfaces(ctx->hardware_context->display,
+ids, config->count);
+if(vas != VA_STATUS_SUCCESS) {
+av_log(ctx, AV_LOG_ERROR, "Failed to destroy surfaces: "
+   "%d (%s).\n", vas, vaErrorStr(vas));
+}
+}
+
+int ff_vaapi_pipeline_init(AVVAAPIPipelineContext *ctx,
+   AVVAAPIHardwareContext *hw_ctx,
+   AVVAAPIPipelineConfig *config,
+   AVVAAPISurfaceConfig *input,
+   AVVAAPISurfaceConfig *output)
+{
+VAStatus vas;
+int err;
+
+//