video: warn if an emulated hwdec API is used

mpv supports two hardware decoding APIs on Linux: vdpau and vaapi. Each
of these has emulation wrappers. The wrappers are usually slower and
have fewer features than their native opposites. In particular the libva
vdpau driver is practically unmaintained.

Check the vendor string and print a warning if emulation is detected.
Checking vendor strings is a very stupid thing to do, but I find the
thought of people using an emulated API for no reason worse.

Also, make --hwdec=auto never use an API that is detected as emulated.
This doesn't work quite right yet, because once one API is loaded,
vo_opengl doesn't unload it, so no hardware decoding will be used if the
first probed API (usually vdpau) is rejected. But good enough.
This commit is contained in:
wm4 2014-05-28 01:37:53 +02:00
parent 8dfd93c6fb
commit d99f30d726
11 changed files with 48 additions and 4 deletions

View File

@ -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 {

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -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");
}

View File

@ -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

View File

@ -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");
}

View File

@ -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

View File

@ -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)