From 6aa4efd1e3205c9b1385865df1b5b09646d2160c Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 20 Feb 2017 08:39:55 +0100 Subject: vd_lavc, vaapi: move hw device creation to generic code hw_vaapi.c didn't do much interesting anymore. Other than the function to create a device for decoding with vaapi-copy, everything can be done by generic code. Other libavcodec hwaccels are planned to provide the same API as vaapi. It will be possible to drop the other hw_ files in the future. They will use this generic code instead. --- video/decode/hw_vaapi.c | 142 -------------------------------------------- video/decode/hw_vaapi_old.c | 10 ++-- video/decode/lavc.h | 10 +++- video/decode/vd_lavc.c | 77 ++++++++++++++++++++++-- video/hwdec.c | 2 - video/hwdec.h | 6 ++ video/vaapi.c | 13 +++- video/vaapi.h | 4 +- wscript_build.py | 1 - 9 files changed, 104 insertions(+), 161 deletions(-) delete mode 100644 video/decode/hw_vaapi.c diff --git a/video/decode/hw_vaapi.c b/video/decode/hw_vaapi.c deleted file mode 100644 index 81854207e2..0000000000 --- a/video/decode/hw_vaapi.c +++ /dev/null @@ -1,142 +0,0 @@ -/* - * This file is part of mpv. - * - * mpv 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. - * - * mpv 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 mpv. If not, see . - */ - -#include -#include - -#include -#include -#include -#include - -#include "config.h" - -#include "lavc.h" -#include "common/common.h" -#include "common/av_common.h" -#include "video/fmt-conversion.h" -#include "video/vaapi.h" -#include "video/mp_image_pool.h" -#include "video/hwdec.h" -#include "video/filter/vf.h" - -struct priv { - struct mp_log *log; - struct mp_vaapi_ctx *ctx; -}; - -static void uninit(struct lavc_ctx *ctx) -{ - struct priv *p = ctx->hwdec_priv; - - if (!p) - return; - - va_destroy(p->ctx); - - talloc_free(p); - ctx->hwdec_priv = NULL; - ctx->hwdec_dev = NULL; -} - -static int init(struct lavc_ctx *ctx, bool direct) -{ - struct priv *p = talloc_ptrtype(NULL, p); - *p = (struct priv) { - .log = mp_log_new(p, ctx->log, "vaapi"), - }; - - if (direct) { - ctx->hwdec_dev = hwdec_devices_get(ctx->hwdec_devs, HWDEC_VAAPI); - } else { - p->ctx = va_create_standalone(ctx->log, false); - if (!p->ctx) { - talloc_free(p); - return -1; - } - ctx->hwdec_dev = &p->ctx->hwctx; - } - - ctx->hwdec_priv = p; - - if (!ctx->hwdec_dev->av_device_ref) - return -1; - - return 0; -} - -static int init_direct(struct lavc_ctx *ctx) -{ - return init(ctx, true); -} - -static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, - const char *codec) -{ - if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_VAAPI)) - return HWDEC_ERR_NO_CTX; - return 0; -} - -static int probe_copy(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, - const char *codec) -{ - struct mp_vaapi_ctx *dummy = va_create_standalone(ctx->log, true); - if (!dummy) - return HWDEC_ERR_NO_CTX; - bool emulated = va_guess_if_emulated(dummy); - va_destroy(dummy); - if (emulated) - return HWDEC_ERR_EMULATED; - return 0; -} - -static int init_copy(struct lavc_ctx *ctx) -{ - return init(ctx, false); -} - -const struct vd_lavc_hwdec mp_vd_lavc_vaapi = { - .type = HWDEC_VAAPI, - .image_format = IMGFMT_VAAPI, - .probe = probe, - .init = init_direct, - .uninit = uninit, - .generic_hwaccel = true, - .static_pool = true, - .pixfmt_map = (const enum AVPixelFormat[][2]) { - {AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010}, - {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12}, - {AV_PIX_FMT_NONE} - }, -}; - -const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy = { - .type = HWDEC_VAAPI_COPY, - .copying = true, - .image_format = IMGFMT_VAAPI, - .probe = probe_copy, - .init = init_copy, - .uninit = uninit, - .generic_hwaccel = true, - .static_pool = true, - .pixfmt_map = (const enum AVPixelFormat[][2]) { - {AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010}, - {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12}, - {AV_PIX_FMT_NONE} - }, -}; diff --git a/video/decode/hw_vaapi_old.c b/video/decode/hw_vaapi_old.c index 88379dfed8..fb0fc40110 100644 --- a/video/decode/hw_vaapi_old.c +++ b/video/decode/hw_vaapi_old.c @@ -327,11 +327,12 @@ static int init(struct lavc_ctx *ctx, bool direct) if (direct) { p->ctx = hwdec_devices_get(ctx->hwdec_devs, HWDEC_VAAPI)->ctx; } else { - p->ctx = va_create_standalone(ctx->log, false); - if (!p->ctx) { + struct mp_hwdec_ctx *hwctx = va_create_standalone(NULL, ctx->log, false); + if (!hwctx) { talloc_free(p); return -1; } + p->ctx = hwctx->ctx; p->own_ctx = true; } @@ -368,9 +369,10 @@ static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, static int probe_copy(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec, const char *codec) { - struct mp_vaapi_ctx *dummy = va_create_standalone(ctx->log, true); - if (!dummy) + struct mp_hwdec_ctx *hwctx = va_create_standalone(NULL, ctx->log, true); + if (!hwctx) return HWDEC_ERR_NO_CTX; + struct mp_vaapi_ctx *dummy = hwctx->ctx; bool emulated = va_guess_if_emulated(dummy); va_destroy(dummy); if (!hwdec_check_codec_support(codec, profiles)) diff --git a/video/decode/lavc.h b/video/decode/lavc.h index b41d56ce2f..dfce9c3bfd 100644 --- a/video/decode/lavc.h +++ b/video/decode/lavc.h @@ -19,6 +19,8 @@ // This value does not yet include HWDEC_DELAY_QUEUE_COUNT. #define HWDEC_EXTRA_SURFACES 4 +struct mpv_global; + typedef struct lavc_ctx { struct mp_log *log; struct MPOpts *opts; @@ -95,9 +97,11 @@ struct vd_lavc_hwdec { struct mp_image *(*allocate_image)(struct lavc_ctx *ctx, int w, int h); // Process the image returned by the libavcodec decoder. struct mp_image *(*process_image)(struct lavc_ctx *ctx, struct mp_image *img); - // Optional; if a special hardware decoder is needed (instead of "hwaccel"). - const char *(*get_codec)(struct lavc_ctx *ctx, const char *codec); - // Suffix for libavcodec decoder. If non-NULL, get_codec() is overridden + // For copy hwdecs. If probing is true, don't log errors if unavailable. + // The returned device must be freed with mp_hwdec_ctx->destroy. + struct mp_hwdec_ctx *(*create_dev)(struct mpv_global *global, + struct mp_log *log, bool probing); + // Suffix for libavcodec decoder. If non-NULL, the codec is overridden // with hwdec_find_decoder. // Intuitively, this will force the corresponding wrapper decoder. const char *lavc_suffix; diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index cd054f7ea4..f89ec7e6cd 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -129,8 +129,6 @@ extern const struct vd_lavc_hwdec mp_vd_lavc_vdpau; extern const struct vd_lavc_hwdec mp_vd_lavc_vdpau_copy; extern const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox; extern const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox_copy; -extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi; -extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy; extern const struct vd_lavc_hwdec mp_vd_lavc_dxva2; extern const struct vd_lavc_hwdec mp_vd_lavc_dxva2_copy; extern const struct vd_lavc_hwdec mp_vd_lavc_d3d11va; @@ -172,6 +170,41 @@ static const struct vd_lavc_hwdec mp_vd_lavc_crystalhd = { .copying = true, }; +#if HAVE_VAAPI_HWACCEL +#if HAVE_VAAPI_HWACCEL_NEW +const struct vd_lavc_hwdec mp_vd_lavc_vaapi = { + .type = HWDEC_VAAPI, + .image_format = IMGFMT_VAAPI, + .generic_hwaccel = true, + .static_pool = true, + .pixfmt_map = (const enum AVPixelFormat[][2]) { + {AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010}, + {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12}, + {AV_PIX_FMT_NONE} + }, +}; + +#include "video/vaapi.h" + +const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy = { + .type = HWDEC_VAAPI_COPY, + .copying = true, + .image_format = IMGFMT_VAAPI, + .generic_hwaccel = true, + .static_pool = true, + .create_dev = va_create_standalone, + .pixfmt_map = (const enum AVPixelFormat[][2]) { + {AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010}, + {AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12}, + {AV_PIX_FMT_NONE} + }, +}; +#else +extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi; +extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy; +#endif +#endif + static const struct vd_lavc_hwdec *const hwdec_list[] = { #if HAVE_RPI &mp_vd_lavc_rpi, @@ -309,13 +342,37 @@ static bool hwdec_is_wrapper(struct vd_lavc_hwdec *hwdec, const char *decoder) return bstr_endswith0(bstr0(decoder), hwdec->lavc_suffix); } +static struct mp_hwdec_ctx *hwdec_create_dev(struct dec_video *vd, + struct vd_lavc_hwdec *hwdec, + bool autoprobe) +{ + if (hwdec->create_dev) + return hwdec->create_dev(vd->global, vd->log, autoprobe); + if (vd->hwdec_devs) { + hwdec_devices_request(vd->hwdec_devs, hwdec->type); + return hwdec_devices_get(vd->hwdec_devs, hwdec->type); + } + return NULL; +} + static int hwdec_probe(struct dec_video *vd, struct vd_lavc_hwdec *hwdec, - const char *codec) + const char *codec, bool autoprobe) { vd_ffmpeg_ctx *ctx = vd->priv; int r = 0; if (hwdec->probe) r = hwdec->probe(ctx, hwdec, codec); + if (hwdec->generic_hwaccel) { + assert(!hwdec->probe && !hwdec->init && !hwdec->init_decoder && + !hwdec->uninit && !hwdec->allocate_image && !hwdec->process_image); + struct mp_hwdec_ctx *dev = hwdec_create_dev(vd, hwdec, autoprobe); + if (!dev) + return hwdec->copying ? -1 : HWDEC_ERR_NO_CTX; + if (dev->emulated) + r = HWDEC_ERR_EMULATED; + if (hwdec->create_dev && dev->destroy) + dev->destroy(dev); + } if (r >= 0) { if (hwdec->lavc_suffix && !hwdec_find_decoder(codec, hwdec->lavc_suffix)) return HWDEC_ERR_NO_CODEC; @@ -333,7 +390,7 @@ static struct vd_lavc_hwdec *probe_hwdec(struct dec_video *vd, bool autoprobe, MP_VERBOSE(vd, "Requested hardware decoder not compiled.\n"); return NULL; } - int r = hwdec_probe(vd, hwdec, codec); + int r = hwdec_probe(vd, hwdec, codec, autoprobe); if (r == HWDEC_ERR_EMULATED) { if (autoprobe) return NULL; @@ -421,8 +478,6 @@ static void reinit(struct dec_video *vd) if (hwdec) { const char *orig_decoder = decoder; - if (hwdec->get_codec) - decoder = hwdec->get_codec(ctx, decoder); if (hwdec->lavc_suffix) decoder = hwdec_find_decoder(codec, hwdec->lavc_suffix); MP_VERBOSE(vd, "Trying hardware decoding.\n"); @@ -505,6 +560,11 @@ static void init_avctx(struct dec_video *vd, const char *decoder, avctx->get_buffer2 = get_buffer2_hwdec; if (ctx->hwdec->init && ctx->hwdec->init(ctx) < 0) goto error; + if (ctx->hwdec->generic_hwaccel) { + ctx->hwdec_dev = hwdec_create_dev(vd, ctx->hwdec, false); + if (!ctx->hwdec_dev) + goto error; + } ctx->max_delay_queue = ctx->hwdec->delay_queue; ctx->hw_probing = true; } else { @@ -584,6 +644,11 @@ static void uninit_avctx(struct dec_video *vd) av_freep(&ctx->avctx->extradata); } + if (ctx->hwdec_dev && ctx->hwdec && ctx->hwdec->generic_hwaccel && + ctx->hwdec_dev->destroy) + ctx->hwdec_dev->destroy(ctx->hwdec_dev); + ctx->hwdec_dev = NULL; + if (ctx->hwdec && ctx->hwdec->uninit) ctx->hwdec->uninit(ctx); ctx->hwdec = NULL; diff --git a/video/hwdec.c b/video/hwdec.c index 6db8d57869..371c368fa3 100644 --- a/video/hwdec.c +++ b/video/hwdec.c @@ -72,8 +72,6 @@ void hwdec_devices_set_loader(struct mp_hwdec_devices *devs, devs->load_api_ctx = load_api_ctx; } -// Cause VO to lazily load the requested device, and will block until this is -// done (even if not available). void hwdec_devices_request(struct mp_hwdec_devices *devs, enum hwdec_type type) { if (devs->load_api && !hwdec_devices_get_first(devs)) diff --git a/video/hwdec.h b/video/hwdec.h index f8a089e8c6..86b5521975 100644 --- a/video/hwdec.h +++ b/video/hwdec.h @@ -53,6 +53,9 @@ struct mp_hwdec_ctx { // List of IMGFMT_s, terminated with 0. NULL if N/A. int *supported_formats; + // Hint to generic code: it's using a wrapper API + bool emulated; + // Optional. Legacy. (New code should use AVHWFramesContext and // mp_image_hw_download().) // Allocates a software image from the pool, downloads the hw image from @@ -62,6 +65,9 @@ struct mp_hwdec_ctx { struct mp_image *(*download_image)(struct mp_hwdec_ctx *ctx, struct mp_image *mpi, struct mp_image_pool *swpool); + + // Optional. Do not set for VO-bound devices. + void (*destroy)(struct mp_hwdec_ctx *ctx); }; // Used to communicate hardware decoder device handles from VO to video decoder. diff --git a/video/vaapi.c b/video/vaapi.c index 5c8ce4c693..171ccdfcbd 100644 --- a/video/vaapi.c +++ b/video/vaapi.c @@ -210,6 +210,8 @@ struct mp_vaapi_ctx *va_initialize(VADisplay *display, struct mp_log *plog, // libva drivers (such as the vdpau wraper). So don't error out on failure. open_lavu_vaapi_device(res); + res->hwctx.emulated = va_guess_if_emulated(res); + return res; error: @@ -716,7 +718,13 @@ static const struct va_native_display *const native_displays[] = { NULL }; -struct mp_vaapi_ctx *va_create_standalone(struct mp_log *plog, bool probing) +static void va_destroy_ctx(struct mp_hwdec_ctx *ctx) +{ + va_destroy(ctx->ctx); +} + +struct mp_hwdec_ctx *va_create_standalone(struct mpv_global *global, + struct mp_log *plog, bool probing) { for (int n = 0; native_displays[n]; n++) { VADisplay *display = NULL; @@ -731,7 +739,8 @@ struct mp_vaapi_ctx *va_create_standalone(struct mp_log *plog, bool probing) } ctx->native_ctx = native_ctx; ctx->destroy_native_ctx = native_displays[n]->destroy; - return ctx; + ctx->hwctx.destroy = va_destroy_ctx; + return &ctx->hwctx; } } return NULL; diff --git a/video/vaapi.h b/video/vaapi.h index de7d6d98d8..d21e3a34ee 100644 --- a/video/vaapi.h +++ b/video/vaapi.h @@ -73,6 +73,8 @@ void va_surface_init_subformat(struct mp_image *mpi); bool va_guess_if_emulated(struct mp_vaapi_ctx *ctx); -struct mp_vaapi_ctx *va_create_standalone(struct mp_log *plog, bool probing); +struct mpv_global; +struct mp_hwdec_ctx *va_create_standalone(struct mpv_global *global, + struct mp_log *plog, bool probing); #endif diff --git a/wscript_build.py b/wscript_build.py index 82d1a879eb..4371426f1f 100644 --- a/wscript_build.py +++ b/wscript_build.py @@ -309,7 +309,6 @@ def build(ctx): ( "video/decode/hw_cuda.c", "cuda-hwaccel" ), ( "video/decode/hw_dxva2.c", "d3d-hwaccel" ), ( "video/decode/hw_d3d11va.c", "d3d-hwaccel" ), - ( "video/decode/hw_vaapi.c", "vaapi-hwaccel-new" ), ( "video/decode/hw_vaapi_old.c", "vaapi-hwaccel-old" ), ( "video/decode/hw_vdpau.c", "vdpau-hwaccel" ), ( "video/decode/hw_videotoolbox.c", "videotoolbox-hwaccel" ), -- cgit v1.2.3