On Thu, 21 Nov 2013 11:51:03 +0100
Anton Khirnov <[email protected]> wrote:
> ---
> Changelog | 2 +-
> Makefile | 4 +-
> avconv.h | 2 +
> avconv_opt.c | 3 +
> avconv_vaapi.c | 596
> +++++++++++++++++++++++++++++++++++++++++++++++++++++++
> configure | 13 ++
> doc/avconv.texi | 13 ++
> 7 files changed, 631 insertions(+), 2 deletions(-)
> create mode 100644 avconv_vaapi.c
>
> diff --git a/Changelog b/Changelog
> index 15e5ac9..af67ce5 100644
> --- a/Changelog
> +++ b/Changelog
> @@ -48,7 +48,7 @@ version 10:
> - setsar/setdar filters now support variables in ratio expressions
> - dar variable in the scale filter now returns the actual DAR (i.e. a * sar)
> - VP9 decoder
> -- support for decoding through VDPAU in avconv (the -hwaccel option)
> +- support for decoding through VDPAU and VAAPI in avconv (the -hwaccel
> option)
>
>
> version 9:
> diff --git a/Makefile b/Makefile
> index 184aa37..b249cda 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -64,6 +64,8 @@ PROGS-$(CONFIG_AVSERVER) += avserver
> PROGS := $(PROGS-yes:%=%$(EXESUF))
>
> OBJS-avconv = avconv_opt.o avconv_filter.o
> +OBJS-avconv-$(HAVE_VAAPI_DRM) += avconv_vaapi.o
> +OBJS-avconv-$(HAVE_VAAPI_X11) += avconv_vaapi.o
> OBJS-avconv-$(HAVE_VDPAU_X11) += avconv_vdpau.o
>
> TESTTOOLS = audiogen videogen rotozoom tiny_psnr base64
> @@ -129,7 +131,7 @@ endef
> $(foreach D,$(FFLIBS),$(eval $(call DOSUBDIR,lib$(D))))
>
> define DOPROG
> -OBJS-$(1) += $(1).o cmdutils.o $(EXEOBJS) $(OBJS-$(1)-yes)
> +OBJS-$(1) += $(1).o cmdutils.o $(EXEOBJS) $$(sort $$(OBJS-$(1)-yes))
> $(1)$(EXESUF): $$(OBJS-$(1))
> $$(OBJS-$(1)): CFLAGS += $(CFLAGS-$(1))
> $(1)$(EXESUF): LDFLAGS += $(LDFLAGS-$(1))
> diff --git a/avconv.h b/avconv.h
> index c270401..1fd9f73 100644
> --- a/avconv.h
> +++ b/avconv.h
> @@ -52,6 +52,7 @@ enum HWAccelID {
> HWACCEL_NONE = 0,
> HWACCEL_AUTO,
> HWACCEL_VDPAU,
> + HWACCEL_VAAPI,
> };
>
> typedef struct HWAccel {
> @@ -404,5 +405,6 @@ FilterGraph *init_simple_filtergraph(InputStream *ist,
> OutputStream *ost);
> int avconv_parse_options(int argc, char **argv);
>
> int vdpau_init(AVCodecContext *s);
> +int vaapi_init(AVCodecContext *s);
>
> #endif /* AVCONV_H */
> diff --git a/avconv_opt.c b/avconv_opt.c
> index da8c6e7..c4cee74 100644
> --- a/avconv_opt.c
> +++ b/avconv_opt.c
> @@ -57,6 +57,9 @@ const HWAccel hwaccels[] = {
> #if HAVE_VDPAU_X11
> { "vdpau", vdpau_init, HWACCEL_VDPAU, AV_PIX_FMT_VDPAU },
> #endif
> +#if HAVE_VAAPI_DRM || HAVE_VAAPI_X11
> + { "vaapi", vaapi_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI_VLD },
> +#endif
> { 0 },
> };
>
> diff --git a/avconv_vaapi.c b/avconv_vaapi.c
> new file mode 100644
> index 0000000..c6574e2
> --- /dev/null
> +++ b/avconv_vaapi.c
> @@ -0,0 +1,596 @@
> +/*
> + * This file is part of Libav.
> + *
> + * Libav is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU Lesser General Public
> + * License as published by the Free Software Foundation; either
> + * version 2.1 of the License, or (at your option) any later version.
> + *
> + * Libav is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
> + * Lesser General Public License for more details.
> + *
> + * You should have received a copy of the GNU Lesser General Public
> + * License along with Libav; if not, write to the Free Software
> + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
> USA
> + */
> +
> +#include "config.h"
> +
> +#include <stdint.h>
> +
> +#include <va/va.h>
> +
> +#if HAVE_VAAPI_DRM
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <unistd.h>
> +#include <xf86drm.h>
> +#include <sys/stat.h>
> +#include <va/va_drm.h>
> +#endif
> +
> +#if HAVE_VAAPI_X11
> +#include <X11/Xlib.h>
> +#include <va/va_x11.h>
> +#endif
> +
> +#include "libavcodec/avcodec.h"
> +#include "libavcodec/vaapi.h"
> +
> +#include "libavutil/avassert.h"
> +#include "libavutil/buffer.h"
> +#include "libavutil/frame.h"
> +#include "libavutil/imgutils.h"
> +#include "libavutil/mem.h"
> +
> +#include "avconv.h"
> +
> +/* Stuff associated with one VAAPI config/decoder. It is refcounted, one ref
> is
> + * held by each used frame + one by the VAAPIContext as long as this config
> is
> + * being used for decoding */
> +typedef struct VAAPIConfig {
> + AVBufferRef *ctx_buf;
> + struct VAAPIContext *ctx;
> +
> + VAConfigID config_id;
> + VAContextID context_id;
> +
> + VASurfaceID *surfaces;
> + uint8_t *surface_used;
> + int nb_surfaces;
> +} VAAPIConfig;
> +
> +/* Global stuff associated with a VAAPI display device + some temp
> variables. It
> + * is refcounted, one reference is held by each config, one by each
> VAAPIImage +
> + * one by itself (released on uninit). */
> +typedef struct VAAPIContext {
> + AVBufferRef *self;
> +#if HAVE_VAAPI_DRM
> + int drm_fd;
> +#endif
> +#if HAVE_VAAPI_X11
> + Display *dpy;
> +#endif
> +
> + VADisplay display;
> +
> + VAAPIConfig *cur_config;
> + AVBufferRef *cur_config_buf;
> +
> + VAImageFormat img_fmt;
> + enum AVPixelFormat pix_fmt;
> + AVFrame *tmp_frame;
> +} VAAPIContext;
> +
> +/* A wrapper around a VAAPI surface */
> +typedef struct VAAPIFrame {
> + VADisplay display;
> + AVBufferRef *config;
> + uint8_t *used;
> +} VAAPIFrame;
> +
> +/* A wrapper around a VAImage for retrieving the data */
> +typedef struct VAAPIImage {
> + VAAPIContext *ctx;
> + AVBufferRef *ctx_buf;
> +
> + VAImage image;
> +} VAAPIImage;
> +
> +static const int vaapi_formats[][2] = {
> + { VA_FOURCC_YV12, AV_PIX_FMT_YUV420P },
> + { VA_FOURCC_NV12, AV_PIX_FMT_NV12 },
> +};
> +
> +static void vaapi_free_image(void *opaque, uint8_t *data)
> +{
> + VAAPIImage *img = opaque;
> +
> + if (img->image.buf != VA_INVALID_ID)
> + vaUnmapBuffer(img->ctx->display, img->image.buf);
> + if (img->image.image_id != VA_INVALID_ID)
> + vaDestroyImage(img->ctx->display, img->image.image_id);
> + av_buffer_unref(&img->ctx_buf);
> + av_freep(&img);
> +}
> +
> +static int vaapi_retrieve_data(AVCodecContext *s, AVFrame *frame)
> +{
> + VASurfaceID surface = (VASurfaceID)(uintptr_t)frame->data[3];
> + InputStream *ist = s->opaque;
> + VAAPIContext *ctx = ist->hwaccel_ctx;
> + VAAPIImage *img;
> + VAStatus err;
> + uint8_t *data;
> + int i, ret;
> +
> + img = av_mallocz(sizeof(*img));
> + if (!img)
> + return AVERROR(ENOMEM);
> +
> + img->image.buf = VA_INVALID_ID;
> + img->image.image_id = VA_INVALID_ID;
> +
> + img->ctx_buf = av_buffer_ref(ctx->self);
> + if (!img->ctx_buf) {
> + av_freep(&img);
> + return AVERROR(ENOMEM);
> + }
> + img->ctx = ctx;
> +
> + err = vaCreateImage(ctx->display, &ctx->img_fmt,
> + frame->width, frame->height, &img->image);
> + if (err != VA_STATUS_SUCCESS) {
> + vaapi_free_image(img, NULL);
> + av_log(NULL, AV_LOG_ERROR, "Error creating an image: %s\n",
> + vaErrorStr(err));
> + return AVERROR_UNKNOWN;
> + }
> +
> + /* We do not use vaDeriveImage, because even when it is implemented, the
> + * access to the image data is usually very slow */
> + err = vaGetImage(ctx->display, surface, 0, 0, frame->width,
> frame->height,
> + img->image.image_id);
> + if (err != VA_STATUS_SUCCESS) {
> + vaapi_free_image(img, NULL);
> + av_log(NULL, AV_LOG_ERROR, "Error getting an image: %s\n",
> + vaErrorStr(err));
> + return AVERROR_UNKNOWN;
> + }
> +
> + err = vaMapBuffer(ctx->display, img->image.buf, (void**)&data);
> + if (err != VA_STATUS_SUCCESS) {
> + vaapi_free_image(img, NULL);
> + av_log(NULL, AV_LOG_ERROR, "Error mapping the image buffer: %s\n",
> + vaErrorStr(err));
> + return AVERROR_UNKNOWN;
> + }
> +
> + ctx->tmp_frame->buf[0] = av_buffer_create(data, img->image.data_size,
> + vaapi_free_image, img, 0);
> + if (!ctx->tmp_frame->buf[0]) {
> + vaapi_free_image(img, NULL);
> + return AVERROR(ENOMEM);
> + }
> +
> + for (i = 0; i < img->image.num_planes; i++) {
> + ctx->tmp_frame->data[i] = data + img->image.offsets[i];
> + ctx->tmp_frame->linesize[i] = img->image.pitches[i];
> + }
> + ctx->tmp_frame->format = ctx->pix_fmt;
> + ctx->tmp_frame->width = frame->width;
> + ctx->tmp_frame->height = frame->height;
> +
> + ret = av_frame_copy_props(ctx->tmp_frame, frame);
> + if (ret < 0) {
> + av_frame_unref(ctx->tmp_frame);
> + return ret;
> + }
> +
> + av_frame_unref(frame);
> + av_frame_move_ref(frame, ctx->tmp_frame);
> +
> + return 0;
> +
> + if (frame->format == AV_PIX_FMT_YUV420P)
> + FFSWAP(uint8_t*, frame->data[1], frame->data[2]);
> +
> + return ret;
> +}
Dead code? It looks like it might be needed too. While we're at it,
maybe it should check for the YV12 fourcc instead, in case someone
wants to add I420 to the lookup table later. But probably not important.
> +
> +static void vaapi_release_buffer(void *opaque, uint8_t *data)
> +{
> + VAAPIFrame *priv = opaque;
> +
> + *priv->used = 0;
> + av_buffer_unref(&priv->config);
> + av_freep(&priv);
> +}
> +
> +static int vaapi_get_buffer(AVCodecContext *s, AVFrame *frame, int flags)
> +{
> + InputStream *ist = s->opaque;
> + VAAPIContext *ctx = ist->hwaccel_ctx;
> + VAAPIConfig *config = ctx->cur_config;
> + VAAPIFrame *priv = NULL;
> + int i;
> +
> + av_assert0(frame->format == AV_PIX_FMT_VAAPI_VLD);
> +
> + for (i = 0; i < config->nb_surfaces; i++)
> + if (!config->surface_used[i])
> + break;
> + if (i == config->nb_surfaces) {
> + av_log(NULL, AV_LOG_ERROR, "No free surfaces left.\n");
> + return AVERROR(ENOMEM);
> + }
> +
> + priv = av_mallocz(sizeof(*priv));
> + if (!priv)
> + return AVERROR(ENOMEM);
> +
> + priv->used = &config->surface_used[i];
> + priv->display = ctx->display;
> + priv->config = av_buffer_ref(ctx->cur_config_buf);
> + if (!priv->config)
> + goto fail;
> +
> + frame->buf[0] = av_buffer_create((uint8_t*)&config->surfaces[i],
> + sizeof(*config->surfaces),
> + vaapi_release_buffer, priv,
> + AV_BUFFER_FLAG_READONLY);
> + if (!frame->buf[0])
> + return AVERROR(ENOMEM);
> +
> + frame->opaque = priv;
> + frame->data[3] = (uint8_t*)(uintptr_t)config->surfaces[i];
> + config->surface_used[i] = 1;
> +
> + return 0;
> +fail:
> + if (priv)
> + av_buffer_unref(&priv->config);
> + av_freep(&priv);
> + return AVERROR(ENOMEM);
> +}
> +
> +static void vaapi_free_config(void *opaque, uint8_t *data)
> +{
> + VAAPIConfig *config = opaque;
> +
> + vaDestroySurfaces(config->ctx->display, config->surfaces,
> config->nb_surfaces);
> + av_freep(&config->surfaces);
> + av_freep(&config->surface_used);
> +
> + if (config->context_id != VA_INVALID_ID)
> + vaDestroyContext(config->ctx->display, config->context_id);
> +
> + if (config->config_id != VA_INVALID_ID)
> + vaDestroyConfig(config->ctx->display, config->config_id);
> +
> + av_buffer_unref(&config->ctx_buf);
> + av_freep(&config);
> +}
> +
> +static int vaapi_create_config(AVCodecContext *s)
> +{
> + InputStream *ist = s->opaque;
> + VAAPIContext *ctx = ist->hwaccel_ctx;
> + int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE :
> AV_LOG_ERROR;
> + VAAPIConfig *config;
> + VAProfile profile;
> + VAStatus err;
> + int ret;
> +
> + ret = av_vaapi_get_profile(s, &profile);
> + if (ret < 0) {
> + av_log(NULL, loglevel, "No known VAAPI decoder profile for input "
> + "stream #%d:%d.\n", ist->file_index, ist->st->index);
> + return AVERROR(EINVAL);
> + }
Shouldn't it check whether the profile is reported as supported? I'm
not sure whether just passing it to vaCreateContext() is such a good
idea.
Also, if the profile is constrained baseline, but the decoder doesn't
support it, it should fall back to one of the other h264 profiles.
> +
> + /* setup a refcounted buffer for the current config */
> + config = av_mallocz(sizeof(*config));
> + if (!config)
> + return AVERROR(ENOMEM);
> + ctx->cur_config_buf = av_buffer_create((uint8_t*)config,
> + sizeof(*config),
> + vaapi_free_config, config,
> + AV_BUFFER_FLAG_READONLY);
> + if (!ctx->cur_config_buf) {
> + av_freep(&config);
> + return AVERROR(ENOMEM);
> + }
> +
> + config->ctx_buf = av_buffer_ref(ctx->self);
> + if (!config->ctx_buf)
> + goto fail;
> + config->ctx = ctx;
> + config->config_id = VA_INVALID_ID;
> + config->context_id = VA_INVALID_ID;
> +
> + /* create the surfaces */
> + config->nb_surfaces = 16;
> + if (s->active_thread_type == FF_THREAD_FRAME)
> + config->nb_surfaces += s->thread_count;
This seems awfully specific. By the way, is it even a good idea to
enable MT with hwaccel? Or does it just waste GPU memory and add
complexity?
> + config->surfaces = av_malloc_array (config->nb_surfaces,
> sizeof(*config->surfaces));
> + config->surface_used = av_mallocz_array(config->nb_surfaces,
> sizeof(*config->surface_used));
> + if (!config->surfaces || !config->surface_used) {
> + av_freep(&config->surfaces);
> + av_freep(&config->surface_used);
> + goto fail;
> + }
> +
> + err = vaCreateSurfaces(ctx->display, VA_RT_FORMAT_YUV420,
> + s->coded_width, s->coded_height,
> + config->surfaces, config->nb_surfaces, NULL, 0);
> + if (err != VA_STATUS_SUCCESS) {
> + config->surfaces[0] = VA_INVALID_ID;
> + av_log(NULL, loglevel, "Error creating surfaces: %s\n",
> + vaErrorStr(err));
> + goto fail;
> + }
> +
> + /* create the decoder configuration */
> + err = vaCreateConfig(ctx->display, profile, VAEntrypointVLD,
> + NULL, 0, &config->config_id);
> + if (err != VA_STATUS_SUCCESS) {
> + av_log(NULL, loglevel, "Error creating configuration: %s\n",
> + vaErrorStr(err));
> + goto fail;
> + }
> +
> + /* create the decoder context */
> + err = vaCreateContext(ctx->display, config->config_id,
> + s->coded_width, s->coded_height, 0,
> + config->surfaces, config->nb_surfaces,
> + &config->context_id);
> + if (err != VA_STATUS_SUCCESS) {
> + av_log(NULL, loglevel, "Error creating the decoding context: %s\n",
> + vaErrorStr(err));
> + goto fail;
> + }
> +
> + ctx->cur_config = config;
> +
> + return 0;
> +fail:
> + av_buffer_unref(&ctx->cur_config_buf);
> + return AVERROR_UNKNOWN;
> +}
> +
> +static void vaapi_uninit(AVCodecContext *s)
> +{
> + InputStream *ist = s->opaque;
> + VAAPIContext *ctx = ist->hwaccel_ctx;
> +
> + av_buffer_unref(&ctx->cur_config_buf);
> + ctx->cur_config = NULL;
> +
> + av_freep(&s->hwaccel_context);
> + ist->hwaccel_ctx = NULL;
> +
> + av_buffer_unref(&ctx->self);
> +}
> +
> +static int pick_format(InputStream *ist, VAAPIContext *ctx)
> +{
> + int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE :
> AV_LOG_ERROR;
> + VAImageFormat *formats = NULL;
> + VAStatus err;
> + int nb_formats, i, j;
> +
> + nb_formats = vaMaxNumImageFormats(ctx->display);
> + if (!nb_formats) {
> + av_log(NULL, loglevel, "No image formats supported.\n");
> + return AVERROR(EINVAL);
> + }
> +
> + formats = av_mallocz_array(nb_formats, sizeof(*formats));
> + if (!formats)
> + return AVERROR(ENOMEM);
> +
> + err = vaQueryImageFormats(ctx->display, formats, &nb_formats);
> + if (err != VA_STATUS_SUCCESS) {
> + av_log(NULL, loglevel, "Error querying image formats: %s\n",
> + vaErrorStr(err));
> + goto fail;
> + }
> +
> + for (i = 0; i < FF_ARRAY_ELEMS(vaapi_formats); i++)
> + for (j = 0; j < nb_formats; j++)
> + if (vaapi_formats[i][0] == formats[j].fourcc) {
> + ctx->img_fmt = formats[j];
> + ctx->pix_fmt = vaapi_formats[i][1];
> + av_freep(&formats);
> + return 0;
> + }
> +
> +fail:
> + av_freep(&formats);
> + return AVERROR(EINVAL);
> +}
> +
> +#if HAVE_VAAPI_DRM
> +static void vaapi_open_drm(InputStream *ist, VAAPIContext *ctx)
> +{
> + if (!ist->hwaccel_device)
> + return;
> +
> + ctx->drm_fd = drmOpen(ist->hwaccel_device, NULL);
> + if (ctx->drm_fd == -1)
> + ctx->drm_fd = open(ist->hwaccel_device, O_RDONLY);
> +
> + if (ctx->drm_fd == -1) {
> + av_log(NULL, AV_LOG_VERBOSE, "Cannot open DRM device %s: %s.\n",
> + ist->hwaccel_device, strerror(errno));
> + return;
> + }
> +
> + ctx->display = vaGetDisplayDRM(ctx->drm_fd);
> + if (!ctx->display) {
> + av_log(NULL, AV_LOG_VERBOSE, "Error getting a DRM VAAPI display.\n");
> + drmClose(ctx->drm_fd);
> + return;
> + }
> +
> + av_log(NULL, AV_LOG_VERBOSE, "Successfully opened a VAAPI display on DRM
> "
> + "device %s.\n", ist->hwaccel_device);
> +}
> +#endif
> +
> +#if HAVE_VAAPI_X11
> +static void vaapi_open_x11(InputStream *ist, VAAPIContext *ctx)
> +{
> + const char *display;
> +
> + ctx->dpy = XOpenDisplay(ist->hwaccel_device);
> + if (!ctx->dpy) {
> + av_log(NULL, AV_LOG_VERBOSE, "Cannot open the X11 display %s.\n",
> + XDisplayName(ist->hwaccel_device));
> + return;
> + }
> + display = XDisplayString(ctx->dpy);
> +
> + ctx->display = vaGetDisplay(ctx->dpy);
> + if (!ctx->display) {
> + av_log(NULL, AV_LOG_VERBOSE, "Error getting an X11 VAAPI
> display.\n");
> + XCloseDisplay(ctx->dpy);
> + return;
> + }
> +
> + av_log(NULL, AV_LOG_VERBOSE, "Successfully opened a VAAPI display on X11
> "
> + "display %s.\n", display);
> +}
> +#endif
> +
> +static void vaapi_free_context(void *opaque, uint8_t *data)
> +{
> + VAAPIContext *ctx = opaque;
> +
> +#if HAVE_VAAPI_DRM
> + close(ctx->drm_fd);
> +#endif
> +
> +#if HAVE_VAAPI_X11
> + if (ctx->dpy)
> + XCloseDisplay(ctx->dpy);
> +#endif
> +
> + if (ctx->display)
> + vaTerminate(ctx->display);
Maybe the X display should be closed after the vaTerminate call, who
knows if libva still accesses the X display here.
> +
> +
> + av_frame_free(&ctx->tmp_frame);
> + av_freep(&ctx);
> +}
> +
> +static int vaapi_create_context(AVCodecContext *s)
> +{
> + InputStream *ist = s->opaque;
> + int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE :
> AV_LOG_ERROR;
> + AVVAAPIContext *vaapi_ctx;
> + VAAPIContext *ctx;
> + VAStatus err;
> + int ret, ver_minor, ver_major;
> +
> + ctx = av_mallocz(sizeof(*ctx));
> + if (!ctx)
> + return AVERROR(ENOMEM);
> +
> + ctx->self = av_buffer_create((uint8_t*)ctx, sizeof(*ctx),
> + vaapi_free_context, ctx,
> + AV_BUFFER_FLAG_READONLY);
> + if (!ctx->self) {
> + av_freep(&ctx);
> + return AVERROR(ENOMEM);
> + }
> +
> + ctx->tmp_frame = av_frame_alloc();
> + if (!ctx->tmp_frame)
> + goto fail;
> +
> +#if HAVE_VAAPI_DRM
> + vaapi_open_drm(ist, ctx);
> +#endif
> +#if HAVE_VAAPI_X11
> + if (!ctx->display)
> + vaapi_open_x11(ist, ctx);
> +#endif
> +
> + if (!ctx->display) {
> + av_log(NULL, loglevel, "Could not open a VAAPI display.\n");
> + goto fail;
> + }
> +
> + err = vaInitialize(ctx->display, &ver_major, &ver_minor);
> + if (err != VA_STATUS_SUCCESS) {
> + av_log(NULL, loglevel, "Error initializing VAAPI: %s\n",
> + vaErrorStr(err));
> + goto fail;
> + }
> +
> + ret = pick_format(ist, ctx);
> + if (ret < 0) {
> + av_log(NULL, loglevel, "No supported image format found.\n");
> + goto fail;
> + }
> +
> + vaapi_ctx = av_vaapi_alloc_context();
> + if (!vaapi_ctx)
> + goto fail;
> + vaapi_ctx->display = ctx->display;
> +
> + s->hwaccel_context = vaapi_ctx;
> +
> + ist->hwaccel_ctx = ctx;
> + ist->hwaccel_uninit = vaapi_uninit;
> +
> + av_log(NULL, AV_LOG_VERBOSE, "Using VAAPI version %d.%d -- %s -- "
> + "to decode input stream #%d:%d.\n", ver_major, ver_minor,
> + vaQueryVendorString(ctx->display), ist->file_index,
> ist->st->index);
> +
> + return 0;
> +
> +fail:
> + av_log(NULL, loglevel, "VAAPI init failed for stream #%d:%d.\n",
> + ist->file_index, ist->st->index);
> + vaapi_uninit(s);
> + return AVERROR(EINVAL);
> +}
> +
> +int vaapi_init(AVCodecContext *s)
> +{
> + InputStream *ist = s->opaque;
> + int loglevel = (ist->hwaccel_id == HWACCEL_AUTO) ? AV_LOG_VERBOSE :
> AV_LOG_ERROR;
> + AVVAAPIContext *vaapi_ctx;
> + VAAPIContext *ctx;
> + int ret;
> +
> + if (!ist->hwaccel_ctx) {
> + ret = vaapi_create_context(s);
> + if (ret < 0)
> + return ret;
> + }
> + ctx = ist->hwaccel_ctx;
> + vaapi_ctx = s->hwaccel_context;
> +
> + av_buffer_unref(&ctx->cur_config_buf);
> + ctx->cur_config = NULL;
> +
> + ret = vaapi_create_config(s);
> + if (ret < 0) {
> + av_log(NULL, loglevel, "Error initializing a VAAPI
> configuration.\n");
> + return AVERROR_UNKNOWN;
> + }
> +
> + vaapi_ctx->config_id = ctx->cur_config->config_id;
> + vaapi_ctx->context_id = ctx->cur_config->context_id;
> +
> + ist->hwaccel_get_buffer = vaapi_get_buffer;
> + ist->hwaccel_retrieve_data = vaapi_retrieve_data;
> +
> + return 0;
> +}
> diff --git a/configure b/configure
> index b23d5e7..c5b6761 100755
> --- a/configure
> +++ b/configure
> @@ -1367,6 +1367,8 @@ HAVE_LIST="
> threads
> unistd_h
> usleep
> + vaapi_drm
> + vaapi_x11
> vdpau_x11
> vfp_args
> VirtualAlloc
> @@ -3915,6 +3917,15 @@ require Xext X11/extensions/XShm.h XShmCreateImage
> -lXext &&
> require Xfixes X11/extensions/Xfixes.h XFixesGetCursorImage -lXfixes &&
> { enabled xlib || die "ERROR: Xlib not found"; }
>
> +enabled vaapi && enabled unistd_h &&
> + check_pkg_config libdrm xf86drm.h drmOpen &&
> + check_lib2 "va/va.h va/va_drm.h" vaGetDisplayDRM -lva -lva-drm &&
> + enable vaapi_drm
> +
> +enabled vaapi && enabled xlib &&
> + check_lib2 "va/va.h va/va_x11.h" vaGetDisplay -lva -lva-x11 &&
> + enable vaapi_x11
> +
> enabled vdpau &&
> check_cpp_condition vdpau/vdpau.h "defined
> VDP_DECODER_PROFILE_MPEG4_PART2_ASP" ||
> disable vdpau
> @@ -4266,6 +4277,8 @@ TARGET_PATH=$target_path
> TARGET_SAMPLES=${target_samples:-\$(SAMPLES)}
> LIBS-avplay=$sdl_libs
> CFLAGS-avplay=$sdl_cflags
> +LIBS-avconv=$libdrm_libs
> +CFLAGS-avconv=$libdrm_cflags
> ZLIB=$($ldflags_filter -lz)
> LIB_INSTALL_EXTRA_CMD=$LIB_INSTALL_EXTRA_CMD
> EXTRALIBS=$extralibs
> diff --git a/doc/avconv.texi b/doc/avconv.texi
> index 972d13f..38ed2ce 100644
> --- a/doc/avconv.texi
> +++ b/doc/avconv.texi
> @@ -565,6 +565,10 @@ Automatically select the hardware acceleration method.
>
> @item vdpau
> Use VDPAU (Video Decode and Presentation API for Unix) hardware acceleration.
> +
> +@item vaapi
> +Use VA API (Video Acceleration API) hardware acceleration. X11 and raw DRM
> +access are supported.
> @end table
>
> This option has no effect if the selected hwaccel is not available or not
> @@ -587,6 +591,15 @@ method chosen.
> @item vdpau
> For VDPAU, this option specifies the X11 display/screen to use. If this
> option
> is not specified, the value of the @var{DISPLAY} environment variable is used
> +
> +@item vaapi
> +For VAAPI, this option specifies either the X11 display/screen to use (for
> X11
> +access), the DRM driver name or the DRM device node (for DRM access). If this
> +option is not specified, the @var{DISPLAY} environment variable is used to
> +determine an X11 display to use.
> +
> +Note that raw DRM access allows using VAAPI acceleration without an X server,
> +but this requires root privileges.
Eh? Does this really have a use in this case? Who would use hw decoding
as root?
> @end table
> @end table
>
_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel