Example #1
0
static int Open(vlc_va_t *va, AVCodecContext *ctx, const es_format_t *fmt)
{
    VdpStatus err;
    VdpDecoderProfile profile;
    int level = fmt->i_level;

    if (av_vdpau_get_profile(ctx, &profile))
    {
        msg_Err(va, "unsupported codec %d or profile %d", ctx->codec_id,
                fmt->i_profile);
        return VLC_EGENERIC;
    }

    switch (ctx->codec_id)
    {
        case AV_CODEC_ID_MPEG1VIDEO:
            level = VDP_DECODER_LEVEL_MPEG1_NA;
            break;
        case AV_CODEC_ID_MPEG2VIDEO:
            level = VDP_DECODER_LEVEL_MPEG2_HL;
            break;
        case AV_CODEC_ID_H263:
            level = VDP_DECODER_LEVEL_MPEG4_PART2_ASP_L5;
            break;
        case AV_CODEC_ID_H264:
            if ((fmt->i_profile & FF_PROFILE_H264_INTRA)
             && (fmt->i_level == 11))
                level = VDP_DECODER_LEVEL_H264_1b;
         default:
            break;
    }

    if (!vlc_xlib_init(VLC_OBJECT(va)))
    {
        msg_Err(va, "Xlib is required for VDPAU");
        return VLC_EGENERIC;
    }

    vlc_va_sys_t *sys = malloc(sizeof (*sys));
    if (unlikely(sys == NULL))
       return VLC_ENOMEM;

    sys->context = av_vdpau_alloc_context();
    if (unlikely(sys->context == NULL))
    {
        free(sys);
        return VLC_ENOMEM;
    }

    err = vdp_get_x11(NULL, -1, &sys->vdp, &sys->device);
    if (err != VDP_STATUS_OK)
    {
        free(sys->context);
        free(sys);
        return VLC_EGENERIC;
    }

    void *func;
    err = vdp_get_proc_address(sys->vdp, sys->device,
                               VDP_FUNC_ID_DECODER_RENDER, &func);
    if (err != VDP_STATUS_OK)
        goto error;

    sys->context->decoder = VDP_INVALID_HANDLE;
    sys->context->render = func;
    sys->profile = profile;

    /* Check capabilities */
    VdpBool support;
    uint32_t l, mb, w, h;

    if (vdp_video_surface_query_capabilities(sys->vdp, sys->device,
              VDP_CHROMA_TYPE_420, &support, &w, &h) != VDP_STATUS_OK)
        support = VDP_FALSE;
    if (!support)
    {
        msg_Err(va, "video surface format not supported: %s", "YUV 4:2:0");
        goto error;
    }
    msg_Dbg(va, "video surface limits: %"PRIu32"x%"PRIu32, w, h);
    if (w < fmt->video.i_width || h < fmt->video.i_height)
    {
        msg_Err(va, "video surface above limits: %ux%u",
                fmt->video.i_width, fmt->video.i_height);
        goto error;
    }

    if (vdp_decoder_query_capabilities(sys->vdp, sys->device, profile,
                                   &support, &l, &mb, &w, &h) != VDP_STATUS_OK)
        support = VDP_FALSE;
    if (!support)
    {
        msg_Err(va, "decoder profile not supported: %u", profile);
        goto error;
    }
    msg_Dbg(va, "decoder profile limits: level %"PRIu32" mb %"PRIu32" "
            "%"PRIu32"x%"PRIu32, l, mb, w, h);
    if ((int)l < level || w < fmt->video.i_width || h < fmt->video.i_height)
    {
        msg_Err(va, "decoder profile above limits: level %d %ux%u",
                level, fmt->video.i_width, fmt->video.i_height);
        goto error;
    }

    const char *infos;
    if (vdp_get_information_string(sys->vdp, &infos) != VDP_STATUS_OK)
        infos = "VDPAU";

    va->sys = sys;
    va->description = (char *)infos;
    va->pix_fmt = AV_PIX_FMT_VDPAU;
    va->setup = Setup;
    va->get = Lock;
    va->release = Unlock;
    va->extract = Copy;
    return VLC_SUCCESS;

error:
    vdp_release_x11(sys->vdp);
    av_free(sys->context);
    free(sys);
    return VLC_EGENERIC;
}
Example #2
0
QString VDPAUContext::init()
{
	QString err;
	
	vdp_get_proc_address = NULL;
	vdpDevice = VDP_INVALID_HANDLE;
	
	VdpStatus st = vdp_device_create_x11( vdpDisplay, vdpScreen, &vdpDevice, &vdp_get_proc_address );
	if ( st != VDP_STATUS_OK ) {
		err = "Can't create vdp device : ";
		if ( st == VDP_STATUS_NO_IMPLEMENTATION )
			err += "No vdpau implementation.";
		else
			err += "Unsupported GPU?";
		return err;
	}
	if ( vdpDevice==VDP_INVALID_HANDLE )
		return "Invalid VdpDevice handle !!";
	if ( !vdp_get_proc_address )
		return "vdp_get_proc_address is NULL !!";
		
	if ( !getFunc( VDP_FUNC_ID_GET_ERROR_STRING , (void**)&vdp_get_error_string ) )
		return "Can't get VDP_FUNC_ID_GET_ERROR_STRING address !!";
		
	if ( !getFunc( VDP_FUNC_ID_GET_API_VERSION , (void**)&vdp_get_api_version ) )
		return "Can't get VDP_FUNC_ID_GET_API_VERSION address !!";
		
	if ( !getFunc( VDP_FUNC_ID_GET_INFORMATION_STRING , (void**)&vdp_get_information_string ) )
		return "Can't get VDP_FUNC_ID_GET_INFORMATION_STRING address !!";
	
	if ( !getFunc( VDP_FUNC_ID_DEVICE_DESTROY , (void**)&vdp_device_destroy ) )
		return "Can't get VDP_FUNC_ID_DEVICE_DESTROY address !!";
	
	if ( !getFunc( VDP_FUNC_ID_GENERATE_CSC_MATRIX , (void**)&vdp_generate_csc_matrix ) )
		return "Can't get VDP_FUNC_ID_GENERATE_CSC_MATRIX address !!";
	
	if ( !getFunc( VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES , (void**)&vdp_video_surface_query_capabilities ) )
		return "Can't get VDP_FUNC_ID_VIDEO_SURFACE_QUERY_CAPABILITIES address !!";
	
	if ( !getFunc( VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES , (void**)&vdp_video_surface_query_get_put_bits_y_cb_cr_capabilities ) )
		return "Can't get VDP_FUNC_ID_VIDEO_SURFACE_QUERY_GET_PUT_BITS_Y_CB_CR_CAPABILITIES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_SURFACE_CREATE , (void**)&vdp_video_surface_create ) )
		return "Can't get VDP_FUNC_ID_VIDEO_SURFACE_CREATE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_SURFACE_DESTROY , (void**)&vdp_video_surface_destroy ) )
		return "Can't get VDP_FUNC_ID_VIDEO_SURFACE_DESTROY address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS , (void**)&vdp_video_surface_get_parameters ) )
		return "Can't get VDP_FUNC_ID_VIDEO_SURFACE_GET_PARAMETERS address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR , (void**)&vdp_video_surface_get_bits_y_cb_cr ) )
		return "Can't get VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR , (void**)&vdp_video_surface_put_bits_y_cb_cr ) )
		return "Can't get VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_CAPABILITIES , (void**)&vdp_output_surface_query_capabilities ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_CAPABILITIES address !!";
	
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_GET_PUT_BITS_NATIVE_CAPABILITIES , (void**)&vdp_output_surface_query_get_put_bits_native_capabilities ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_GET_PUT_BITS_NATIVE_CAPABILITIES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_INDEXED_CAPABILITIES , (void**)&vdp_output_surface_query_put_bits_indexed_capabilities ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_INDEXED_CAPABILITIES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_Y_CB_CR_CAPABILITIES , (void**)&vdp_output_surface_query_put_bits_y_cb_cr_capabilities ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_QUERY_PUT_BITS_Y_CB_CR_CAPABILITIES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_CREATE , (void**)&vdp_output_surface_create ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_CREATE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY , (void**)&vdp_output_surface_destroy ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY address !!";
	
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_GET_PARAMETERS , (void**)&vdp_output_surface_get_parameters ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_GET_PARAMETERS address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE , (void**)&vdp_output_surface_get_bits_native ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_GET_BITS_NATIVE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE , (void**)&vdp_output_surface_put_bits_native ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED , (void**)&vdp_output_surface_put_bits_indexed ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR , (void**)&vdp_output_surface_put_bits_y_cb_cr ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_Y_CB_CR address !!";
		
	if ( !getFunc( VDP_FUNC_ID_BITMAP_SURFACE_QUERY_CAPABILITIES , (void**)&vdp_bitmap_surface_query_capabilities ) )
		return "Can't get VDP_FUNC_ID_BITMAP_SURFACE_QUERY_CAPABILITIES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_BITMAP_SURFACE_CREATE , (void**)&vdp_bitmap_surface_create ) )
		return "Can't get VDP_FUNC_ID_BITMAP_SURFACE_CREATE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_BITMAP_SURFACE_DESTROY , (void**)&vdp_bitmap_surface_destroy ) )
		return "Can't get VDP_FUNC_ID_BITMAP_SURFACE_DESTROY address !!";
		
	if ( !getFunc( VDP_FUNC_ID_BITMAP_SURFACE_GET_PARAMETERS , (void**)&vdp_bitmap_surface_get_parameters ) )
		return "Can't get VDP_FUNC_ID_BITMAP_SURFACE_GET_PARAMETERS address !!";
		
	if ( !getFunc( VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE , (void**)&vdp_bitmap_surface_put_bits_native ) )
		return "Can't get VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE , (void**)&vdp_output_surface_render_output_surface ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE , (void**)&vdp_output_surface_render_bitmap_surface ) )
		return "Can't get VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES , (void**)&vdp_decoder_query_capabilities ) )
		return "Can't get VDP_FUNC_ID_DECODER_QUERY_CAPABILITIES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_DECODER_CREATE , (void**)&vdp_decoder_create ) )
		return "Can't get VDP_FUNC_ID_DECODER_CREATE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_DECODER_DESTROY , (void**)&vdp_decoder_destroy ) )
		return "Can't get VDP_FUNC_ID_DECODER_DESTROY address !!";
		
	if ( !getFunc( VDP_FUNC_ID_DECODER_GET_PARAMETERS , (void**)&vdp_decoder_get_parameters ) )
		return "Can't get VDP_FUNC_ID_DECODER_GET_PARAMETERS address !!";
		
	if ( !getFunc( VDP_FUNC_ID_DECODER_RENDER , (void**)&vdp_decoder_render ) )
		return "Can't get VDP_FUNC_ID_DECODER_RENDER address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT , (void**)&vdp_video_mixer_query_feature_support ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_QUERY_FEATURE_SUPPORT address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT , (void**)&vdp_video_mixer_query_parameter_support ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_SUPPORT address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_SUPPORT , (void**)&vdp_video_mixer_query_attribute_support ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_SUPPORT address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_VALUE_RANGE , (void**)&vdp_video_mixer_query_parameter_value_range ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_QUERY_PARAMETER_VALUE_RANGE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_VALUE_RANGE , (void**)&vdp_video_mixer_query_attribute_value_range ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_QUERY_ATTRIBUTE_VALUE_RANGE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_CREATE , (void**)&vdp_video_mixer_create ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_CREATE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES , (void**)&vdp_video_mixer_set_feature_enables ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES , (void**)&vdp_video_mixer_set_attribute_values ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_SUPPORT , (void**)&vdp_video_mixer_get_feature_support ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_SUPPORT address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_ENABLES , (void**)&vdp_video_mixer_get_feature_enables ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_GET_FEATURE_ENABLES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_GET_PARAMETER_VALUES , (void**)&vdp_video_mixer_get_parameter_values ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_GET_PARAMETER_VALUES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_GET_ATTRIBUTE_VALUES , (void**)&vdp_video_mixer_get_attribute_values ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_GET_ATTRIBUTE_VALUES address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_DESTROY , (void**)&vdp_video_mixer_destroy ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_DESTROY address !!";
		
	if ( !getFunc( VDP_FUNC_ID_VIDEO_MIXER_RENDER , (void**)&vdp_video_mixer_render ) )
		return "Can't get VDP_FUNC_ID_VIDEO_MIXER_RENDER address !!";
	
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 , (void**)&vdp_presentation_queue_target_create_x11 ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11 address !!";
	
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY , (void**)&vdp_presentation_queue_target_destroy ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY address !!";
		
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE , (void**)&vdp_presentation_queue_create ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY , (void**)&vdp_presentation_queue_destroy ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY address !!";
		
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_SET_BACKGROUND_COLOR , (void**)&vdp_presentation_queue_set_background_color ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_SET_BACKGROUND_COLOR address !!";
		
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_GET_BACKGROUND_COLOR , (void**)&vdp_presentation_queue_get_background_color ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_GET_BACKGROUND_COLOR address !!";
		
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME , (void**)&vdp_presentation_queue_get_time ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_GET_TIME address !!";
		
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY , (void**)&vdp_presentation_queue_display ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY address !!";
		
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE , (void**)&vdp_presentation_queue_block_until_surface_idle ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE address !!";
		
	if ( !getFunc( VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS , (void**)&vdp_presentation_queue_query_surface_status ) )
		return "Can't get VDP_FUNC_ID_PRESENTATION_QUEUE_QUERY_SURFACE_STATUS address !!";
		
	if ( !getFunc( VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER , (void**)&vdp_preemption_callback_register ) )
		return "Can't get VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER address !!";
	
	
	unsigned int tmp;
	vdp_get_api_version( &tmp );
	context.append( QString("VDPAU API version : %1\n").arg(tmp) );

	const char *s;
	st = vdp_get_information_string( &s );
	context.append( QString("VDPAU implementation : %1\n\n").arg(s) );
	
	getDecoderCaps();

#ifdef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
	vdp_video_mixer_query_feature_support( vdpDevice, VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1, &hqScaling );
#endif
	
	return "";
}
Example #3
0
File: avcodec.c Project: etix/vlc
static int Open(vlc_va_t *va, AVCodecContext *avctx, enum PixelFormat pix_fmt,
                const es_format_t *fmt, picture_sys_t *p_sys)
{
    if (pix_fmt != AV_PIX_FMT_VDPAU)
        return VLC_EGENERIC;

    (void) fmt;
    (void) p_sys;
    void *func;
    VdpStatus err;
    VdpChromaType type;
    uint32_t width, height;

    if (av_vdpau_get_surface_parameters(avctx, &type, &width, &height))
        return VLC_EGENERIC;

    switch (type)
    {
        case VDP_CHROMA_TYPE_420:
        case VDP_CHROMA_TYPE_422:
        case VDP_CHROMA_TYPE_444:
            break;
        default:
            msg_Err(va, "unsupported chroma type %"PRIu32, type);
            return VLC_EGENERIC;
    }

    if (!vlc_xlib_init(VLC_OBJECT(va)))
    {
        msg_Err(va, "Xlib is required for VDPAU");
        return VLC_EGENERIC;
    }

    unsigned refs = avctx->refs + 2 * avctx->thread_count + 5;
    vlc_va_sys_t *sys = malloc(sizeof (*sys)
                               + (refs + 1) * sizeof (sys->pool[0]));
    if (unlikely(sys == NULL))
       return VLC_ENOMEM;

    sys->type = type;
    sys->width = width;
    sys->height = height;

    err = vdp_get_x11(NULL, -1, &sys->vdp, &sys->device);
    if (err != VDP_STATUS_OK)
    {
        free(sys);
        return VLC_EGENERIC;
    }

    unsigned flags = AV_HWACCEL_FLAG_ALLOW_HIGH_DEPTH;

    err = vdp_get_proc_address(sys->vdp, sys->device,
                               VDP_FUNC_ID_GET_PROC_ADDRESS, &func);
    if (err != VDP_STATUS_OK)
        goto error;

    if (av_vdpau_bind_context(avctx, sys->device, func, flags))
        goto error;
    va->sys = sys;

    unsigned i = 0;
    while (i < refs)
    {
        sys->pool[i] = CreateSurface(va);
        if (sys->pool[i] == NULL)
            break;
        i++;
    }
    sys->pool[i] = NULL;

    if (i < avctx->refs + 3u)
    {
        msg_Err(va, "not enough video RAM");
        while (i > 0)
            DestroySurface(sys->pool[--i]);
        goto error;
    }

    if (i < refs)
        msg_Warn(va, "video RAM low (allocated %u of %u buffers)",
                 i, refs);

    const char *infos;
    if (vdp_get_information_string(sys->vdp, &infos) != VDP_STATUS_OK)
        infos = "VDPAU";

    va->description = infos;
    va->get = Lock;
    va->release = NULL;
    va->extract = Copy;
    return VLC_SUCCESS;

error:
    vdp_release_x11(sys->vdp);
    free(sys);
    return VLC_EGENERIC;
}