On 25/11/13 16:58, wm4 wrote: > 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? >
s/root/video group. lu _______________________________________________ libav-devel mailing list [email protected] https://lists.libav.org/mailman/listinfo/libav-devel
