diff --git a/video/decode/lavc.h b/video/decode/lavc.h index d67292c4fd..14dc6dda4e 100644 --- a/video/decode/lavc.h +++ b/video/decode/lavc.h @@ -65,6 +65,7 @@ struct vd_lavc_hwdec { enum { HWDEC_ERR_NO_CTX = -2, HWDEC_ERR_NO_CODEC = -3, + HWDEC_ERR_EMULATED = -4, // probing successful, but emulated API detected }; struct hwdec_profile_entry { diff --git a/video/decode/vaapi.c b/video/decode/vaapi.c index d9267936d0..2b951fd1bb 100644 --- a/video/decode/vaapi.c +++ b/video/decode/vaapi.c @@ -409,6 +409,8 @@ static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, return HWDEC_ERR_NO_CTX; if (!hwdec_check_codec_support(decoder, profiles)) return HWDEC_ERR_NO_CODEC; + if (va_guess_if_emulated(info->vaapi_ctx)) + return HWDEC_ERR_EMULATED; return 0; } @@ -418,9 +420,12 @@ static int probe_copy(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, struct priv dummy = {mp_null_log}; if (!create_va_dummy_ctx(&dummy)) return HWDEC_ERR_NO_CTX; + bool emulated = va_guess_if_emulated(dummy.ctx); destroy_va_dummy_ctx(&dummy); if (!hwdec_check_codec_support(decoder, profiles)) return HWDEC_ERR_NO_CODEC; + if (emulated) + return HWDEC_ERR_EMULATED; return 0; } diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c index 2593e50285..9ef49c25e1 100644 --- a/video/decode/vd_lavc.c +++ b/video/decode/vd_lavc.c @@ -200,19 +200,24 @@ static struct vd_lavc_hwdec *probe_hwdec(struct dec_video *vd, bool autoprobe, { struct vd_lavc_hwdec *hwdec = find_hwcodec(api); if (!hwdec) { - MP_VERBOSE(vd, "Requested hardware decoder not " - "compiled.\n"); + MP_VERBOSE(vd, "Requested hardware decoder not compiled.\n"); return NULL; } int r = hwdec_probe(hwdec, &vd->hwdec_info, decoder); + if (r == HWDEC_ERR_EMULATED) { + if (autoprobe) + return NULL; + // User requested this explicitly. + MP_WARN(vd, "Using emulated hardware decoding API.\n"); + r = 0; + } if (r >= 0) { return hwdec; } else if (r == HWDEC_ERR_NO_CODEC) { MP_VERBOSE(vd, "Hardware decoder '%s' not found in " "libavcodec.\n", decoder); } else if (r == HWDEC_ERR_NO_CTX && !autoprobe) { - MP_WARN(vd, "VO does not support requested " - "hardware decoder.\n"); + MP_WARN(vd, "VO does not support requested hardware decoder.\n"); } return NULL; } diff --git a/video/decode/vdpau.c b/video/decode/vdpau.c index 4cd1eee531..44850dfaec 100644 --- a/video/decode/vdpau.c +++ b/video/decode/vdpau.c @@ -175,6 +175,8 @@ static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info, return HWDEC_ERR_NO_CTX; if (!hwdec_check_codec_support(decoder, profiles)) return HWDEC_ERR_NO_CODEC; + if (mp_vdpau_guess_if_emulated(info->vdpau_ctx)) + return HWDEC_ERR_EMULATED; return 0; } diff --git a/video/out/vo_vaapi.c b/video/out/vo_vaapi.c index 8fb863ece6..7d167ea82e 100644 --- a/video/out/vo_vaapi.c +++ b/video/out/vo_vaapi.c @@ -584,6 +584,11 @@ static int preinit(struct vo *vo) goto fail; } + if (va_guess_if_emulated(p->mpvaapi)) { + MP_WARN(vo, "VA-API is most likely emulated via VDPAU.\n" + "It's better to use VDPAU directly with: --vo=vdpau\n"); + } + p->pool = mp_image_pool_new(MAX_OUTPUT_SURFACES + 3); va_pool_set_allocator(p->pool, p->mpvaapi, VA_RT_FORMAT_YUV420); p->va_image_formats = p->mpvaapi->image_formats; diff --git a/video/out/vo_vdpau.c b/video/out/vo_vdpau.c index b6728e79d8..3deac1724b 100644 --- a/video/out/vo_vdpau.c +++ b/video/out/vo_vdpau.c @@ -1005,6 +1005,11 @@ static int preinit(struct vo *vo) vc->video_mixer = mp_vdpau_mixer_create(vc->mpvdp, vo->log); + if (mp_vdpau_guess_if_emulated(vc->mpvdp)) { + MP_WARN(vo, "VDPAU is most likely emulated via VA-API.\n" + "This is inefficient. Use --vo=opengl instead.\n"); + } + // Mark everything as invalid first so uninit() can tell what has been // allocated mark_vdpau_objects_uninitialized(vo); diff --git a/video/vaapi.c b/video/vaapi.c index 2b2b7819dd..56bffaa05f 100644 --- a/video/vaapi.c +++ b/video/vaapi.c @@ -448,3 +448,9 @@ void va_pool_set_allocator(struct mp_image_pool *pool, struct mp_vaapi_ctx *ctx, mp_image_pool_set_allocator(pool, alloc_pool, alloc_ctx); mp_image_pool_set_lru(pool); } + +bool va_guess_if_emulated(struct mp_vaapi_ctx *ctx) +{ + const char *s = vaQueryVendorString(ctx->display); + return s && strstr(s, "VDPAU backend"); +} diff --git a/video/vaapi.h b/video/vaapi.h index c555161999..8a96bb1347 100644 --- a/video/vaapi.h +++ b/video/vaapi.h @@ -109,4 +109,6 @@ struct mp_image *va_surface_download(struct mp_image *src, int va_surface_alloc_imgfmt(struct mp_image *img, int imgfmt); int va_surface_upload(struct mp_image *va_dst, struct mp_image *sw_src); +bool va_guess_if_emulated(struct mp_vaapi_ctx *ctx); + #endif diff --git a/video/vdpau.c b/video/vdpau.c index 20fbf2566f..0cf91ffe86 100644 --- a/video/vdpau.c +++ b/video/vdpau.c @@ -426,3 +426,13 @@ struct mp_image *mp_vdpau_upload_video_surface(struct mp_vdpau_ctx *ctx, mp_image_copy_attributes(hwmpi, mpi); return hwmpi; } + +bool mp_vdpau_guess_if_emulated(struct mp_vdpau_ctx *ctx) +{ + struct vdp_functions *vdp = &ctx->vdp; + VdpStatus vdp_st; + char const* info = NULL; + vdp_st = vdp->get_information_string(&info); + CHECK_VDP_WARNING(ctx, "Error when calling vdp_get_information_string"); + return vdp_st == VDP_STATUS_OK && info && strstr(info, "VAAPI"); +} diff --git a/video/vdpau.h b/video/vdpau.h index 3aea414700..7fdbbf47bf 100644 --- a/video/vdpau.h +++ b/video/vdpau.h @@ -84,4 +84,6 @@ bool mp_vdpau_get_rgb_format(int imgfmt, VdpRGBAFormat *out_rgba_format); struct mp_image *mp_vdpau_upload_video_surface(struct mp_vdpau_ctx *ctx, struct mp_image *mpi); +bool mp_vdpau_guess_if_emulated(struct mp_vdpau_ctx *ctx); + #endif diff --git a/video/vdpau_functions.inc b/video/vdpau_functions.inc index 1789768c83..5604420f69 100644 --- a/video/vdpau_functions.inc +++ b/video/vdpau_functions.inc @@ -14,6 +14,7 @@ VDP_FUNCTION(VdpDecoderDestroy, VDP_FUNC_ID_DECODER_DESTROY, decoder_destroy) VDP_FUNCTION(VdpDecoderRender, VDP_FUNC_ID_DECODER_RENDER, decoder_render) VDP_FUNCTION(VdpDecoderQueryCapabilities, VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES, decoder_query_capabilities) VDP_FUNCTION(VdpDeviceDestroy, VDP_FUNC_ID_DEVICE_DESTROY, device_destroy) +VDP_FUNCTION(VdpGetInformationString, VDP_FUNC_ID_GET_INFORMATION_STRING, get_information_string) VDP_FUNCTION(VdpGenerateCSCMatrix, VDP_FUNC_ID_GENERATE_CSC_MATRIX, generate_csc_matrix) VDP_FUNCTION(VdpOutputSurfaceCreate, VDP_FUNC_ID_OUTPUT_SURFACE_CREATE, output_surface_create) VDP_FUNCTION(VdpOutputSurfaceDestroy, VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY, output_surface_destroy)