2 * VDPAU video output driver
4 * Copyright (C) 2008 NVIDIA
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * \defgroup VDPAU_Presentation VDPAU Presentation
27 * Actual decoding and presentation are implemented here.
28 * All necessary frame information is collected through
29 * the "vdpau_render_state" structure after parsing all headers
30 * etc. in libavcodec for different codecs.
40 #include "video_out.h"
41 #include "video_out_internal.h"
42 #include "x11_common.h"
45 #include "subopt-helper.h"
47 #include "libavcodec/vdpau.h"
49 #include "gui/interface.h"
51 #include "libavutil/common.h"
53 #include "libass/ass.h"
54 #include "libass/ass_mp.h"
56 static vo_info_t info
= {
59 "Rajib Mahapatra <rmahapatra@nvidia.com> and others",
65 #define CHECK_ST_ERROR(message) \
66 if (vdp_st != VDP_STATUS_OK) { \
67 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \
68 message, vdp_get_error_string(vdp_st)); \
72 #define CHECK_ST_WARNING(message) \
73 if (vdp_st != VDP_STATUS_OK) \
74 mp_msg(MSGT_VO, MSGL_WARN, "[vdpau] %s: %s\n", \
75 message, vdp_get_error_string(vdp_st));
77 /* number of video and output surfaces */
78 #define NUM_OUTPUT_SURFACES 2
79 #define MAX_VIDEO_SURFACES 50
81 /* number of palette entries */
82 #define PALETTE_SIZE 256
84 /* Initial maximum number of EOSD surfaces */
85 #define EOSD_SURFACES_INITIAL 512
88 * Global variable declaration - VDPAU specific
91 /* Declaration for all variables of win_x11_init_vdpau_procs() and
92 * win_x11_init_vdpau_flip_queue() functions
94 static VdpDevice vdp_device
;
95 static VdpDeviceCreateX11
*vdp_device_create
;
96 static VdpGetProcAddress
*vdp_get_proc_address
;
98 static VdpPresentationQueueTarget vdp_flip_target
;
99 static VdpPresentationQueue vdp_flip_queue
;
101 static VdpDeviceDestroy
*vdp_device_destroy
;
102 static VdpVideoSurfaceCreate
*vdp_video_surface_create
;
103 static VdpVideoSurfaceDestroy
*vdp_video_surface_destroy
;
105 static VdpGetErrorString
*vdp_get_error_string
;
107 /* May be used in software filtering/postprocessing options
108 * in MPlayer (./mplayer -vf ..) if we copy video_surface data to
111 static VdpVideoSurfacePutBitsYCbCr
*vdp_video_surface_put_bits_y_cb_cr
;
112 static VdpOutputSurfacePutBitsNative
*vdp_output_surface_put_bits_native
;
114 static VdpOutputSurfaceCreate
*vdp_output_surface_create
;
115 static VdpOutputSurfaceDestroy
*vdp_output_surface_destroy
;
117 /* VideoMixer puts video_surface data on displayable output_surface. */
118 static VdpVideoMixerCreate
*vdp_video_mixer_create
;
119 static VdpVideoMixerDestroy
*vdp_video_mixer_destroy
;
120 static VdpVideoMixerRender
*vdp_video_mixer_render
;
121 static VdpVideoMixerSetFeatureEnables
*vdp_video_mixer_set_feature_enables
;
122 static VdpVideoMixerSetAttributeValues
*vdp_video_mixer_set_attribute_values
;
124 static VdpPresentationQueueTargetDestroy
*vdp_presentation_queue_target_destroy
;
125 static VdpPresentationQueueCreate
*vdp_presentation_queue_create
;
126 static VdpPresentationQueueDestroy
*vdp_presentation_queue_destroy
;
127 static VdpPresentationQueueDisplay
*vdp_presentation_queue_display
;
128 static VdpPresentationQueueBlockUntilSurfaceIdle
*vdp_presentation_queue_block_until_surface_idle
;
129 static VdpPresentationQueueTargetCreateX11
*vdp_presentation_queue_target_create_x11
;
131 static VdpOutputSurfaceRenderOutputSurface
*vdp_output_surface_render_output_surface
;
132 static VdpOutputSurfacePutBitsIndexed
*vdp_output_surface_put_bits_indexed
;
133 static VdpOutputSurfaceRenderBitmapSurface
*vdp_output_surface_render_bitmap_surface
;
135 static VdpBitmapSurfaceCreate
*vdp_bitmap_surface_create
;
136 static VdpBitmapSurfaceDestroy
*vdp_bitmap_surface_destroy
;
137 static VdpBitmapSurfacePutBitsNative
*vdp_bitmap_surface_putbits_native
;
139 static VdpDecoderCreate
*vdp_decoder_create
;
140 static VdpDecoderDestroy
*vdp_decoder_destroy
;
141 static VdpDecoderRender
*vdp_decoder_render
;
143 static void *vdpau_lib_handle
;
144 /* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */
145 #define osd_surface output_surfaces[NUM_OUTPUT_SURFACES]
146 static VdpOutputSurface output_surfaces
[NUM_OUTPUT_SURFACES
+ 1];
147 static int output_surface_width
, output_surface_height
;
149 static VdpVideoMixer video_mixer
;
151 static int deint_type
;
153 static float denoise
;
154 static float sharpen
;
155 static int top_field_first
;
157 static VdpDecoder decoder
;
158 static int decoder_max_refs
;
160 static VdpRect src_rect_vid
;
161 static VdpRect out_rect_vid
;
162 static int border_x
, border_y
;
164 static struct vdpau_render_state surface_render
[MAX_VIDEO_SURFACES
];
165 static int surface_num
;
166 static int vid_surface_num
;
167 static uint32_t vid_width
, vid_height
;
168 static uint32_t image_format
;
169 static const VdpChromaType vdp_chroma_type
= VDP_CHROMA_TYPE_420
;
172 static unsigned char *index_data
;
173 static int index_data_size
;
174 static uint32_t palette
[PALETTE_SIZE
];
179 VdpBitmapSurface surface
;
185 // List of surfaces to be rendered
187 VdpBitmapSurface surface
;
193 static int eosd_render_count
;
194 static int eosd_surface_count
;
199 static int visible_buf
;
200 static int int_pause
;
202 static void video_to_output_surface(void)
207 if (vid_surface_num
< 0)
210 // we would need to provide 2 past and 1 future frames to allow advanced
211 // deinterlacing, which is not really possible currently.
212 for (i
= 0; i
<= !!(deint
> 1); i
++) {
213 int field
= VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME
;
214 VdpOutputSurface output_surface
;
218 field
= top_field_first
== i
?
219 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD
:
220 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD
;
221 output_surface
= output_surfaces
[surface_num
];
222 vdp_st
= vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue
,
225 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_block_until_surface_idle")
227 vdp_st
= vdp_video_mixer_render(video_mixer
, VDP_INVALID_HANDLE
, 0,
229 surface_render
[vid_surface_num
].surface
,
230 0, NULL
, &src_rect_vid
,
232 NULL
, &out_rect_vid
, 0, NULL
);
233 CHECK_ST_WARNING("Error when calling vdp_video_mixer_render")
237 static void resize(void)
241 struct vo_rect src_rect
;
242 struct vo_rect dst_rect
;
243 struct vo_rect borders
;
244 calc_src_dst_rects(vid_width
, vid_height
, &src_rect
, &dst_rect
, &borders
, NULL
);
245 out_rect_vid
.x0
= dst_rect
.left
;
246 out_rect_vid
.x1
= dst_rect
.right
;
247 out_rect_vid
.y0
= dst_rect
.top
;
248 out_rect_vid
.y1
= dst_rect
.bottom
;
249 src_rect_vid
.x0
= src_rect
.left
;
250 src_rect_vid
.x1
= src_rect
.right
;
251 src_rect_vid
.y0
= src_rect
.top
;
252 src_rect_vid
.y1
= src_rect
.bottom
;
253 border_x
= borders
.left
;
254 border_y
= borders
.top
;
255 #ifdef CONFIG_FREETYPE
256 // adjust font size to display size
259 vo_osd_changed(OSDTYPE_OSD
);
261 if (output_surface_width
< vo_dwidth
|| output_surface_height
< vo_dheight
) {
262 if (output_surface_width
< vo_dwidth
) {
263 output_surface_width
+= output_surface_width
>> 1;
264 output_surface_width
= FFMAX(output_surface_width
, vo_dwidth
);
266 if (output_surface_height
< vo_dheight
) {
267 output_surface_height
+= output_surface_height
>> 1;
268 output_surface_height
= FFMAX(output_surface_height
, vo_dheight
);
270 // Creation of output_surfaces
271 for (i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++) {
272 if (output_surfaces
[i
] != VDP_INVALID_HANDLE
)
273 vdp_output_surface_destroy(output_surfaces
[i
]);
274 vdp_st
= vdp_output_surface_create(vdp_device
, VDP_RGBA_FORMAT_B8G8R8A8
,
275 output_surface_width
, output_surface_height
,
276 &output_surfaces
[i
]);
277 CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
278 mp_msg(MSGT_VO
, MSGL_DBG2
, "OUT CREATE: %u\n", output_surfaces
[i
]);
281 video_to_output_surface();
286 /* Initialize vdp_get_proc_address, called from preinit() */
287 static int win_x11_init_vdpau_procs(void)
291 struct vdp_function
{
296 const struct vdp_function
*dsc
;
298 static const struct vdp_function vdp_func
[] = {
299 {VDP_FUNC_ID_GET_ERROR_STRING
, &vdp_get_error_string
},
300 {VDP_FUNC_ID_DEVICE_DESTROY
, &vdp_device_destroy
},
301 {VDP_FUNC_ID_VIDEO_SURFACE_CREATE
, &vdp_video_surface_create
},
302 {VDP_FUNC_ID_VIDEO_SURFACE_DESTROY
, &vdp_video_surface_destroy
},
303 {VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR
,
304 &vdp_video_surface_put_bits_y_cb_cr
},
305 {VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE
,
306 &vdp_output_surface_put_bits_native
},
307 {VDP_FUNC_ID_OUTPUT_SURFACE_CREATE
, &vdp_output_surface_create
},
308 {VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY
, &vdp_output_surface_destroy
},
309 {VDP_FUNC_ID_VIDEO_MIXER_CREATE
, &vdp_video_mixer_create
},
310 {VDP_FUNC_ID_VIDEO_MIXER_DESTROY
, &vdp_video_mixer_destroy
},
311 {VDP_FUNC_ID_VIDEO_MIXER_RENDER
, &vdp_video_mixer_render
},
312 {VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES
,
313 &vdp_video_mixer_set_feature_enables
},
314 {VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES
,
315 &vdp_video_mixer_set_attribute_values
},
316 {VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY
,
317 &vdp_presentation_queue_target_destroy
},
318 {VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE
, &vdp_presentation_queue_create
},
319 {VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY
,
320 &vdp_presentation_queue_destroy
},
321 {VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY
,
322 &vdp_presentation_queue_display
},
323 {VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE
,
324 &vdp_presentation_queue_block_until_surface_idle
},
325 {VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11
,
326 &vdp_presentation_queue_target_create_x11
},
327 {VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE
,
328 &vdp_output_surface_render_output_surface
},
329 {VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED
,
330 &vdp_output_surface_put_bits_indexed
},
331 {VDP_FUNC_ID_DECODER_CREATE
, &vdp_decoder_create
},
332 {VDP_FUNC_ID_DECODER_RENDER
, &vdp_decoder_render
},
333 {VDP_FUNC_ID_DECODER_DESTROY
, &vdp_decoder_destroy
},
334 {VDP_FUNC_ID_BITMAP_SURFACE_CREATE
, &vdp_bitmap_surface_create
},
335 {VDP_FUNC_ID_BITMAP_SURFACE_DESTROY
, &vdp_bitmap_surface_destroy
},
336 {VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE
,
337 &vdp_bitmap_surface_putbits_native
},
338 {VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE
,
339 &vdp_output_surface_render_bitmap_surface
},
343 vdp_st
= vdp_device_create(mDisplay
, mScreen
,
344 &vdp_device
, &vdp_get_proc_address
);
345 if (vdp_st
!= VDP_STATUS_OK
) {
346 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling vdp_device_create_x11: %i\n", vdp_st
);
350 for (dsc
= vdp_func
; dsc
->pointer
; dsc
++) {
351 vdp_st
= vdp_get_proc_address(vdp_device
, dsc
->id
, dsc
->pointer
);
352 if (vdp_st
!= VDP_STATUS_OK
) {
353 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
) : "?");
360 /* Initialize vdpau_flip_queue, called from config() */
361 static int win_x11_init_vdpau_flip_queue(void)
365 vdp_st
= vdp_presentation_queue_target_create_x11(vdp_device
, vo_window
,
367 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_target_create_x11")
369 vdp_st
= vdp_presentation_queue_create(vdp_device
, vdp_flip_target
,
371 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create")
376 static int create_vdp_mixer(VdpChromaType vdp_chroma_type
) {
377 #define VDP_NUM_MIXER_PARAMETER 3
378 #define MAX_NUM_FEATURES 5
381 int feature_count
= 0;
382 VdpVideoMixerFeature features
[MAX_NUM_FEATURES
];
383 VdpBool feature_enables
[MAX_NUM_FEATURES
];
384 static const VdpVideoMixerAttribute denoise_attrib
[] = {VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL
};
385 const void * const denoise_value
[] = {&denoise
};
386 static const VdpVideoMixerAttribute sharpen_attrib
[] = {VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL
};
387 const void * const sharpen_value
[] = {&sharpen
};
388 static const VdpVideoMixerParameter parameters
[VDP_NUM_MIXER_PARAMETER
] = {
389 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
,
390 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
,
391 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
393 const void *const parameter_values
[VDP_NUM_MIXER_PARAMETER
] = {
399 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
;
401 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
;
403 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
;
405 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
;
407 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS
;
409 vdp_st
= vdp_video_mixer_create(vdp_device
, feature_count
, features
,
410 VDP_NUM_MIXER_PARAMETER
,
411 parameters
, parameter_values
,
413 CHECK_ST_ERROR("Error when calling vdp_video_mixer_create")
415 for (i
= 0; i
< feature_count
; i
++) feature_enables
[i
] = VDP_TRUE
;
417 vdp_video_mixer_set_feature_enables(video_mixer
, feature_count
, features
, feature_enables
);
419 vdp_video_mixer_set_attribute_values(video_mixer
, 1, denoise_attrib
, denoise_value
);
421 vdp_video_mixer_set_attribute_values(video_mixer
, 1, sharpen_attrib
, sharpen_value
);
426 // Free everything specific to a certain video file
427 static void free_video_specific(void) {
431 if (decoder
!= VDP_INVALID_HANDLE
)
432 vdp_decoder_destroy(decoder
);
433 decoder
= VDP_INVALID_HANDLE
;
434 decoder_max_refs
= -1;
436 for (i
= 0; i
< MAX_VIDEO_SURFACES
; i
++) {
437 if (surface_render
[i
].surface
!= VDP_INVALID_HANDLE
) {
438 vdp_st
= vdp_video_surface_destroy(surface_render
[i
].surface
);
439 CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy")
441 surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
444 if (video_mixer
!= VDP_INVALID_HANDLE
) {
445 vdp_st
= vdp_video_mixer_destroy(video_mixer
);
446 CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy")
448 video_mixer
= VDP_INVALID_HANDLE
;
452 * connect to X server, create and map window, initialize all
453 * VDPAU objects, create different surfaces etc.
455 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
456 uint32_t d_height
, uint32_t flags
, char *title
,
460 XSetWindowAttributes xswa
;
461 XWindowAttributes attribs
;
462 unsigned long xswamask
;
466 int vm
= flags
& VOFLAG_MODESWITCHING
;
469 image_format
= format
;
476 guiGetEvent(guiSetShVideo
, 0); // the GUI will set up / resize our window
485 XGetWindowAttributes(mDisplay
, DefaultRootWindow(mDisplay
), &attribs
);
486 depth
= attribs
.depth
;
487 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
489 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
491 xswa
.background_pixel
= 0;
492 xswa
.border_pixel
= 0;
493 xswamask
= CWBackPixel
| CWBorderPixel
;
495 vo_x11_create_vo_window(&vinfo
, vo_dx
, vo_dy
, d_width
, d_height
,
496 flags
, CopyFromParent
, "vdpau", title
);
497 XChangeWindowAttributes(mDisplay
, vo_window
, xswamask
, &xswa
);
501 /* Grab the mouse pointer in our window */
503 XGrabPointer(mDisplay
, vo_window
, True
, 0,
504 GrabModeAsync
, GrabModeAsync
,
505 vo_window
, None
, CurrentTime
);
506 XSetInputFocus(mDisplay
, vo_window
, RevertToNone
, CurrentTime
);
511 if ((flags
& VOFLAG_FULLSCREEN
) && WinID
<= 0)
514 /* -----VDPAU related code here -------- */
516 free_video_specific();
518 if (vdp_flip_queue
== VDP_INVALID_HANDLE
&& win_x11_init_vdpau_flip_queue())
521 // video width and height
525 if (create_vdp_mixer(vdp_chroma_type
))
529 vid_surface_num
= -1;
535 static void check_events(void)
537 int e
= vo_x11_check_events(mDisplay
);
539 if (e
& VO_EVENT_RESIZE
)
542 if ((e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
) && int_pause
) {
543 /* did we already draw a buffer */
545 /* redraw the last visible buffer */
547 vdp_st
= vdp_presentation_queue_display(vdp_flip_queue
,
548 output_surfaces
[surface_num
],
549 vo_dwidth
, vo_dheight
,
551 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
556 static void draw_osd_I8A8(int x0
,int y0
, int w
,int h
, unsigned char *src
,
557 unsigned char *srca
, int stride
)
559 VdpOutputSurface output_surface
= output_surfaces
[surface_num
];
563 int index_data_size_required
;
564 VdpRect output_indexed_rect_vid
;
565 VdpOutputSurfaceRenderBlendState blend_state
;
570 index_data_size_required
= 2*w
*h
;
571 if (index_data_size
< index_data_size_required
) {
572 index_data
= realloc(index_data
, index_data_size_required
);
573 index_data_size
= index_data_size_required
;
576 // index_data creation, component order - I, A, I, A, .....
577 for (i
= 0; i
< h
; i
++)
578 for (j
= 0; j
< w
; j
++) {
579 index_data
[i
*2*w
+ j
*2] = src
[i
*stride
+j
];
580 index_data
[i
*2*w
+ j
*2 + 1] = -srca
[i
*stride
+j
];
583 output_indexed_rect_vid
.x0
= x0
;
584 output_indexed_rect_vid
.y0
= y0
;
585 output_indexed_rect_vid
.x1
= x0
+ w
;
586 output_indexed_rect_vid
.y1
= y0
+ h
;
590 // write source_data to osd_surface.
591 vdp_st
= vdp_output_surface_put_bits_indexed(osd_surface
,
592 VDP_INDEXED_FORMAT_I8A8
,
593 (const void *const*)&index_data
,
595 &output_indexed_rect_vid
,
596 VDP_COLOR_TABLE_FORMAT_B8G8R8X8
,
598 CHECK_ST_WARNING("Error when calling vdp_output_surface_put_bits_indexed")
600 blend_state
.struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
;
601 blend_state
.blend_factor_source_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
;
602 blend_state
.blend_factor_source_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
;
603 blend_state
.blend_factor_destination_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
;
604 blend_state
.blend_factor_destination_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
;
605 blend_state
.blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
;
606 blend_state
.blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
;
608 vdp_st
= vdp_output_surface_render_output_surface(output_surface
,
609 &output_indexed_rect_vid
,
611 &output_indexed_rect_vid
,
614 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
615 CHECK_ST_WARNING("Error when calling vdp_output_surface_render_output_surface")
618 static void draw_eosd(void) {
620 VdpOutputSurface output_surface
= output_surfaces
[surface_num
];
621 VdpOutputSurfaceRenderBlendState blend_state
;
624 blend_state
.struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
;
625 blend_state
.blend_factor_source_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
;
626 blend_state
.blend_factor_source_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
;
627 blend_state
.blend_factor_destination_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
;
628 blend_state
.blend_factor_destination_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
;
629 blend_state
.blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
;
630 blend_state
.blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
;
632 for (i
=0; i
<eosd_render_count
; i
++) {
633 vdp_st
= vdp_output_surface_render_bitmap_surface(
634 output_surface
, &eosd_targets
[i
].dest
,
635 eosd_targets
[i
].surface
, &eosd_targets
[i
].source
,
636 &eosd_targets
[i
].color
, &blend_state
,
637 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
638 CHECK_ST_WARNING("EOSD: Error when rendering")
642 static void generate_eosd(mp_eosd_images_t
*imgs
) {
646 ass_image_t
*img
= imgs
->imgs
;
649 // Nothing changed, no need to redraw
650 if (imgs
->changed
== 0)
652 eosd_render_count
= 0;
653 // There's nothing to render!
657 if (imgs
->changed
== 1)
658 goto eosd_skip_upload
;
660 for (j
=0; j
<eosd_surface_count
; j
++)
661 eosd_surfaces
[j
].in_use
= 0;
663 for (i
= img
; i
; i
= i
->next
) {
664 // Try to reuse a suitable surface
666 for (j
=0; j
<eosd_surface_count
; j
++) {
667 if (eosd_surfaces
[j
].surface
!= VDP_INVALID_HANDLE
&& !eosd_surfaces
[j
].in_use
&&
668 eosd_surfaces
[j
].w
>= i
->w
&& eosd_surfaces
[j
].h
>= i
->h
) {
673 // None found, allocate a new surface
675 for (j
=0; j
<eosd_surface_count
; j
++) {
676 if (!eosd_surfaces
[j
].in_use
) {
677 if (eosd_surfaces
[j
].surface
!= VDP_INVALID_HANDLE
)
678 vdp_bitmap_surface_destroy(eosd_surfaces
[j
].surface
);
683 // Allocate new space for surface/target arrays
685 j
= found
= eosd_surface_count
;
686 eosd_surface_count
= eosd_surface_count
? eosd_surface_count
*2 : EOSD_SURFACES_INITIAL
;
687 eosd_surfaces
= realloc(eosd_surfaces
, eosd_surface_count
* sizeof(*eosd_surfaces
));
688 eosd_targets
= realloc(eosd_targets
, eosd_surface_count
* sizeof(*eosd_targets
));
689 for(j
=found
; j
<eosd_surface_count
; j
++) {
690 eosd_surfaces
[j
].surface
= VDP_INVALID_HANDLE
;
691 eosd_surfaces
[j
].in_use
= 0;
694 vdp_st
= vdp_bitmap_surface_create(vdp_device
, VDP_RGBA_FORMAT_A8
,
695 i
->w
, i
->h
, VDP_TRUE
, &eosd_surfaces
[found
].surface
);
696 CHECK_ST_WARNING("EOSD: error when creating surface")
697 eosd_surfaces
[found
].w
= i
->w
;
698 eosd_surfaces
[found
].h
= i
->h
;
700 eosd_surfaces
[found
].in_use
= 1;
701 eosd_targets
[eosd_render_count
].surface
= eosd_surfaces
[found
].surface
;
706 vdp_st
= vdp_bitmap_surface_putbits_native(eosd_targets
[eosd_render_count
].surface
,
707 (const void *) &i
->bitmap
, &i
->stride
, &destRect
);
708 CHECK_ST_WARNING("EOSD: putbits failed")
713 eosd_render_count
= 0;
714 for (i
= img
; i
; i
= i
->next
) {
715 // Render dest, color, etc.
716 eosd_targets
[eosd_render_count
].color
.alpha
= 1.0 - ((i
->color
>> 0) & 0xff) / 255.0;
717 eosd_targets
[eosd_render_count
].color
.blue
= ((i
->color
>> 8) & 0xff) / 255.0;
718 eosd_targets
[eosd_render_count
].color
.green
= ((i
->color
>> 16) & 0xff) / 255.0;
719 eosd_targets
[eosd_render_count
].color
.red
= ((i
->color
>> 24) & 0xff) / 255.0;
720 eosd_targets
[eosd_render_count
].dest
.x0
= i
->dst_x
;
721 eosd_targets
[eosd_render_count
].dest
.y0
= i
->dst_y
;
722 eosd_targets
[eosd_render_count
].dest
.x1
= i
->w
+ i
->dst_x
;
723 eosd_targets
[eosd_render_count
].dest
.y1
= i
->h
+ i
->dst_y
;
724 eosd_targets
[eosd_render_count
].source
.x0
= 0;
725 eosd_targets
[eosd_render_count
].source
.y0
= 0;
726 eosd_targets
[eosd_render_count
].source
.x1
= i
->w
;
727 eosd_targets
[eosd_render_count
].source
.y1
= i
->h
;
732 static void draw_osd(void)
734 mp_msg(MSGT_VO
, MSGL_DBG2
, "DRAW_OSD\n");
737 vo_draw_text_ext(vo_dwidth
, vo_dheight
, border_x
, border_y
, border_x
, border_y
,
738 vid_width
, vid_height
, draw_osd_I8A8
);
741 static void flip_page(void)
744 mp_msg(MSGT_VO
, MSGL_DBG2
, "\nFLIP_PAGE VID:%u -> OUT:%u\n",
745 surface_render
[vid_surface_num
].surface
, output_surfaces
[surface_num
]);
747 vdp_st
= vdp_presentation_queue_display(vdp_flip_queue
, output_surfaces
[surface_num
],
748 vo_dwidth
, vo_dheight
,
750 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
752 surface_num
= (surface_num
+ 1) % NUM_OUTPUT_SURFACES
;
756 static int draw_slice(uint8_t *image
[], int stride
[], int w
, int h
,
760 struct vdpau_render_state
*rndr
= (struct vdpau_render_state
*)image
[0];
761 int max_refs
= image_format
== IMGFMT_VDPAU_H264
? rndr
->info
.h264
.num_ref_frames
: 2;
762 if (!IMGFMT_IS_VDPAU(image_format
))
764 if (decoder
== VDP_INVALID_HANDLE
|| decoder_max_refs
< max_refs
) {
765 VdpDecoderProfile vdp_decoder_profile
;
766 if (decoder
!= VDP_INVALID_HANDLE
)
767 vdp_decoder_destroy(decoder
);
768 decoder
= VDP_INVALID_HANDLE
;
769 switch (image_format
) {
770 case IMGFMT_VDPAU_MPEG1
:
771 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG1
;
773 case IMGFMT_VDPAU_MPEG2
:
774 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG2_MAIN
;
776 case IMGFMT_VDPAU_H264
:
777 vdp_decoder_profile
= VDP_DECODER_PROFILE_H264_HIGH
;
779 case IMGFMT_VDPAU_WMV3
:
780 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_MAIN
;
782 case IMGFMT_VDPAU_VC1
:
783 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_ADVANCED
;
786 vdp_st
= vdp_decoder_create(vdp_device
, vdp_decoder_profile
, vid_width
, vid_height
, max_refs
, &decoder
);
787 CHECK_ST_WARNING("Failed creating VDPAU decoder");
788 if (vdp_st
!= VDP_STATUS_OK
) {
789 decoder
= VDP_INVALID_HANDLE
;
790 decoder_max_refs
= 0;
793 decoder_max_refs
= max_refs
;
795 vdp_st
= vdp_decoder_render(decoder
, rndr
->surface
, (void *)&rndr
->info
, rndr
->bitstream_buffers_used
, rndr
->bitstream_buffers
);
796 CHECK_ST_WARNING("Failed VDPAU decoder rendering");
801 static int draw_frame(uint8_t *src
[])
806 static struct vdpau_render_state
*get_surface(int number
)
808 if (number
> MAX_VIDEO_SURFACES
)
810 if (surface_render
[number
].surface
== VDP_INVALID_HANDLE
) {
812 vdp_st
= vdp_video_surface_create(vdp_device
, vdp_chroma_type
,
813 vid_width
, vid_height
,
814 &surface_render
[number
].surface
);
815 CHECK_ST_WARNING("Error when calling vdp_video_surface_create")
816 if (vdp_st
!= VDP_STATUS_OK
)
819 mp_msg(MSGT_VO
, MSGL_DBG2
, "VID CREATE: %u\n", surface_render
[number
].surface
);
820 return &surface_render
[number
];
823 static uint32_t draw_image(mp_image_t
*mpi
)
825 if (IMGFMT_IS_VDPAU(image_format
)) {
826 struct vdpau_render_state
*rndr
= mpi
->priv
;
827 vid_surface_num
= rndr
- surface_render
;
828 } else if (!(mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)) {
830 void *destdata
[3] = {mpi
->planes
[0], mpi
->planes
[2], mpi
->planes
[1]};
831 struct vdpau_render_state
*rndr
= get_surface(0);
832 vid_surface_num
= rndr
- surface_render
;
833 vdp_st
= vdp_video_surface_put_bits_y_cb_cr(rndr
->surface
,
834 VDP_YCBCR_FORMAT_YV12
,
835 (const void *const*)destdata
,
836 mpi
->stride
); // pitch
837 CHECK_ST_ERROR("Error when calling vdp_video_surface_put_bits_y_cb_cr")
839 top_field_first
= !!(mpi
->fields
& MP_IMGFIELD_TOP_FIRST
);
841 video_to_output_surface();
845 static uint32_t get_image(mp_image_t
*mpi
)
847 struct vdpau_render_state
*rndr
;
849 // no dr for non-decoding for now
850 if (!IMGFMT_IS_VDPAU(image_format
)) return VO_FALSE
;
851 if (mpi
->type
!= MP_IMGTYPE_NUMBERED
) return VO_FALSE
;
853 rndr
= get_surface(mpi
->number
);
855 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] no surfaces available in get_image\n");
856 // TODO: this probably breaks things forever, provide a dummy buffer?
859 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
860 mpi
->stride
[0] = mpi
->stride
[1] = mpi
->stride
[2] = 0;
861 mpi
->planes
[0] = mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
862 // hack to get around a check and to avoid a special-case in vd_ffmpeg.c
863 mpi
->planes
[0] = (void *)rndr
;
869 static int query_format(uint32_t format
)
871 int default_flags
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_OSD
| VFCAP_EOSD
| VFCAP_EOSD_UNSCALED
;
874 return default_flags
| VOCAP_NOSLICES
;
875 case IMGFMT_VDPAU_MPEG1
:
876 case IMGFMT_VDPAU_MPEG2
:
877 case IMGFMT_VDPAU_H264
:
878 case IMGFMT_VDPAU_WMV3
:
879 case IMGFMT_VDPAU_VC1
:
880 return default_flags
;
885 static void DestroyVdpauObjects(void)
890 free_video_specific();
892 vdp_st
= vdp_presentation_queue_destroy(vdp_flip_queue
);
893 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy")
895 vdp_st
= vdp_presentation_queue_target_destroy(vdp_flip_target
);
896 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_target_destroy")
898 for (i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++) {
899 vdp_st
= vdp_output_surface_destroy(output_surfaces
[i
]);
900 output_surfaces
[i
] = VDP_INVALID_HANDLE
;
901 CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy")
904 for (i
= 0; i
<eosd_surface_count
; i
++) {
905 if (eosd_surfaces
[i
].surface
!= VDP_INVALID_HANDLE
) {
906 vdp_st
= vdp_bitmap_surface_destroy(eosd_surfaces
[i
].surface
);
907 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy")
909 eosd_surfaces
[i
].surface
= VDP_INVALID_HANDLE
;
912 vdp_st
= vdp_device_destroy(vdp_device
);
913 CHECK_ST_WARNING("Error when calling vdp_device_destroy")
916 static void uninit(void)
918 if (!vo_config_count
)
922 /* Destroy all vdpau objects */
923 DestroyVdpauObjects();
929 eosd_surfaces
= NULL
;
938 dlclose(vdpau_lib_handle
);
941 static opt_t subopts
[] = {
942 {"deint", OPT_ARG_INT
, &deint
, (opt_test_f
)int_non_neg
},
943 {"pullup", OPT_ARG_BOOL
, &pullup
, NULL
},
944 {"denoise", OPT_ARG_FLOAT
, &denoise
, NULL
},
945 {"sharpen", OPT_ARG_FLOAT
, &sharpen
, NULL
},
949 static const char help_msg
[] =
950 "\n-vo vdpau command line help:\n"
951 "Example: mplayer -vo vdpau:deint=2\n"
953 " deint (all modes > 0 respect -field-dominance)\n"
954 " 0: no deinterlacing\n"
955 " 1: only show first field\n"
956 " 2: bob deinterlacing (current fallback)\n"
957 " 3: temporal deinterlacing (not yet working)\n"
958 " 4: temporal-spatial deinterlacing (not yet working)\n"
960 " Try to apply inverse-telecine (needs deinterlacing, not working)\n"
962 " Apply denoising, argument is strength from 0.0 to 1.0\n"
964 " Apply sharpening or softening, argument is strength from -1.0 to 1.0\n"
967 static int preinit(const char *arg
)
970 static const char *vdpaulibrary
= "libvdpau.so.1";
971 static const char *vdpau_device_create
= "vdp_device_create_x11";
978 if (subopt_parse(arg
, subopts
) != 0) {
979 mp_msg(MSGT_VO
, MSGL_FATAL
, help_msg
);
985 vdpau_lib_handle
= dlopen(vdpaulibrary
, RTLD_LAZY
);
986 if (!vdpau_lib_handle
) {
987 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Could not open dynamic library %s\n",
991 vdp_device_create
= dlsym(vdpau_lib_handle
, vdpau_device_create
);
992 if (!vdp_device_create
) {
993 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Could not find function %s in %s\n",
994 vdpau_device_create
, vdpaulibrary
);
997 if (!vo_init() || win_x11_init_vdpau_procs())
1000 decoder
= VDP_INVALID_HANDLE
;
1001 for (i
= 0; i
< MAX_VIDEO_SURFACES
; i
++)
1002 surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
1003 video_mixer
= VDP_INVALID_HANDLE
;
1004 for (i
= 0; i
< NUM_OUTPUT_SURFACES
; i
++)
1005 output_surfaces
[i
] = VDP_INVALID_HANDLE
;
1006 vdp_flip_queue
= VDP_INVALID_HANDLE
;
1007 output_surface_width
= output_surface_height
= -1;
1009 // full grayscale palette.
1010 for (i
= 0; i
< PALETTE_SIZE
; ++i
)
1011 palette
[i
] = (i
<< 16) | (i
<< 8) | i
;
1013 index_data_size
= 0;
1015 eosd_surface_count
= eosd_render_count
= 0;
1016 eosd_surfaces
= NULL
;
1017 eosd_targets
= NULL
;
1022 static int control(uint32_t request
, void *data
, ...)
1025 case VOCTRL_GET_DEINTERLACE
:
1026 *(int*)data
= deint
;
1028 case VOCTRL_SET_DEINTERLACE
:
1029 deint
= *(int*)data
;
1034 return (int_pause
= 1);
1036 return (int_pause
= 0);
1037 case VOCTRL_QUERY_FORMAT
:
1038 return query_format(*(uint32_t *)data
);
1039 case VOCTRL_GET_IMAGE
:
1040 return get_image(data
);
1041 case VOCTRL_DRAW_IMAGE
:
1042 return draw_image(data
);
1043 case VOCTRL_GUISUPPORT
:
1049 case VOCTRL_FULLSCREEN
:
1050 vo_x11_fullscreen();
1053 case VOCTRL_GET_PANSCAN
:
1055 case VOCTRL_SET_PANSCAN
:
1058 case VOCTRL_SET_EQUALIZER
: {
1063 value
= va_arg(ap
, int);
1066 return vo_x11_set_equalizer(data
, value
);
1068 case VOCTRL_GET_EQUALIZER
: {
1073 value
= va_arg(ap
, int *);
1076 return vo_x11_get_equalizer(data
, value
);
1081 case VOCTRL_UPDATE_SCREENINFO
:
1082 update_xinerama_info();
1084 case VOCTRL_DRAW_EOSD
:
1087 generate_eosd(data
);
1089 case VOCTRL_GET_EOSD_RES
: {
1090 mp_eosd_res_t
*r
= data
;
1091 r
->mt
= r
->mb
= r
->ml
= r
->mr
= 0;
1093 r
->w
= vo_screenwidth
;
1094 r
->h
= vo_screenheight
;
1095 r
->ml
= r
->mr
= border_x
;
1096 r
->mt
= r
->mb
= border_y
;