diff options
Diffstat (limited to 'libvo/vo_vdpau.c')
-rw-r--r-- | libvo/vo_vdpau.c | 1864 |
1 files changed, 1083 insertions, 781 deletions
diff --git a/libvo/vo_vdpau.c b/libvo/vo_vdpau.c index 486a6e699f..e613205834 100644 --- a/libvo/vo_vdpau.c +++ b/libvo/vo_vdpau.c @@ -20,58 +20,56 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -/** - * \defgroup VDPAU_Presentation VDPAU Presentation - * \ingroup Decoder - * +/* * Actual decoding and presentation are implemented here. * All necessary frame information is collected through * the "vdpau_render_state" structure after parsing all headers * etc. in libavcodec for different codecs. - * - * @{ */ #include <stdio.h> +#include <stdlib.h> #include <dlfcn.h> +#include <stdint.h> +#include <stdbool.h> #include "config.h" #include "mp_msg.h" +#include "options.h" +#include "talloc.h" #include "video_out.h" -#include "video_out_internal.h" #include "x11_common.h" #include "aspect.h" #include "sub.h" #include "subopt-helper.h" -#include "font_load.h" +#include "libmpcodecs/vfcap.h" +#include "libmpcodecs/mp_image.h" +#include "osdep/timer.h" #include "libavcodec/vdpau.h" +#include "font_load.h" + #include "libavutil/common.h" #include "libavutil/mathematics.h" #include "ass_mp.h" -static vo_info_t info = { - "VDPAU with X11", - "vdpau", - "Rajib Mahapatra <rmahapatra@nvidia.com> and others", - "" -}; - -LIBVO_EXTERN(vdpau) - #define CHECK_ST_ERROR(message) \ - if (vdp_st != VDP_STATUS_OK) { \ - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \ - message, vdp_get_error_string(vdp_st)); \ - return -1; \ - } + do { \ + if (vdp_st != VDP_STATUS_OK) { \ + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \ + message, vdp->get_error_string(vdp_st)); \ + return -1; \ + } \ + } while (0) #define CHECK_ST_WARNING(message) \ - if (vdp_st != VDP_STATUS_OK) \ - mp_msg(MSGT_VO, MSGL_WARN, "[vdpau] %s: %s\n", \ - message, vdp_get_error_string(vdp_st)); + do { \ + if (vdp_st != VDP_STATUS_OK) \ + mp_msg(MSGT_VO, MSGL_WARN, "[ vdpau] %s: %s\n", \ + message, vdp->get_error_string(vdp_st)); \ + } while (0) /* number of video and output surfaces */ #define NUM_OUTPUT_SURFACES 2 @@ -80,423 +78,456 @@ LIBVO_EXTERN(vdpau) /* number of palette entries */ #define PALETTE_SIZE 256 -/* Initial maximum number of EOSD surfaces */ -#define EOSD_SURFACES_INITIAL 512 +/* Initial size of EOSD surface in pixels (x*x) */ +#define EOSD_SURFACE_INITIAL_SIZE 256 /* * Global variable declaration - VDPAU specific */ -/* Declaration for all variables of win_x11_init_vdpau_procs() and - * win_x11_init_vdpau_flip_queue() functions - */ -static VdpDevice vdp_device; -static VdpDeviceCreateX11 *vdp_device_create; -static VdpGetProcAddress *vdp_get_proc_address; +struct vdp_functions { +#define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name; +#include "vdpau_template.c" +#undef VDP_FUNCTION +}; -static VdpPresentationQueueTarget vdp_flip_target; -static VdpPresentationQueue vdp_flip_queue; +struct vdpctx { + struct vdp_functions *vdp; + + VdpDevice vdp_device; + bool is_preempted; + bool preemption_acked; + bool preemption_user_notified; + unsigned int last_preemption_retry_fail; + VdpDeviceCreateX11 *vdp_device_create; + VdpGetProcAddress *vdp_get_proc_address; + + VdpPresentationQueueTarget flip_target; + VdpPresentationQueue flip_queue; + + void *vdpau_lib_handle; + + /* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */ +#define osd_surface vc->output_surfaces[NUM_OUTPUT_SURFACES] + VdpOutputSurface output_surfaces[NUM_OUTPUT_SURFACES + 1]; + VdpVideoSurface deint_surfaces[3]; + double deint_pts[3]; + int deint_queue_pos; + mp_image_t *deint_mpi[3]; + int output_surface_width, output_surface_height; + + VdpVideoMixer video_mixer; + int deint; + int deint_type; + int deint_counter; + int pullup; + float denoise; + float sharpen; + int chroma_deint; + int top_field_first; + + VdpDecoder decoder; + int decoder_max_refs; + + VdpRect src_rect_vid; + VdpRect out_rect_vid; + int border_x, border_y; + + struct vdpau_render_state surface_render[MAX_VIDEO_SURFACES]; + int surface_num; + uint32_t vid_width, vid_height; + uint32_t image_format; + VdpChromaType vdp_chroma_type; + VdpYCbCrFormat vdp_pixel_format; + + /* draw_osd */ + unsigned char *index_data; + int index_data_size; + uint32_t palette[PALETTE_SIZE]; + + // EOSD + // Pool of surfaces + struct eosd_bitmap_surface { + VdpBitmapSurface surface; + int w; + int h; + uint32_t max_width; + uint32_t max_height; + } eosd_surface; + + // List of surfaces to be rendered + struct eosd_target { + VdpRect source; + VdpRect dest; + VdpColor color; + } *eosd_targets; + int eosd_targets_size; + int *eosd_scratch; + + int eosd_render_count; + + // Video equalizer + VdpProcamp procamp; + + bool visible_buf; + bool paused; + + // These tell what's been initialized and uninit() should free/uninitialize + bool mode_switched; +}; -static VdpDeviceDestroy *vdp_device_destroy; -static VdpVideoSurfaceCreate *vdp_video_surface_create; -static VdpVideoSurfaceDestroy *vdp_video_surface_destroy; -static VdpGetErrorString *vdp_get_error_string; +static void flip_page(struct vo *vo); +static int video_to_output_surface(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; + VdpTime dummy; + VdpStatus vdp_st; + if (vc->deint_queue_pos < 0) + return -1; -/* May be used in software filtering/postprocessing options - * in MPlayer (./mplayer -vf ..) if we copy video_surface data to - * system memory. - */ -static VdpVideoSurfacePutBitsYCbCr *vdp_video_surface_put_bits_y_cb_cr; -static VdpOutputSurfacePutBitsNative *vdp_output_surface_put_bits_native; - -static VdpOutputSurfaceCreate *vdp_output_surface_create; -static VdpOutputSurfaceDestroy *vdp_output_surface_destroy; - -/* VideoMixer puts video_surface data on displayable output_surface. */ -static VdpVideoMixerCreate *vdp_video_mixer_create; -static VdpVideoMixerDestroy *vdp_video_mixer_destroy; -static VdpVideoMixerRender *vdp_video_mixer_render; -static VdpVideoMixerSetFeatureEnables *vdp_video_mixer_set_feature_enables; -static VdpVideoMixerSetAttributeValues *vdp_video_mixer_set_attribute_values; - -static VdpPresentationQueueTargetDestroy *vdp_presentation_queue_target_destroy; -static VdpPresentationQueueCreate *vdp_presentation_queue_create; -static VdpPresentationQueueDestroy *vdp_presentation_queue_destroy; -static VdpPresentationQueueDisplay *vdp_presentation_queue_display; -static VdpPresentationQueueBlockUntilSurfaceIdle *vdp_presentation_queue_block_until_surface_idle; -static VdpPresentationQueueTargetCreateX11 *vdp_presentation_queue_target_create_x11; - -static VdpOutputSurfaceRenderOutputSurface *vdp_output_surface_render_output_surface; -static VdpOutputSurfacePutBitsIndexed *vdp_output_surface_put_bits_indexed; -static VdpOutputSurfaceRenderBitmapSurface *vdp_output_surface_render_bitmap_surface; - -static VdpBitmapSurfaceCreate *vdp_bitmap_surface_create; -static VdpBitmapSurfaceDestroy *vdp_bitmap_surface_destroy; -static VdpBitmapSurfacePutBitsNative *vdp_bitmap_surface_putbits_native; - -static VdpDecoderCreate *vdp_decoder_create; -static VdpDecoderDestroy *vdp_decoder_destroy; -static VdpDecoderRender *vdp_decoder_render; - -static VdpGenerateCSCMatrix *vdp_generate_csc_matrix; - -static void *vdpau_lib_handle; -/* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */ -#define osd_surface output_surfaces[NUM_OUTPUT_SURFACES] -static VdpOutputSurface output_surfaces[NUM_OUTPUT_SURFACES + 1]; -static VdpVideoSurface deint_surfaces[3]; -static mp_image_t *deint_mpi[2]; -static int output_surface_width, output_surface_height; - -static VdpVideoMixer video_mixer; -static int deint; -static int deint_type; -static int deint_counter; -static int deint_buffer_past_frames; -static int pullup; -static float denoise; -static float sharpen; -static int chroma_deint; -static int top_field_first; - -static VdpDecoder decoder; -static int decoder_max_refs; - -static VdpRect src_rect_vid; -static VdpRect out_rect_vid; -static int border_x, border_y; - -static struct vdpau_render_state surface_render[MAX_VIDEO_SURFACES]; -static int surface_num; -static int vid_surface_num; -static uint32_t vid_width, vid_height; -static uint32_t image_format; -static VdpChromaType vdp_chroma_type; -static VdpYCbCrFormat vdp_pixel_format; - -/* draw_osd */ -static unsigned char *index_data; -static int index_data_size; -static uint32_t palette[PALETTE_SIZE]; - -// EOSD -// Pool of surfaces -struct { - VdpBitmapSurface surface; - int w; - int h; - char in_use; -} *eosd_surfaces; - -// List of surfaces to be rendered -struct { - VdpBitmapSurface surface; - VdpRect source; - VdpRect dest; - VdpColor color; -} *eosd_targets; - -static int eosd_render_count; -static int eosd_surface_count; - -// Video equalizer -static VdpProcamp procamp; + int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; + unsigned int dp = vc->deint_queue_pos; + // dp==0 means last field of latest frame, 1 earlier field of latest frame, + // 2 last field of previous frame and so on + if (vc->deint) { + field = vc->top_field_first ^ (dp & 1) ? + VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: + VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; + } + VdpVideoSurface *q = vc->deint_surfaces; + const VdpVideoSurface *past_fields = (const VdpVideoSurface []){ + q[(dp+1)/2], q[(dp+2)/2]}; + const VdpVideoSurface *future_fields = (const VdpVideoSurface []){ + q[(dp-1)/2]}; + VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num]; + vdp_st = vdp->presentation_queue_block_until_surface_idle(vc->flip_queue, + output_surface, + &dummy); + CHECK_ST_WARNING("Error when calling " + "vdp_presentation_queue_block_until_surface_idle"); + + vdp_st = vdp->video_mixer_render(vc->video_mixer, VDP_INVALID_HANDLE, + 0, field, 2, past_fields, + vc->deint_surfaces[dp/2], 1, future_fields, + &vc->src_rect_vid, output_surface, + NULL, &vc->out_rect_vid, 0, NULL); + CHECK_ST_WARNING("Error when calling vdp_video_mixer_render"); + return 0; +} -/* - * X11 specific - */ -static int visible_buf; -static int int_pause; +static void add_new_video_surface(struct vo *vo, VdpVideoSurface surface, + struct mp_image *reserved_mpi, double pts) +{ + struct vdpctx *vc = vo->priv; -static void draw_eosd(void); + if (reserved_mpi) + reserved_mpi->usage_count++; + if (vc->deint_mpi[2]) + vc->deint_mpi[2]->usage_count--; -static void push_deint_surface(VdpVideoSurface surface) -{ - deint_surfaces[2] = deint_surfaces[1]; - deint_surfaces[1] = deint_surfaces[0]; - deint_surfaces[0] = surface; + for (int i = 2; i > 0; i--) { + vc->deint_mpi[i] = vc->deint_mpi[i - 1]; + vc->deint_surfaces[i] = vc->deint_surfaces[i - 1]; + vc->deint_pts[i] = vc->deint_pts[i - 1]; + } + vc->deint_mpi[0] = reserved_mpi; + vc->deint_surfaces[0] = surface; + vc->deint_pts[0] = pts; + + vo->frame_loaded = true; + vo->next_pts = pts; + if (vc->deint >= 2 && vc->deint_queue_pos >= 0) { + vc->deint_queue_pos = 2; + double diff = vc->deint_pts[0] - vc->deint_pts[1]; + if (diff > 0 && diff < 0.5) + vo->next_pts = (vc->deint_pts[0] + vc->deint_pts[1]) / 2; + else + vo->next_pts = vc->deint_pts[1]; + } else + vc->deint_queue_pos = 1; + video_to_output_surface(vo); } -static void video_to_output_surface(void) +static void forget_frames(struct vo *vo) { - VdpTime dummy; - VdpStatus vdp_st; - int i; - if (vid_surface_num < 0) - return; - - if (deint < 2 || deint_surfaces[0] == VDP_INVALID_HANDLE) - push_deint_surface(surface_render[vid_surface_num].surface); - - for (i = 0; i <= !!(deint > 1); i++) { - int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME; - VdpOutputSurface output_surface; - if (i) { - draw_eosd(); - draw_osd(); - flip_page(); - } - if (deint) - field = (top_field_first == i) ^ (deint > 1) ? - VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD: - VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD; - output_surface = output_surfaces[surface_num]; - vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue, - output_surface, - &dummy); - CHECK_ST_WARNING("Error when calling vdp_presentation_queue_block_until_surface_idle") - - vdp_st = vdp_video_mixer_render(video_mixer, VDP_INVALID_HANDLE, 0, - field, 2, deint_surfaces + 1, - deint_surfaces[0], - 1, &surface_render[vid_surface_num].surface, - &src_rect_vid, - output_surface, - NULL, &out_rect_vid, 0, NULL); - CHECK_ST_WARNING("Error when calling vdp_video_mixer_render") - push_deint_surface(surface_render[vid_surface_num].surface); + struct vdpctx *vc = vo->priv; + + vc->deint_queue_pos = -1; + for (int i = 0; i < 3; i++) { + vc->deint_surfaces[i] = VDP_INVALID_HANDLE; + if (vc->deint_mpi[i]) + vc->deint_mpi[i]->usage_count--; + vc->deint_mpi[i] = NULL; } } -static void resize(void) +static void resize(struct vo *vo) { + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; VdpStatus vdp_st; int i; struct vo_rect src_rect; struct vo_rect dst_rect; struct vo_rect borders; - calc_src_dst_rects(vid_width, vid_height, &src_rect, &dst_rect, &borders, NULL); - out_rect_vid.x0 = dst_rect.left; - out_rect_vid.x1 = dst_rect.right; - out_rect_vid.y0 = dst_rect.top; - out_rect_vid.y1 = dst_rect.bottom; - src_rect_vid.x0 = src_rect.left; - src_rect_vid.x1 = src_rect.right; - src_rect_vid.y0 = src_rect.top; - src_rect_vid.y1 = src_rect.bottom; - border_x = borders.left; - border_y = borders.top; + calc_src_dst_rects(vo, vc->vid_width, vc->vid_height, &src_rect, &dst_rect, + &borders, NULL); + vc->out_rect_vid.x0 = dst_rect.left; + vc->out_rect_vid.x1 = dst_rect.right; + vc->out_rect_vid.y0 = dst_rect.top; + vc->out_rect_vid.y1 = dst_rect.bottom; + vc->src_rect_vid.x0 = src_rect.left; + vc->src_rect_vid.x1 = src_rect.right; + vc->src_rect_vid.y0 = src_rect.top; + vc->src_rect_vid.y1 = src_rect.bottom; + vc->border_x = borders.left; + vc->border_y = borders.top; #ifdef CONFIG_FREETYPE // adjust font size to display size force_load_font = 1; #endif vo_osd_changed(OSDTYPE_OSD); - if (output_surface_width < vo_dwidth || output_surface_height < vo_dheight) { - if (output_surface_width < vo_dwidth) { - output_surface_width += output_surface_width >> 1; - output_surface_width = FFMAX(output_surface_width, vo_dwidth); + if (vc->output_surface_width < vo->dwidth + || vc->output_surface_height < vo->dheight) { + if (vc->output_surface_width < vo->dwidth) { + vc->output_surface_width += vc->output_surface_width >> 1; + vc->output_surface_width = FFMAX(vc->output_surface_width, + vo->dwidth); } - if (output_surface_height < vo_dheight) { - output_surface_height += output_surface_height >> 1; - output_surface_height = FFMAX(output_surface_height, vo_dheight); + if (vc->output_surface_height < vo->dheight) { + vc->output_surface_height += vc->output_surface_height >> 1; + vc->output_surface_height = FFMAX(vc->output_surface_height, + vo->dheight); } // Creation of output_surfaces for (i = 0; i <= NUM_OUTPUT_SURFACES; i++) { - if (output_surfaces[i] != VDP_INVALID_HANDLE) - vdp_output_surface_destroy(output_surfaces[i]); - vdp_st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8, - output_surface_width, output_surface_height, - &output_surfaces[i]); - CHECK_ST_WARNING("Error when calling vdp_output_surface_create") - mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE: %u\n", output_surfaces[i]); + if (vc->output_surfaces[i] != VDP_INVALID_HANDLE) + vdp->output_surface_destroy(vc->output_surfaces[i]); + vdp_st = vdp->output_surface_create(vc->vdp_device, + VDP_RGBA_FORMAT_B8G8R8A8, + vc->output_surface_width, + vc->output_surface_height, + &vc->output_surfaces[i]); + CHECK_ST_WARNING("Error when calling vdp_output_surface_create"); + mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE: %u\n", + vc->output_surfaces[i]); } } - video_to_output_surface(); - if (visible_buf) - flip_page(); + if (vc->paused && vc->visible_buf) + if (video_to_output_surface(vo) >= 0) + flip_page(vo); +} + +static void preemption_callback(VdpDevice device, void *context) +{ + struct vdpctx *vc = context; + vc->is_preempted = true; + vc->preemption_acked = false; } /* Initialize vdp_get_proc_address, called from preinit() */ -static int win_x11_init_vdpau_procs(void) +static int win_x11_init_vdpau_procs(struct vo *vo) { + struct vo_x11_state *x11 = vo->x11; + struct vdpctx *vc = vo->priv; + talloc_free(vc->vdp); // In case this is reinitialization after preemption + struct vdp_functions *vdp = talloc_zero(vc, struct vdp_functions); + vc->vdp = vdp; VdpStatus vdp_st; struct vdp_function { const int id; - void *pointer; + int offset; }; const struct vdp_function *dsc; static const struct vdp_function vdp_func[] = { - {VDP_FUNC_ID_GET_ERROR_STRING, &vdp_get_error_string}, - {VDP_FUNC_ID_DEVICE_DESTROY, &vdp_device_destroy}, - {VDP_FUNC_ID_VIDEO_SURFACE_CREATE, &vdp_video_surface_create}, - {VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, &vdp_video_surface_destroy}, - {VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR, - &vdp_video_surface_put_bits_y_cb_cr}, - {VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE, - &vdp_output_surface_put_bits_native}, - {VDP_FUNC_ID_OUTPUT_SURFACE_CREATE, &vdp_output_surface_create}, - {VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY, &vdp_output_surface_destroy}, - {VDP_FUNC_ID_VIDEO_MIXER_CREATE, &vdp_video_mixer_create}, - {VDP_FUNC_ID_VIDEO_MIXER_DESTROY, &vdp_video_mixer_destroy}, - {VDP_FUNC_ID_VIDEO_MIXER_RENDER, &vdp_video_mixer_render}, - {VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES, - &vdp_video_mixer_set_feature_enables}, - {VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES, - &vdp_video_mixer_set_attribute_values}, - {VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY, - &vdp_presentation_queue_target_destroy}, - {VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE, &vdp_presentation_queue_create}, - {VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY, - &vdp_presentation_queue_destroy}, - {VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY, - &vdp_presentation_queue_display}, - {VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE, - &vdp_presentation_queue_block_until_surface_idle}, - {VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11, - &vdp_presentation_queue_target_create_x11}, - {VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE, - &vdp_output_surface_render_output_surface}, - {VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED, - &vdp_output_surface_put_bits_indexed}, - {VDP_FUNC_ID_DECODER_CREATE, &vdp_decoder_create}, - {VDP_FUNC_ID_DECODER_RENDER, &vdp_decoder_render}, - {VDP_FUNC_ID_DECODER_DESTROY, &vdp_decoder_destroy}, - {VDP_FUNC_ID_BITMAP_SURFACE_CREATE, &vdp_bitmap_surface_create}, - {VDP_FUNC_ID_BITMAP_SURFACE_DESTROY, &vdp_bitmap_surface_destroy}, - {VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE, - &vdp_bitmap_surface_putbits_native}, - {VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE, - &vdp_output_surface_render_bitmap_surface}, - {VDP_FUNC_ID_GENERATE_CSC_MATRIX, &vdp_generate_csc_matrix}, - {0, NULL} +#define VDP_FUNCTION(_, macro_name, mp_name) {macro_name, offsetof(struct vdp_functions, mp_name)}, +#include "vdpau_template.c" +#undef VDP_FUNCTION + {0, -1} }; - vdp_st = vdp_device_create(mDisplay, mScreen, - &vdp_device, &vdp_get_proc_address); + vdp_st = vc->vdp_device_create(x11->display, x11->screen,&vc->vdp_device, + &vc->vdp_get_proc_address); if (vdp_st != VDP_STATUS_OK) { - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling vdp_device_create_x11: %i\n", vdp_st); + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling " + "vdp_device_create_x11: %i\n", vdp_st); return -1; } - vdp_get_error_string = NULL; - for (dsc = vdp_func; dsc->pointer; dsc++) { - vdp_st = vdp_get_proc_address(vdp_device, dsc->id, dsc->pointer); + vdp->get_error_string = NULL; + for (dsc = vdp_func; dsc->offset >= 0; dsc++) { + vdp_st = vc->vdp_get_proc_address(vc->vdp_device, dsc->id, + (void **)((char *)vdp + dsc->offset)); if (vdp_st != VDP_STATUS_OK) { - mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling vdp_get_proc_address(function id %d): %s\n", dsc->id, vdp_get_error_string ? vdp_get_error_string(vdp_st) : "?"); + mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling " + "vdp_get_proc_address(function id %d): %s\n", dsc->id, + vdp->get_error_string ? vdp->get_error_string(vdp_st) : "?"); return -1; } } + vdp_st = vdp->preemption_callback_register(vc->vdp_device, + preemption_callback, vc); return 0; } -/* Initialize vdpau_flip_queue, called from config() */ -static int win_x11_init_vdpau_flip_queue(void) +static int win_x11_init_vdpau_flip_queue(struct vo *vo) { + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; + struct vo_x11_state *x11 = vo->x11; VdpStatus vdp_st; - vdp_st = vdp_presentation_queue_target_create_x11(vdp_device, vo_window, - &vdp_flip_target); - CHECK_ST_ERROR("Error when calling vdp_presentation_queue_target_create_x11") + if (vc->flip_target == VDP_INVALID_HANDLE) { + vdp_st = vdp->presentation_queue_target_create_x11(vc->vdp_device, + x11->window, + &vc->flip_target); + CHECK_ST_ERROR("Error when calling " + "vdp_presentation_queue_target_create_x11"); + } - vdp_st = vdp_presentation_queue_create(vdp_device, vdp_flip_target, - &vdp_flip_queue); - CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create") + /* Emperically this seems to be the first call which fails when we + * try to reinit after preemption while the user is still switched + * from X to a virtual terminal (creating the vdp_device initially + * succeeds, as does creating the flip_target above). This is + * probably not guaranteed behavior, but we'll assume it as a simple + * way to reduce warnings while trying to recover from preemption. + */ + if (vc->flip_queue == VDP_INVALID_HANDLE) { + vdp_st = vdp->presentation_queue_create(vc->vdp_device, vc->flip_target, + &vc->flip_queue); + if (vc->is_preempted && vdp_st != VDP_STATUS_OK) { + mp_msg(MSGT_VO, MSGL_DBG2, "[vdpau] Failed to create flip queue " + "while preempted: %s\n", vdp->get_error_string(vdp_st)); + return -1; + } else + CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create"); + } return 0; } -static int create_vdp_mixer(VdpChromaType vdp_chroma_type) { +static int create_vdp_mixer(struct vo *vo, VdpChromaType vdp_chroma_type) +{ + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; #define VDP_NUM_MIXER_PARAMETER 3 #define MAX_NUM_FEATURES 5 int i; VdpStatus vdp_st; + + if (vc->video_mixer != VDP_INVALID_HANDLE) + return 0; + int feature_count = 0; VdpVideoMixerFeature features[MAX_NUM_FEATURES]; VdpBool feature_enables[MAX_NUM_FEATURES]; - static const VdpVideoMixerAttribute denoise_attrib[] = {VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL}; - const void * const denoise_value[] = {&denoise}; - static const VdpVideoMixerAttribute sharpen_attrib[] = {VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL}; - const void * const sharpen_value[] = {&sharpen}; - static const VdpVideoMixerAttribute skip_chroma_attrib[] = {VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE}; + static const VdpVideoMixerAttribute denoise_attrib[] = + {VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL}; + const void * const denoise_value[] = {&vc->denoise}; + static const VdpVideoMixerAttribute sharpen_attrib[] = + {VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL}; + const void * const sharpen_value[] = {&vc->sharpen}; + static const VdpVideoMixerAttribute skip_chroma_attrib[] = + {VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE}; const uint8_t skip_chroma_value = 1; const void * const skip_chroma_value_ptr[] = {&skip_chroma_value}; static const VdpVideoMixerParameter parameters[VDP_NUM_MIXER_PARAMETER] = { VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH, VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT, - VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE + VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE, }; const void *const parameter_values[VDP_NUM_MIXER_PARAMETER] = { - &vid_width, - &vid_height, - &vdp_chroma_type + &vc->vid_width, + &vc->vid_height, + &vdp_chroma_type, }; features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL; - if (deint == 4) - features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL; - if (pullup) + if (vc->deint == 4) + features[feature_count++] = + VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL; + if (vc->pullup) features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE; - if (denoise) + if (vc->denoise) features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION; - if (sharpen) + if (vc->sharpen) features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS; - vdp_st = vdp_video_mixer_create(vdp_device, feature_count, features, - VDP_NUM_MIXER_PARAMETER, - parameters, parameter_values, - &video_mixer); - CHECK_ST_ERROR("Error when calling vdp_video_mixer_create") + vdp_st = vdp->video_mixer_create(vc->vdp_device, feature_count, features, + VDP_NUM_MIXER_PARAMETER, + parameters, parameter_values, + &vc->video_mixer); + CHECK_ST_ERROR("Error when calling vdp_video_mixer_create"); - for (i = 0; i < feature_count; i++) feature_enables[i] = VDP_TRUE; - if (deint < 3) + for (i = 0; i < feature_count; i++) + feature_enables[i] = VDP_TRUE; + if (vc->deint < 3) feature_enables[0] = VDP_FALSE; if (feature_count) - vdp_video_mixer_set_feature_enables(video_mixer, feature_count, features, feature_enables); - if (denoise) - vdp_video_mixer_set_attribute_values(video_mixer, 1, denoise_attrib, denoise_value); - if (sharpen) - vdp_video_mixer_set_attribute_values(video_mixer, 1, sharpen_attrib, sharpen_value); - if (!chroma_deint) - vdp_video_mixer_set_attribute_values(video_mixer, 1, skip_chroma_attrib, skip_chroma_value_ptr); + vdp->video_mixer_set_feature_enables(vc->video_mixer, feature_count, + features, feature_enables); + if (vc->denoise) + vdp->video_mixer_set_attribute_values(vc->video_mixer, 1, + denoise_attrib, denoise_value); + if (vc->sharpen) + vdp->video_mixer_set_attribute_values(vc->video_mixer, 1, + sharpen_attrib, sharpen_value); + if (!vc->chroma_deint) + vdp->video_mixer_set_attribute_values(vc->video_mixer, 1, + skip_chroma_attrib, + skip_chroma_value_ptr); return 0; } // Free everything specific to a certain video file -static void free_video_specific(void) { +static void free_video_specific(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; int i; VdpStatus vdp_st; - if (decoder != VDP_INVALID_HANDLE) - vdp_decoder_destroy(decoder); - decoder = VDP_INVALID_HANDLE; - decoder_max_refs = -1; - - for (i = 0; i < 3; i++) - deint_surfaces[i] = VDP_INVALID_HANDLE; + if (vc->decoder != VDP_INVALID_HANDLE) + vdp->decoder_destroy(vc->decoder); + vc->decoder = VDP_INVALID_HANDLE; + vc->decoder_max_refs = -1; for (i = 0; i < 2; i++) - if (deint_mpi[i]) { - deint_mpi[i]->usage_count--; - deint_mpi[i] = NULL; + if (vc->deint_mpi[i]) { + vc->deint_mpi[i]->usage_count--; + vc->deint_mpi[i] = NULL; } for (i = 0; i < MAX_VIDEO_SURFACES; i++) { - if (surface_render[i].surface != VDP_INVALID_HANDLE) { - vdp_st = vdp_video_surface_destroy(surface_render[i].surface); - CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy") + if (vc->surface_render[i].surface != VDP_INVALID_HANDLE) { + vdp_st = vdp->video_surface_destroy(vc->surface_render[i].surface); + CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy"); } - surface_render[i].surface = VDP_INVALID_HANDLE; + vc->surface_render[i].surface = VDP_INVALID_HANDLE; } - if (video_mixer != VDP_INVALID_HANDLE) { - vdp_st = vdp_video_mixer_destroy(video_mixer); - CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy") + if (vc->video_mixer != VDP_INVALID_HANDLE) { + vdp_st = vdp->video_mixer_destroy(vc->video_mixer); + CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy"); } - video_mixer = VDP_INVALID_HANDLE; + vc->video_mixer = VDP_INVALID_HANDLE; } -static int create_vdp_decoder(int max_refs) +static int create_vdp_decoder(struct vo *vo, int max_refs) { + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; VdpStatus vdp_st; VdpDecoderProfile vdp_decoder_profile; - if (decoder != VDP_INVALID_HANDLE) - vdp_decoder_destroy(decoder); - switch (image_format) { + if (vc->decoder != VDP_INVALID_HANDLE) + vdp->decoder_destroy(vc->decoder); + switch (vc->image_format) { case IMGFMT_VDPAU_MPEG1: vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1; break; @@ -505,7 +536,8 @@ static int create_vdp_decoder(int max_refs) break; case IMGFMT_VDPAU_H264: vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH; - mp_msg(MSGT_VO, MSGL_V, "[vdpau] Creating H264 hardware decoder for %d reference frames.\n", max_refs); + mp_msg(MSGT_VO, MSGL_V, "[vdpau] Creating H264 hardware decoder " + "for %d reference frames.\n", max_refs); break; case IMGFMT_VDPAU_WMV3: vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN; @@ -514,15 +546,111 @@ static int create_vdp_decoder(int max_refs) vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED; break; } - vdp_st = vdp_decoder_create(vdp_device, vdp_decoder_profile, - vid_width, vid_height, max_refs, &decoder); + vdp_st = vdp->decoder_create(vc->vdp_device, vdp_decoder_profile, + vc->vid_width, vc->vid_height, max_refs, + &vc->decoder); CHECK_ST_WARNING("Failed creating VDPAU decoder"); if (vdp_st != VDP_STATUS_OK) { - decoder = VDP_INVALID_HANDLE; - decoder_max_refs = 0; + vc->decoder = VDP_INVALID_HANDLE; + vc->decoder_max_refs = 0; return 0; } - decoder_max_refs = max_refs; + vc->decoder_max_refs = max_refs; + return 1; +} + +int initialize_vdpau_objects(struct vo *vo) +{ + struct vdpctx *vc = vo->priv; + struct vdp_functions *vdp = vc->vdp; + VdpStatus vdp_st; + + vc->vdp_chroma_type = VDP_CHROMA_TYPE_420; + switch (vc->image_format) { + case IMGFMT_YV12: + case IMGFMT_I420: + case IMGFMT_IYUV: + vc->vdp_pixel_format = VDP_YCBCR_FORMAT_YV12; + break; + case IMGFMT_NV12: + vc->vdp_pixel_format = VDP_YCBCR_FORMAT_NV12; + break; + case IMGFMT_YUY2: + vc->vdp_pixel_format = VDP_YCBCR_FORMAT_YUYV; + vc->vdp_chroma_type = VDP_CHROMA_TYPE_422; + |