Re: [FFmpeg-devel] [PATCH v3 2/5] ffmpeg: initialisation code for VAAPI, hwaccel helper
On Mon, 18 Jan 2016 22:50:50 + Mark Thompsonwrote: > --- > Makefile | 1 + > ffmpeg.c | 5 + > ffmpeg.h | 5 + > ffmpeg_opt.c | 14 ++ > ffmpeg_vaapi.c | 622 > + > 5 files changed, 647 insertions(+) > create mode 100644 ffmpeg_vaapi.c > > diff --git a/Makefile b/Makefile > index 7836a20..be1d2ca 100644 > --- a/Makefile > +++ b/Makefile > @@ -36,6 +36,7 @@ OBJS-ffmpeg-$(CONFIG_VDA) += ffmpeg_videotoolbox.o > endif > OBJS-ffmpeg-$(CONFIG_VIDEOTOOLBOX) += ffmpeg_videotoolbox.o > OBJS-ffmpeg-$(CONFIG_LIBMFX) += ffmpeg_qsv.o > +OBJS-ffmpeg-$(CONFIG_VAAPI) += ffmpeg_vaapi.o > OBJS-ffserver += ffserver_config.o > > TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64 > diff --git a/ffmpeg.c b/ffmpeg.c > index 1f4277c..e76879a 100644 > --- a/ffmpeg.c > +++ b/ffmpeg.c > @@ -2603,6 +2603,11 @@ static int init_output_stream(OutputStream *ost, char > *error, int error_len) > !av_dict_get(ost->encoder_opts, "ab", NULL, 0)) > av_dict_set(>encoder_opts, "b", "128000", 0); > > +#if CONFIG_VAAPI > +if(ost->enc->type == AVMEDIA_TYPE_VIDEO) > +vaapi_hardware_set_options(>encoder_opts); > +#endif > + > if ((ret = avcodec_open2(ost->enc_ctx, codec, >encoder_opts)) < > 0) { > if (ret == AVERROR_EXPERIMENTAL) > abort_codec_experimental(codec, 1); > diff --git a/ffmpeg.h b/ffmpeg.h > index 20322b0..2134213 100644 > --- a/ffmpeg.h > +++ b/ffmpeg.h > @@ -65,6 +65,7 @@ enum HWAccelID { > HWACCEL_VDA, > HWACCEL_VIDEOTOOLBOX, > HWACCEL_QSV, > +HWACCEL_VAAPI, > }; > > typedef struct HWAccel { > @@ -577,5 +578,9 @@ int vda_init(AVCodecContext *s); > int videotoolbox_init(AVCodecContext *s); > int qsv_init(AVCodecContext *s); > int qsv_transcode_init(OutputStream *ost); > +int vaapi_decode_init(AVCodecContext *s); > + > +int vaapi_hardware_init(const char *device); > +int vaapi_hardware_set_options(AVDictionary **dict); > > #endif /* FFMPEG_H */ > diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c > index 9b341cf..47ac467 100644 > --- a/ffmpeg_opt.c > +++ b/ffmpeg_opt.c > @@ -82,6 +82,9 @@ const HWAccel hwaccels[] = { > #if CONFIG_LIBMFX > { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV }, > #endif > +#if CONFIG_VAAPI > +{ "vaapi", vaapi_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI }, > +#endif > { 0 }, > }; > > @@ -442,6 +445,13 @@ static int opt_sdp_file(void *optctx, const char *opt, > const char *arg) > return 0; > } > > +static int opt_vaapi(void *optctx, const char *opt, const char *arg) > +{ > +if(vaapi_hardware_init(arg)) > +exit_program(1); > +return 0; > +} > + > /** > * Parse a metadata specifier passed as 'arg' parameter. > * @param arg metadata string to parse > @@ -3438,5 +3448,9 @@ const OptionDef options[] = { > { "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { > .off = OFFSET(data_disable) }, > "disable data" }, > > +#if CONFIG_VAAPI > +{ "vaapi", HAS_ARG, { .func_arg = opt_vaapi }, "set VAAPI hardware > context" }, > +#endif > + > { NULL, }, > }; > diff --git a/ffmpeg_vaapi.c b/ffmpeg_vaapi.c > new file mode 100644 > index 000..e04532c > --- /dev/null > +++ b/ffmpeg_vaapi.c > @@ -0,0 +1,622 @@ > +/* > + * VAAPI helper for hardware-accelerated decoding. > + * > + * 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 > +#include > +#include > + > +#include "ffmpeg.h" > + > +#include "libavutil/avassert.h" > +#include "libavutil/avconfig.h" > +#include "libavutil/buffer.h" > +#include "libavutil/frame.h" > +#include "libavutil/imgutils.h" > +#include "libavutil/opt.h" > +#include "libavutil/pixfmt.h" > +#include "libavutil/thread.h" > +#include "libavutil/vaapi.h" > + > +#include "libavcodec/vaapi.h" > + > +#include > +#include > + > + > +static AVClass vaapi_class = { > +.class_name = "VAAPI/driver", > +.item_name = av_default_item_name, > +.version= LIBAVUTIL_VERSION_INT, > +}; > + > + > +#define DEFAULT_SURFACES 20 > + >
Re: [FFmpeg-devel] [PATCH v3 2/5] ffmpeg: initialisation code for VAAPI, hwaccel helper
On Tue, 19 Jan 2016 13:54:25 + Mark Thompsonwrote: > >> +surface = (AVVAAPISurface*)input_frame->buf[0]->data; > > > > I haven't paid attention to this before. Shouldn't this be a vaapi > > surface ID according to how libavcodec works? > > data[3] is the VAAPI surface ID, as used in libavcodec. > > Here we need to carry more information around in order to have enough context > to map/unmap the surface. Still slightly questionable. Does this mean the user can't create surfaces and pass them to an API which happens to expect this set? Also, it would be cleaner to set this on a data pointer too. For example AVFrame.data[1]. (In fact, it would be pretty sane to do it this way. This also fulfills the AVFrame "rule" that the memory referenced by data pointers should be covered by AVFrame.buf. We even thought about doing this in an uniform way across all hwaccels, so that every hwaccel would use the same struct type.) > >> +av_log(ctx, AV_LOG_DEBUG, "Retrieve data from surface %#x (format > >> %#x).\n", > >> + surface->id, output->av_format); > >> + > >> +av_vaapi_lock_hardware_context(ctx->hardware_context); > >> + > >> +if(output->av_format == AV_PIX_FMT_VAAPI) { > >> +copying = 0; > >> +av_log(ctx, AV_LOG_VERBOSE, "Surface %#x retrieved without > >> copy.\n", > >> + surface->id); > > > > I'm not sure if this (and the one below) deserves a log message, and at > > a verbose level at that. If you really want this, a trace level might be > > better. > > This was mainly so that at -v 55 I could see what was going on without being > totally spammed (well, several lines per frame). > > I'll demote these (and others in the codecs which are saying the same thing). In general, I'm not very fond of all these log calls (they just make the code harder to read once you're done with the implementation), but I'll leave this to you to decide. (Or maybe others have opinions.) > >> + > >> +} else { > >> +err = ff_vaapi_map_surface(surface, 1); > >> +if(err) { > >> +av_log(ctx, AV_LOG_ERROR, "Failed to map surface %#x.", > >> + surface->id); > >> +goto fail; > >> +} > >> + > >> +copying = 1; > >> +av_log(ctx, AV_LOG_VERBOSE, "Surface %#x mapped: image %#x data > >> %p.\n", > >> + surface->id, surface->image.image_id, > >> surface->mapped_address); > >> +} > >> + > >> +// The actual frame need not fill the surface. > >> +av_assert0(input_frame->width <= output->width); > >> +av_assert0(input_frame->height <= output->height); > >> + > >> +output_frame = >output_frame; > >> +output_frame->width = input_frame->width; > >> +output_frame->height = input_frame->height; > >> +output_frame->format = output->av_format; > >> + > >> +if(copying) { > >> +err = av_frame_get_buffer(output_frame, 32); > >> +if(err < 0) { > >> +av_log(ctx, AV_LOG_ERROR, "Failed to get output buffer: %d > >> (%s).\n", > >> + err, av_err2str(err)); > >> +goto fail_unmap; > >> +} > >> + > >> +err = ff_vaapi_copy_from_surface(output_frame, surface); > >> +if(err < 0) { > >> +av_log(ctx, AV_LOG_ERROR, "Failed to copy frame data: %d > >> (%s).\n", > >> + err, av_err2str(err)); > >> +goto fail_unmap; > >> +} > >> + > >> +} else { > >> +// Just copy the hidden ID field. > >> +output_frame->data[3] = input_frame->data[3]; > >> +} > >> + > >> +err = av_frame_copy_props(output_frame, input_frame); > >> +if(err < 0) { > >> +av_log(ctx, AV_LOG_ERROR, "Failed to copy frame props: %d > >> (%s).\n", > >> + err, av_err2str(err)); > >> +goto fail_unmap; > >> +} > >> + > >> +av_frame_unref(input_frame); > >> +av_frame_move_ref(input_frame, output_frame); > >> + > >> + fail_unmap: > >> +if(copying) > >> +ff_vaapi_unmap_surface(surface, 0); > >> + fail: > >> +av_vaapi_unlock_hardware_context(ctx->hardware_context); > >> +return err; > >> +} > > > > This whole thing could be a utility function. (Libav was planning to do > > this.) > > Unsure, I'll think about it along with AVFrame redesign. If nothing else, > the map/copy/unmap could be abstracted out. > > >> + > >> +static const struct { > >> +VAProfile from; > >> +VAProfile to; > >> +} vaapi_profile_compatibility[] = { > >> +#define FT(f, t) { VAProfile ## f, VAProfile ## t } > >> +FT(MPEG2Simple, MPEG2Main ), > >> +FT(H263Baseline, MPEG4AdvancedSimple), > >> +FT(MPEG4Simple, MPEG4AdvancedSimple), > >> +FT(MPEG4AdvancedSimple, MPEG4Main ), > >> +FT(H264ConstrainedBaseline, H264Baseline), > >> +FT(H264Baseline,H264Main), // (Not quite true.) > >> +FT(H264Main,
Re: [FFmpeg-devel] [PATCH v3 2/5] ffmpeg: initialisation code for VAAPI, hwaccel helper
On 19/01/16 12:16, wm4 wrote: > On Mon, 18 Jan 2016 22:50:50 + > Mark Thompsonwrote: > >> --- >> Makefile | 1 + >> ffmpeg.c | 5 + >> ffmpeg.h | 5 + >> ffmpeg_opt.c | 14 ++ >> ffmpeg_vaapi.c | 622 >> + >> 5 files changed, 647 insertions(+) >> create mode 100644 ffmpeg_vaapi.c >> >> diff --git a/Makefile b/Makefile >> index 7836a20..be1d2ca 100644 >> --- a/Makefile >> +++ b/Makefile >> @@ -36,6 +36,7 @@ OBJS-ffmpeg-$(CONFIG_VDA) += ffmpeg_videotoolbox.o >> endif >> OBJS-ffmpeg-$(CONFIG_VIDEOTOOLBOX) += ffmpeg_videotoolbox.o >> OBJS-ffmpeg-$(CONFIG_LIBMFX) += ffmpeg_qsv.o >> +OBJS-ffmpeg-$(CONFIG_VAAPI) += ffmpeg_vaapi.o >> OBJS-ffserver += ffserver_config.o >> >> TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64 >> diff --git a/ffmpeg.c b/ffmpeg.c >> index 1f4277c..e76879a 100644 >> --- a/ffmpeg.c >> +++ b/ffmpeg.c >> @@ -2603,6 +2603,11 @@ static int init_output_stream(OutputStream *ost, char >> *error, int error_len) >> !av_dict_get(ost->encoder_opts, "ab", NULL, 0)) >> av_dict_set(>encoder_opts, "b", "128000", 0); >> >> +#if CONFIG_VAAPI >> +if(ost->enc->type == AVMEDIA_TYPE_VIDEO) >> +vaapi_hardware_set_options(>encoder_opts); >> +#endif >> + >> if ((ret = avcodec_open2(ost->enc_ctx, codec, >encoder_opts)) >> < 0) { >> if (ret == AVERROR_EXPERIMENTAL) >> abort_codec_experimental(codec, 1); >> diff --git a/ffmpeg.h b/ffmpeg.h >> index 20322b0..2134213 100644 >> --- a/ffmpeg.h >> +++ b/ffmpeg.h >> @@ -65,6 +65,7 @@ enum HWAccelID { >> HWACCEL_VDA, >> HWACCEL_VIDEOTOOLBOX, >> HWACCEL_QSV, >> +HWACCEL_VAAPI, >> }; >> >> typedef struct HWAccel { >> @@ -577,5 +578,9 @@ int vda_init(AVCodecContext *s); >> int videotoolbox_init(AVCodecContext *s); >> int qsv_init(AVCodecContext *s); >> int qsv_transcode_init(OutputStream *ost); >> +int vaapi_decode_init(AVCodecContext *s); >> + >> +int vaapi_hardware_init(const char *device); >> +int vaapi_hardware_set_options(AVDictionary **dict); >> >> #endif /* FFMPEG_H */ >> diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c >> index 9b341cf..47ac467 100644 >> --- a/ffmpeg_opt.c >> +++ b/ffmpeg_opt.c >> @@ -82,6 +82,9 @@ const HWAccel hwaccels[] = { >> #if CONFIG_LIBMFX >> { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV }, >> #endif >> +#if CONFIG_VAAPI >> +{ "vaapi", vaapi_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI }, >> +#endif >> { 0 }, >> }; >> >> @@ -442,6 +445,13 @@ static int opt_sdp_file(void *optctx, const char *opt, >> const char *arg) >> return 0; >> } >> >> +static int opt_vaapi(void *optctx, const char *opt, const char *arg) >> +{ >> +if(vaapi_hardware_init(arg)) >> +exit_program(1); >> +return 0; >> +} >> + >> /** >> * Parse a metadata specifier passed as 'arg' parameter. >> * @param arg metadata string to parse >> @@ -3438,5 +3448,9 @@ const OptionDef options[] = { >> { "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { >> .off = OFFSET(data_disable) }, >> "disable data" }, >> >> +#if CONFIG_VAAPI >> +{ "vaapi", HAS_ARG, { .func_arg = opt_vaapi }, "set VAAPI hardware >> context" }, >> +#endif >> + >> { NULL, }, >> }; >> diff --git a/ffmpeg_vaapi.c b/ffmpeg_vaapi.c >> new file mode 100644 >> index 000..e04532c >> --- /dev/null >> +++ b/ffmpeg_vaapi.c >> @@ -0,0 +1,622 @@ >> +/* >> + * VAAPI helper for hardware-accelerated decoding. >> + * >> + * 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 >> +#include >> +#include >> + >> +#include "ffmpeg.h" >> + >> +#include "libavutil/avassert.h" >> +#include "libavutil/avconfig.h" >> +#include "libavutil/buffer.h" >> +#include "libavutil/frame.h" >> +#include "libavutil/imgutils.h" >> +#include "libavutil/opt.h" >> +#include "libavutil/pixfmt.h" >> +#include "libavutil/thread.h" >> +#include "libavutil/vaapi.h" >> + >> +#include "libavcodec/vaapi.h" >> + >> +#include >> +#include >> + >> + >> +static AVClass vaapi_class
[FFmpeg-devel] [PATCH v3 2/5] ffmpeg: initialisation code for VAAPI, hwaccel helper
--- Makefile | 1 + ffmpeg.c | 5 + ffmpeg.h | 5 + ffmpeg_opt.c | 14 ++ ffmpeg_vaapi.c | 622 + 5 files changed, 647 insertions(+) create mode 100644 ffmpeg_vaapi.c diff --git a/Makefile b/Makefile index 7836a20..be1d2ca 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ OBJS-ffmpeg-$(CONFIG_VDA) += ffmpeg_videotoolbox.o endif OBJS-ffmpeg-$(CONFIG_VIDEOTOOLBOX) += ffmpeg_videotoolbox.o OBJS-ffmpeg-$(CONFIG_LIBMFX) += ffmpeg_qsv.o +OBJS-ffmpeg-$(CONFIG_VAAPI) += ffmpeg_vaapi.o OBJS-ffserver += ffserver_config.o TESTTOOLS = audiogen videogen rotozoom tiny_psnr tiny_ssim base64 diff --git a/ffmpeg.c b/ffmpeg.c index 1f4277c..e76879a 100644 --- a/ffmpeg.c +++ b/ffmpeg.c @@ -2603,6 +2603,11 @@ static int init_output_stream(OutputStream *ost, char *error, int error_len) !av_dict_get(ost->encoder_opts, "ab", NULL, 0)) av_dict_set(>encoder_opts, "b", "128000", 0); +#if CONFIG_VAAPI +if(ost->enc->type == AVMEDIA_TYPE_VIDEO) +vaapi_hardware_set_options(>encoder_opts); +#endif + if ((ret = avcodec_open2(ost->enc_ctx, codec, >encoder_opts)) < 0) { if (ret == AVERROR_EXPERIMENTAL) abort_codec_experimental(codec, 1); diff --git a/ffmpeg.h b/ffmpeg.h index 20322b0..2134213 100644 --- a/ffmpeg.h +++ b/ffmpeg.h @@ -65,6 +65,7 @@ enum HWAccelID { HWACCEL_VDA, HWACCEL_VIDEOTOOLBOX, HWACCEL_QSV, +HWACCEL_VAAPI, }; typedef struct HWAccel { @@ -577,5 +578,9 @@ int vda_init(AVCodecContext *s); int videotoolbox_init(AVCodecContext *s); int qsv_init(AVCodecContext *s); int qsv_transcode_init(OutputStream *ost); +int vaapi_decode_init(AVCodecContext *s); + +int vaapi_hardware_init(const char *device); +int vaapi_hardware_set_options(AVDictionary **dict); #endif /* FFMPEG_H */ diff --git a/ffmpeg_opt.c b/ffmpeg_opt.c index 9b341cf..47ac467 100644 --- a/ffmpeg_opt.c +++ b/ffmpeg_opt.c @@ -82,6 +82,9 @@ const HWAccel hwaccels[] = { #if CONFIG_LIBMFX { "qsv", qsv_init, HWACCEL_QSV, AV_PIX_FMT_QSV }, #endif +#if CONFIG_VAAPI +{ "vaapi", vaapi_decode_init, HWACCEL_VAAPI, AV_PIX_FMT_VAAPI }, +#endif { 0 }, }; @@ -442,6 +445,13 @@ static int opt_sdp_file(void *optctx, const char *opt, const char *arg) return 0; } +static int opt_vaapi(void *optctx, const char *opt, const char *arg) +{ +if(vaapi_hardware_init(arg)) +exit_program(1); +return 0; +} + /** * Parse a metadata specifier passed as 'arg' parameter. * @param arg metadata string to parse @@ -3438,5 +3448,9 @@ const OptionDef options[] = { { "dn", OPT_BOOL | OPT_VIDEO | OPT_OFFSET | OPT_INPUT | OPT_OUTPUT, { .off = OFFSET(data_disable) }, "disable data" }, +#if CONFIG_VAAPI +{ "vaapi", HAS_ARG, { .func_arg = opt_vaapi }, "set VAAPI hardware context" }, +#endif + { NULL, }, }; diff --git a/ffmpeg_vaapi.c b/ffmpeg_vaapi.c new file mode 100644 index 000..e04532c --- /dev/null +++ b/ffmpeg_vaapi.c @@ -0,0 +1,622 @@ +/* + * VAAPI helper for hardware-accelerated decoding. + * + * 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 +#include +#include + +#include "ffmpeg.h" + +#include "libavutil/avassert.h" +#include "libavutil/avconfig.h" +#include "libavutil/buffer.h" +#include "libavutil/frame.h" +#include "libavutil/imgutils.h" +#include "libavutil/opt.h" +#include "libavutil/pixfmt.h" +#include "libavutil/thread.h" +#include "libavutil/vaapi.h" + +#include "libavcodec/vaapi.h" + +#include +#include + + +static AVClass vaapi_class = { +.class_name = "VAAPI/driver", +.item_name = av_default_item_name, +.version= LIBAVUTIL_VERSION_INT, +}; + + +#define DEFAULT_SURFACES 20 + +typedef struct VAAPIDecoderContext { +const AVClass *class; + +AVVAAPIHardwareContext *hardware_context; +AVVAAPIPipelineConfig config; +AVVAAPIPipelineContext codec; +AVVAAPISurfaceConfig output; + +int codec_initialised; + +AVFrame output_frame; +} VAAPIDecoderContext; + + +static int vaapi_get_buffer(AVCodecContext *s, AVFrame *frame, int flags) +{ +InputStream *ist =