[FFmpeg-devel] [PATCH v5 1/5] libavcodec: VAAPI support infrastructure
wm4
nfxjfg at googlemail.com
Wed Feb 3 14:54:59 CET 2016
On Tue, 2 Feb 2016 19:51:53 +0000
Mark Thompson <sw at jkqxz.net> wrote:
> On 01/02/16 15:58, wm4 wrote:
> > On Sat, 30 Jan 2016 22:11:52 +0000
> > Mark Thompson <sw at jkqxz.net> wrote:
> >
> >> ---
> >> configure | 5 +
> >> libavcodec/Makefile | 1 +
> >> libavcodec/vaapi_support.c | 710 +++++++++++++++++++++++++++++++++++++++++++++
> >> libavcodec/vaapi_support.h | 122 ++++++++
> >> 4 files changed, 838 insertions(+)
> >> create mode 100644 libavcodec/vaapi_support.c
> >> create mode 100644 libavcodec/vaapi_support.h
> >>
> >> diff --git a/configure b/configure
> >> index dba8180..e7f53af 100755
> >> --- a/configure
> >> +++ b/configure
> >> @@ -2037,6 +2037,7 @@ CONFIG_EXTRA="
> >> texturedsp
> >> texturedspenc
> >> tpeldsp
> >> + vaapi_recent
> >> videodsp
> >> vp3dsp
> >> vp56dsp
> >> @@ -5768,6 +5769,10 @@ enabled vaapi &&
> >> check_lib va/va.h vaInitialize -lva ||
> >> disable vaapi
> >>
> >> +enabled vaapi &&
> >> + check_code cc va/va.h "vaCreateSurfaces(0, 0, 0, 0, 0, 0, 0, 0)" &&
> >> + enable vaapi_recent
> >> +
> >> enabled vaapi && enabled xlib &&
> >> check_lib2 "va/va.h va/va_x11.h" vaGetDisplay -lva -lva-x11 &&
> >> enable vaapi_x11
> >> diff --git a/libavcodec/Makefile b/libavcodec/Makefile
> >> index de957d8..045d118 100644
> >> --- a/libavcodec/Makefile
> >> +++ b/libavcodec/Makefile
> >> @@ -719,6 +719,7 @@ OBJS-$(CONFIG_ADPCM_YAMAHA_ENCODER) += adpcmenc.o adpcm_data.o
> >> OBJS-$(CONFIG_D3D11VA) += dxva2.o
> >> OBJS-$(CONFIG_DXVA2) += dxva2.o
> >> OBJS-$(CONFIG_VAAPI) += vaapi.o
> >> +OBJS-$(CONFIG_VAAPI_RECENT) += vaapi_support.o
> >> OBJS-$(CONFIG_VDA) += vda.o videotoolbox.o
> >> OBJS-$(CONFIG_VIDEOTOOLBOX) += videotoolbox.o
> >> OBJS-$(CONFIG_VDPAU) += vdpau.o
> >> diff --git a/libavcodec/vaapi_support.c b/libavcodec/vaapi_support.c
> >> new file mode 100644
> >> index 0000000..2e22f98
> >> --- /dev/null
> >> +++ b/libavcodec/vaapi_support.c
> >> @@ -0,0 +1,710 @@
> >> +/*
> >> + * VAAPI helper functions.
> >> + *
> >> + * Copyright (C) 2016 Mark Thompson <mrt at jkqxz.net>
> >> + *
> >> + * 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_support.h"
> >> +
> >> +#include "libavutil/avassert.h"
> >> +#include "libavutil/imgutils.h"
> >> +#include "libavutil/pixfmt.h"
> >> +
> >> +
> >> +static AVClass vaapi_class = {
> >> + .class_name = "vaapi",
> >> + .item_name = av_default_item_name,
> >> + .version = LIBAVUTIL_VERSION_INT,
> >> +};
> >> +static AVClass *vaapi_log = &vaapi_class;
> >
> > We've talked about it on IRC. So the idea was matching
> > AVVAAPIHardwareContext with vaapi_context, which is why the first
> > member of AVVAAPIHardwareContext can't be AVClass. I think trying to
> > somehow make these structs compatible should be given up, and instead
> > the struct should have a vaapi_context pointer field instead.
>
> Yes.
>
> > Also, I'm very worried about how this patch in general with combine
> > with the API Libav is planning to add:
> >
> > https://lists.libav.org/pipermail/libav-devel/2016-January/074490.html
> >
> > To make this clear, above patch series:
> > - extends the buffer pool to make it useful for the hwdec case (where
> > you need to free the hw context when the final AVFrame is unreffed)
> > - create a common API for hwaccel contexts, which overlaps with this
> > patch to some degree, but not fully
> > - adds a hwaccel context field to AVFrame
> > - the hwaccel context is refcounted
> > - adds helper for reading back data from hwaccel AVFrames in an
> > API-independent way
> >
> > I'm not sure what to make out of this mess. Any ideas? I don't really
> > want to hold this patch series back either. There is not much reason to
> > refactor the whole API 1 week after it has been added either.
>
> I'm not sure how to respond usefully to all of that, it adds a lot of new things all over the place.
>
> It looks like it has most of the elements needed here, though I would need to examine it more carefully to be sure. (I don't see a way to do the "enumerate all of a set of frames for something which requires all render targets in advance" operation, but maybe I haven't looked hard enough.)
>
The newer patches have something for this, I think. At least partially.
> ...
> >> + err = 0;
> >> + if(0) {
> >> + fail:
> >
> > This looks funny. My personal preference is avoiding such tricks, but
> > maybe it's not important.
>
> I think this unwinding was more complex at some previous iteration. The failure case can be moved below the return now, though I still think it's nice to have exactly one lock/unlock pair to be sure that that is correct.
If you think so... I still think it could be more readable, but I don't
want to force you. In general, gotos should be lined up at the end of a
function for cleanup, and "if (0)" looks like a WTF.
> >> + if(surface) {
> >> + if(surface->id)
> >> + vaDestroySurfaces(hw_ctx->display, &surface->id, 1);
> >> + av_free(surface);
> >> + }
> >> + if(frame)
> >> + av_frame_free(&frame);
> >> + for(--i; i >= 0; i--)
> >> + av_frame_free(&pool->frames[i]);
> >> + }
> >> +
> >> + av_vaapi_unlock_hardware_context(hw_ctx);
> >> + return err;
> >> +}
> >> +
> >> +int av_vaapi_surface_pool_uninit(AVVAAPISurfacePool *pool)
> >> +
> >> +{
> >> + int i;
> >> +
> >> + av_vaapi_lock_hardware_context(pool->hardware_context);
> >> +
> >> + for(i = 0; i < FF_ARRAY_ELEMS(pool->frames); i++) {
> >> + if(pool->frames[i])
> >> + av_frame_free(&pool->frames[i]);
> >> + }
> >> +
> >> + av_vaapi_unlock_hardware_context(pool->hardware_context);
> >> +
> >> + return 0;
> >> +}
> >> +
> >> +int av_vaapi_surface_pool_get(AVVAAPISurfacePool *pool, AVFrame *target)
> >> +{
> >> + AVFrame *frame = 0;
> >> + int i, err;
> >> +
> >> + av_vaapi_lock_hardware_context(pool->hardware_context);
> >> +
> >> + for(i = 0; i < FF_ARRAY_ELEMS(pool->frames); i++) {
> >> + if(!pool->frames[i])
> >> + break;
> >> +
> >> + if(av_buffer_get_ref_count(pool->frames[i]->buf[0]) == 1) {
> >> + frame = pool->frames[i];
> >> + break;
> >> + }
> >> + }
> >> +
> >> + if(frame) {
> >> + target->data[3] = frame->data[3];
> >> + target->buf[0] = av_buffer_ref(frame->buf[0]);
> >> + target->buf[1] = av_buffer_ref(frame->buf[1]);
> >> + if(!target->buf[0] || !target->buf[1])
> >> + err = AVERROR(ENOMEM);
> >> + else
> >> + err = 0;
> >> + } else {
> >> + err = AVERROR(ENOMEM);
> >> + }
> >> +
> >> + av_vaapi_unlock_hardware_context(pool->hardware_context);
> >> +
> >> + return err;
> >> +}
> >> +
> >> +int av_vaapi_map_frame(AVFrame *frame, int get)
> >> +{
> >> + AVVAAPISurface *surface = vaapi_get_surface(frame);
> >> + AVVAAPISurfaceConfig *config = vaapi_get_surface_config(frame);
> >> + AVVAAPIHardwareContext *hw_ctx = surface->hardware_context;
> >> + VAImage *image = &surface->image;
> >> + VAStatus vas;
> >> + int i, err;
> >> + void *address;
> >> + // On current Intel drivers, derive gives you memory which is very slow
> >> + // to read (uncached?). It can be better for write-only cases, but for
> >> + // now play it safe and never use derive.
> >> + int derive = 0;
> >
> > Before the patch gets applied, we also should check if we can get in a
> > "GPU memcpy", and whether this codepath can be enabled. If not, there
> > wouldn't be much of a reason to keep it.
>
> Even without it, it has use for the "drawing on frames" case (subtitles?). I haven't studied how that works in libavfilter at all, but I imagine we want the derive case there to avoid a pointless copy there and back to speed up changing only a few pixel values.
>
> I guess it could go for now and be added back if/when someone implements that, though.
>
Then it would have an option. But let's not leave commented code in
there just so it can bitrot.
> ...
> > Looks in general pretty ok to me.
> >
> > There should be allocation functions for structs which don't have one
> > yet, and a clear warning should be added to the doxygen. (Doxygen
> > should also be added.)
>
> If you're happy that this is now plausible, then I will write documentation for the relevant parts.
>
OK, but there's still the unsolved Libav issue, which might dice up
everything again.
> > One nit: I _think_ we usually add a whitespace between statement and
> > "(", e.g. "if (". (Not for function calls or declarations.)
>
> I can sed the spaces in, I guess.
>
> Thanks for the review!
>
> - Mark
>
> _______________________________________________
> ffmpeg-devel mailing list
> ffmpeg-devel at ffmpeg.org
> http://ffmpeg.org/mailman/listinfo/ffmpeg-devel
More information about the ffmpeg-devel
mailing list