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
;
152 static float denoise
;
153 static float sharpen
;
154 static int top_field_first
;
156 static VdpDecoder decoder
;
157 static int decoder_max_refs
;
159 static VdpRect src_rect_vid
;
160 static VdpRect out_rect_vid
;
161 static int border_x
, border_y
;
163 static struct vdpau_render_state surface_render
[MAX_VIDEO_SURFACES
];
164 static int surface_num
;
165 static int vid_surface_num
;
166 static uint32_t vid_width
, vid_height
;
167 static uint32_t image_format
;
168 static const VdpChromaType vdp_chroma_type
= VDP_CHROMA_TYPE_420
;
171 static unsigned char *index_data
;
172 static int index_data_size
;
173 static uint32_t palette
[PALETTE_SIZE
];
178 VdpBitmapSurface surface
;
184 // List of surfaces to be rendered
186 VdpBitmapSurface surface
;
192 static int eosd_render_count
;
193 static int eosd_surface_count
;
198 static int visible_buf
;
199 static int int_pause
;
201 static void video_to_output_surface(void)
206 if (vid_surface_num
< 0)
209 // we would need to provide 2 past and 1 future frames to allow advanced
210 // deinterlacing, which is not really possible currently.
211 for (i
= 0; i
<= !!deint
; i
++) {
212 int field
= VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME
;
213 VdpOutputSurface output_surface
;
217 field
= top_field_first
== i
?
218 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD
:
219 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD
;
220 output_surface
= output_surfaces
[surface_num
];
221 vdp_st
= vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue
,
224 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_block_until_surface_idle")
226 vdp_st
= vdp_video_mixer_render(video_mixer
, VDP_INVALID_HANDLE
, 0,
228 surface_render
[vid_surface_num
].surface
,
229 0, NULL
, &src_rect_vid
,
231 NULL
, &out_rect_vid
, 0, NULL
);
232 CHECK_ST_WARNING("Error when calling vdp_video_mixer_render")
236 static void resize(void)
240 struct vo_rect src_rect
;
241 struct vo_rect dst_rect
;
242 struct vo_rect borders
;
243 calc_src_dst_rects(vid_width
, vid_height
, &src_rect
, &dst_rect
, &borders
, NULL
);
244 out_rect_vid
.x0
= dst_rect
.left
;
245 out_rect_vid
.x1
= dst_rect
.right
;
246 out_rect_vid
.y0
= dst_rect
.top
;
247 out_rect_vid
.y1
= dst_rect
.bottom
;
248 src_rect_vid
.x0
= src_rect
.left
;
249 src_rect_vid
.x1
= src_rect
.right
;
250 src_rect_vid
.y0
= src_rect
.top
;
251 src_rect_vid
.y1
= src_rect
.bottom
;
252 border_x
= borders
.left
;
253 border_y
= borders
.top
;
254 #ifdef CONFIG_FREETYPE
255 // adjust font size to display size
258 vo_osd_changed(OSDTYPE_OSD
);
260 if (output_surface_width
< vo_dwidth
|| output_surface_height
< vo_dheight
) {
261 if (output_surface_width
< vo_dwidth
) {
262 output_surface_width
+= output_surface_width
>> 1;
263 output_surface_width
= FFMAX(output_surface_width
, vo_dwidth
);
265 if (output_surface_height
< vo_dheight
) {
266 output_surface_height
+= output_surface_height
>> 1;
267 output_surface_height
= FFMAX(output_surface_height
, vo_dheight
);
269 // Creation of output_surfaces
270 for (i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++) {
271 if (output_surfaces
[i
] != VDP_INVALID_HANDLE
)
272 vdp_output_surface_destroy(output_surfaces
[i
]);
273 vdp_st
= vdp_output_surface_create(vdp_device
, VDP_RGBA_FORMAT_B8G8R8A8
,
274 output_surface_width
, output_surface_height
,
275 &output_surfaces
[i
]);
276 CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
277 mp_msg(MSGT_VO
, MSGL_DBG2
, "OUT CREATE: %u\n", output_surfaces
[i
]);
280 video_to_output_surface();
285 /* Initialize vdp_get_proc_address, called from preinit() */
286 static int win_x11_init_vdpau_procs(void)
290 struct vdp_function
{
295 const struct vdp_function
*dsc
;
297 static const struct vdp_function vdp_func
[] = {
298 {VDP_FUNC_ID_GET_ERROR_STRING
, &vdp_get_error_string
},
299 {VDP_FUNC_ID_DEVICE_DESTROY
, &vdp_device_destroy
},
300 {VDP_FUNC_ID_VIDEO_SURFACE_CREATE
, &vdp_video_surface_create
},
301 {VDP_FUNC_ID_VIDEO_SURFACE_DESTROY
, &vdp_video_surface_destroy
},
302 {VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR
,
303 &vdp_video_surface_put_bits_y_cb_cr
},
304 {VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE
,
305 &vdp_output_surface_put_bits_native
},
306 {VDP_FUNC_ID_OUTPUT_SURFACE_CREATE
, &vdp_output_surface_create
},
307 {VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY
, &vdp_output_surface_destroy
},
308 {VDP_FUNC_ID_VIDEO_MIXER_CREATE
, &vdp_video_mixer_create
},
309 {VDP_FUNC_ID_VIDEO_MIXER_DESTROY
, &vdp_video_mixer_destroy
},
310 {VDP_FUNC_ID_VIDEO_MIXER_RENDER
, &vdp_video_mixer_render
},
311 {VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES
,
312 &vdp_video_mixer_set_feature_enables
},
313 {VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES
,
314 &vdp_video_mixer_set_attribute_values
},
315 {VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY
,
316 &vdp_presentation_queue_target_destroy
},
317 {VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE
, &vdp_presentation_queue_create
},
318 {VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY
,
319 &vdp_presentation_queue_destroy
},
320 {VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY
,
321 &vdp_presentation_queue_display
},
322 {VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE
,
323 &vdp_presentation_queue_block_until_surface_idle
},
324 {VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11
,
325 &vdp_presentation_queue_target_create_x11
},
326 {VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE
,
327 &vdp_output_surface_render_output_surface
},
328 {VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED
,
329 &vdp_output_surface_put_bits_indexed
},
330 {VDP_FUNC_ID_DECODER_CREATE
, &vdp_decoder_create
},
331 {VDP_FUNC_ID_DECODER_RENDER
, &vdp_decoder_render
},
332 {VDP_FUNC_ID_DECODER_DESTROY
, &vdp_decoder_destroy
},
333 {VDP_FUNC_ID_BITMAP_SURFACE_CREATE
, &vdp_bitmap_surface_create
},
334 {VDP_FUNC_ID_BITMAP_SURFACE_DESTROY
, &vdp_bitmap_surface_destroy
},
335 {VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE
,
336 &vdp_bitmap_surface_putbits_native
},
337 {VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE
,
338 &vdp_output_surface_render_bitmap_surface
},
342 vdp_st
= vdp_device_create(mDisplay
, mScreen
,
343 &vdp_device
, &vdp_get_proc_address
);
344 if (vdp_st
!= VDP_STATUS_OK
) {
345 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling vdp_device_create_x11: %i\n", vdp_st
);
349 for (dsc
= vdp_func
; dsc
->pointer
; dsc
++) {
350 vdp_st
= vdp_get_proc_address(vdp_device
, dsc
->id
, dsc
->pointer
);
351 if (vdp_st
!= VDP_STATUS_OK
) {
352 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
) : "?");
359 /* Initialize vdpau_flip_queue, called from config() */
360 static int win_x11_init_vdpau_flip_queue(void)
364 vdp_st
= vdp_presentation_queue_target_create_x11(vdp_device
, vo_window
,
366 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_target_create_x11")
368 vdp_st
= vdp_presentation_queue_create(vdp_device
, vdp_flip_target
,
370 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create")
375 static int create_vdp_mixer(VdpChromaType vdp_chroma_type
) {
376 #define VDP_NUM_MIXER_PARAMETER 3
377 #define MAX_NUM_FEATURES 5
380 int feature_count
= 0;
381 VdpVideoMixerFeature features
[MAX_NUM_FEATURES
];
382 VdpBool feature_enables
[MAX_NUM_FEATURES
];
383 static const VdpVideoMixerAttribute denoise_attrib
[] = {VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL
};
384 const void * const denoise_value
[] = {&denoise
};
385 static const VdpVideoMixerAttribute sharpen_attrib
[] = {VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL
};
386 const void * const sharpen_value
[] = {&sharpen
};
387 static const VdpVideoMixerParameter parameters
[VDP_NUM_MIXER_PARAMETER
] = {
388 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
,
389 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
,
390 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
392 const void *const parameter_values
[VDP_NUM_MIXER_PARAMETER
] = {
398 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
;
400 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
;
402 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
;
404 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
;
406 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS
;
408 vdp_st
= vdp_video_mixer_create(vdp_device
, feature_count
, features
,
409 VDP_NUM_MIXER_PARAMETER
,
410 parameters
, parameter_values
,
412 CHECK_ST_ERROR("Error when calling vdp_video_mixer_create")
414 for (i
= 0; i
< feature_count
; i
++) feature_enables
[i
] = VDP_TRUE
;
416 vdp_video_mixer_set_feature_enables(video_mixer
, feature_count
, features
, feature_enables
);
418 vdp_video_mixer_set_attribute_values(video_mixer
, 1, denoise_attrib
, denoise_value
);
420 vdp_video_mixer_set_attribute_values(video_mixer
, 1, sharpen_attrib
, sharpen_value
);
425 // Free everything specific to a certain video file
426 static void free_video_specific(void) {
430 if (decoder
!= VDP_INVALID_HANDLE
)
431 vdp_decoder_destroy(decoder
);
432 decoder
= VDP_INVALID_HANDLE
;
433 decoder_max_refs
= -1;
435 for (i
= 0; i
< MAX_VIDEO_SURFACES
; i
++) {
436 if (surface_render
[i
].surface
!= VDP_INVALID_HANDLE
) {
437 vdp_st
= vdp_video_surface_destroy(surface_render
[i
].surface
);
438 CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy")
440 surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
443 if (video_mixer
!= VDP_INVALID_HANDLE
) {
444 vdp_st
= vdp_video_mixer_destroy(video_mixer
);
445 CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy")
447 video_mixer
= VDP_INVALID_HANDLE
;
451 * connect to X server, create and map window, initialize all
452 * VDPAU objects, create different surfaces etc.
454 static int config(uint32_t width
, uint32_t height
, uint32_t d_width
,
455 uint32_t d_height
, uint32_t flags
, char *title
,
459 XSetWindowAttributes xswa
;
460 XWindowAttributes attribs
;
461 unsigned long xswamask
;
465 int vm
= flags
& VOFLAG_MODESWITCHING
;
468 image_format
= format
;
475 guiGetEvent(guiSetShVideo
, 0); // the GUI will set up / resize our window
484 XGetWindowAttributes(mDisplay
, DefaultRootWindow(mDisplay
), &attribs
);
485 depth
= attribs
.depth
;
486 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
488 XMatchVisualInfo(mDisplay
, mScreen
, depth
, TrueColor
, &vinfo
);
490 xswa
.background_pixel
= 0;
491 xswa
.border_pixel
= 0;
492 xswamask
= CWBackPixel
| CWBorderPixel
;
494 vo_x11_create_vo_window(&vinfo
, vo_dx
, vo_dy
, d_width
, d_height
,
495 flags
, CopyFromParent
, "vdpau", title
);
496 XChangeWindowAttributes(mDisplay
, vo_window
, xswamask
, &xswa
);
500 /* Grab the mouse pointer in our window */
502 XGrabPointer(mDisplay
, vo_window
, True
, 0,
503 GrabModeAsync
, GrabModeAsync
,
504 vo_window
, None
, CurrentTime
);
505 XSetInputFocus(mDisplay
, vo_window
, RevertToNone
, CurrentTime
);
510 if ((flags
& VOFLAG_FULLSCREEN
) && WinID
<= 0)
513 /* -----VDPAU related code here -------- */
515 free_video_specific();
517 if (vdp_flip_queue
== VDP_INVALID_HANDLE
&& win_x11_init_vdpau_flip_queue())
520 // video width and height
524 if (create_vdp_mixer(vdp_chroma_type
))
528 vid_surface_num
= -1;
534 static void check_events(void)
536 int e
= vo_x11_check_events(mDisplay
);
538 if (e
& VO_EVENT_RESIZE
)
541 if ((e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
) && int_pause
) {
542 /* did we already draw a buffer */
544 /* redraw the last visible buffer */
546 vdp_st
= vdp_presentation_queue_display(vdp_flip_queue
,
547 output_surfaces
[surface_num
],
548 vo_dwidth
, vo_dheight
,
550 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
555 static void draw_osd_I8A8(int x0
,int y0
, int w
,int h
, unsigned char *src
,
556 unsigned char *srca
, int stride
)
558 VdpOutputSurface output_surface
= output_surfaces
[surface_num
];
562 int index_data_size_required
;
563 VdpRect output_indexed_rect_vid
;
564 VdpOutputSurfaceRenderBlendState blend_state
;
569 index_data_size_required
= 2*w
*h
;
570 if (index_data_size
< index_data_size_required
) {
571 index_data
= realloc(index_data
, index_data_size_required
);
572 index_data_size
= index_data_size_required
;
575 // index_data creation, component order - I, A, I, A, .....
576 for (i
= 0; i
< h
; i
++)
577 for (j
= 0; j
< w
; j
++) {
578 index_data
[i
*2*w
+ j
*2] = src
[i
*stride
+j
];
579 index_data
[i
*2*w
+ j
*2 + 1] = -srca
[i
*stride
+j
];
582 output_indexed_rect_vid
.x0
= x0
;
583 output_indexed_rect_vid
.y0
= y0
;
584 output_indexed_rect_vid
.x1
= x0
+ w
;
585 output_indexed_rect_vid
.y1
= y0
+ h
;
589 // write source_data to osd_surface.
590 vdp_st
= vdp_output_surface_put_bits_indexed(osd_surface
,
591 VDP_INDEXED_FORMAT_I8A8
,
592 (const void *const*)&index_data
,
594 &output_indexed_rect_vid
,
595 VDP_COLOR_TABLE_FORMAT_B8G8R8X8
,
597 CHECK_ST_WARNING("Error when calling vdp_output_surface_put_bits_indexed")
599 blend_state
.struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
;
600 blend_state
.blend_factor_source_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
;
601 blend_state
.blend_factor_source_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
;
602 blend_state
.blend_factor_destination_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
;
603 blend_state
.blend_factor_destination_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
;
604 blend_state
.blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
;
605 blend_state
.blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
;
607 vdp_st
= vdp_output_surface_render_output_surface(output_surface
,
608 &output_indexed_rect_vid
,
610 &output_indexed_rect_vid
,
613 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
614 CHECK_ST_WARNING("Error when calling vdp_output_surface_render_output_surface")
617 static void draw_eosd(void) {
619 VdpOutputSurface output_surface
= output_surfaces
[surface_num
];
620 VdpOutputSurfaceRenderBlendState blend_state
;
623 blend_state
.struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
;
624 blend_state
.blend_factor_source_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
;
625 blend_state
.blend_factor_source_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
;
626 blend_state
.blend_factor_destination_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
;
627 blend_state
.blend_factor_destination_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
;
628 blend_state
.blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
;
629 blend_state
.blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
;
631 for (i
=0; i
<eosd_render_count
; i
++) {
632 vdp_st
= vdp_output_surface_render_bitmap_surface(
633 output_surface
, &eosd_targets
[i
].dest
,
634 eosd_targets
[i
].surface
, &eosd_targets
[i
].source
,
635 &eosd_targets
[i
].color
, &blend_state
,
636 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
637 CHECK_ST_WARNING("EOSD: Error when rendering")
641 static void generate_eosd(mp_eosd_images_t
*imgs
) {
645 ass_image_t
*img
= imgs
->imgs
;
648 // Nothing changed, no need to redraw
649 if (imgs
->changed
== 0)
651 eosd_render_count
= 0;
652 // There's nothing to render!
656 if (imgs
->changed
== 1)
657 goto eosd_skip_upload
;
659 for (j
=0; j
<eosd_surface_count
; j
++)
660 eosd_surfaces
[j
].in_use
= 0;
662 for (i
= img
; i
; i
= i
->next
) {
663 // Try to reuse a suitable surface
665 for (j
=0; j
<eosd_surface_count
; j
++) {
666 if (eosd_surfaces
[j
].surface
!= VDP_INVALID_HANDLE
&& !eosd_surfaces
[j
].in_use
&&
667 eosd_surfaces
[j
].w
>= i
->w
&& eosd_surfaces
[j
].h
>= i
->h
) {
672 // None found, allocate a new surface
674 for (j
=0; j
<eosd_surface_count
; j
++) {
675 if (!eosd_surfaces
[j
].in_use
) {
676 if (eosd_surfaces
[j
].surface
!= VDP_INVALID_HANDLE
)
677 vdp_bitmap_surface_destroy(eosd_surfaces
[j
].surface
);
682 // Allocate new space for surface/target arrays
684 j
= found
= eosd_surface_count
;
685 eosd_surface_count
= eosd_surface_count
? eosd_surface_count
*2 : EOSD_SURFACES_INITIAL
;
686 eosd_surfaces
= realloc(eosd_surfaces
, eosd_surface_count
* sizeof(*eosd_surfaces
));
687 eosd_targets
= realloc(eosd_targets
, eosd_surface_count
* sizeof(*eosd_targets
));
688 for(j
=found
; j
<eosd_surface_count
; j
++) {
689 eosd_surfaces
[j
].surface
= VDP_INVALID_HANDLE
;
690 eosd_surfaces
[j
].in_use
= 0;
693 vdp_st
= vdp_bitmap_surface_create(vdp_device
, VDP_RGBA_FORMAT_A8
,
694 i
->w
, i
->h
, VDP_TRUE
, &eosd_surfaces
[found
].surface
);
695 CHECK_ST_WARNING("EOSD: error when creating surface")
696 eosd_surfaces
[found
].w
= i
->w
;
697 eosd_surfaces
[found
].h
= i
->h
;
699 eosd_surfaces
[found
].in_use
= 1;
700 eosd_targets
[eosd_render_count
].surface
= eosd_surfaces
[found
].surface
;
705 vdp_st
= vdp_bitmap_surface_putbits_native(eosd_targets
[eosd_render_count
].surface
,
706 (const void *) &i
->bitmap
, &i
->stride
, &destRect
);
707 CHECK_ST_WARNING("EOSD: putbits failed")
712 eosd_render_count
= 0;
713 for (i
= img
; i
; i
= i
->next
) {
714 // Render dest, color, etc.
715 eosd_targets
[eosd_render_count
].color
.alpha
= 1.0 - ((i
->color
>> 0) & 0xff) / 255.0;
716 eosd_targets
[eosd_render_count
].color
.blue
= ((i
->color
>> 8) & 0xff) / 255.0;
717 eosd_targets
[eosd_render_count
].color
.green
= ((i
->color
>> 16) & 0xff) / 255.0;
718 eosd_targets
[eosd_render_count
].color
.red
= ((i
->color
>> 24) & 0xff) / 255.0;
719 eosd_targets
[eosd_render_count
].dest
.x0
= i
->dst_x
;
720 eosd_targets
[eosd_render_count
].dest
.y0
= i
->dst_y
;
721 eosd_targets
[eosd_render_count
].dest
.x1
= i
->w
+ i
->dst_x
;
722 eosd_targets
[eosd_render_count
].dest
.y1
= i
->h
+ i
->dst_y
;
723 eosd_targets
[eosd_render_count
].source
.x0
= 0;
724 eosd_targets
[eosd_render_count
].source
.y0
= 0;
725 eosd_targets
[eosd_render_count
].source
.x1
= i
->w
;
726 eosd_targets
[eosd_render_count
].source
.y1
= i
->h
;
731 static void draw_osd(void)
733 mp_msg(MSGT_VO
, MSGL_DBG2
, "DRAW_OSD\n");
736 vo_draw_text_ext(vo_dwidth
, vo_dheight
, border_x
, border_y
, border_x
, border_y
,
737 vid_width
, vid_height
, draw_osd_I8A8
);
740 static void flip_page(void)
743 mp_msg(MSGT_VO
, MSGL_DBG2
, "\nFLIP_PAGE VID:%u -> OUT:%u\n",
744 surface_render
[vid_surface_num
].surface
, output_surfaces
[surface_num
]);
746 vdp_st
= vdp_presentation_queue_display(vdp_flip_queue
, output_surfaces
[surface_num
],
747 vo_dwidth
, vo_dheight
,
749 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
751 surface_num
= (surface_num
+ 1) % NUM_OUTPUT_SURFACES
;
755 static int draw_slice(uint8_t *image
[], int stride
[], int w
, int h
,
759 struct vdpau_render_state
*rndr
= (struct vdpau_render_state
*)image
[0];
760 int max_refs
= image_format
== IMGFMT_VDPAU_H264
? rndr
->info
.h264
.num_ref_frames
: 2;
761 if (!IMGFMT_IS_VDPAU(image_format
))
763 if (decoder
== VDP_INVALID_HANDLE
|| decoder_max_refs
< max_refs
) {
764 VdpDecoderProfile vdp_decoder_profile
;
765 if (decoder
!= VDP_INVALID_HANDLE
)
766 vdp_decoder_destroy(decoder
);
767 decoder
= VDP_INVALID_HANDLE
;
768 switch (image_format
) {
769 case IMGFMT_VDPAU_MPEG1
:
770 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG1
;
772 case IMGFMT_VDPAU_MPEG2
:
773 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG2_MAIN
;
775 case IMGFMT_VDPAU_H264
:
776 vdp_decoder_profile
= VDP_DECODER_PROFILE_H264_HIGH
;
778 case IMGFMT_VDPAU_WMV3
:
779 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_MAIN
;
781 case IMGFMT_VDPAU_VC1
:
782 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_ADVANCED
;
785 vdp_st
= vdp_decoder_create(vdp_device
, vdp_decoder_profile
, vid_width
, vid_height
, max_refs
, &decoder
);
786 CHECK_ST_WARNING("Failed creating VDPAU decoder");
787 decoder_max_refs
= max_refs
;
789 vdp_st
= vdp_decoder_render(decoder
, rndr
->surface
, (void *)&rndr
->info
, rndr
->bitstream_buffers_used
, rndr
->bitstream_buffers
);
790 CHECK_ST_WARNING("Failed VDPAU decoder rendering");
795 static int draw_frame(uint8_t *src
[])
800 static struct vdpau_render_state
*get_surface(int number
)
802 if (number
> MAX_VIDEO_SURFACES
)
804 if (surface_render
[number
].surface
== VDP_INVALID_HANDLE
) {
806 vdp_st
= vdp_video_surface_create(vdp_device
, vdp_chroma_type
,
807 vid_width
, vid_height
,
808 &surface_render
[number
].surface
);
809 CHECK_ST_WARNING("Error when calling vdp_video_surface_create")
810 if (vdp_st
!= VDP_STATUS_OK
)
813 mp_msg(MSGT_VO
, MSGL_DBG2
, "VID CREATE: %u\n", surface_render
[number
].surface
);
814 return &surface_render
[number
];
817 static uint32_t draw_image(mp_image_t
*mpi
)
819 if (IMGFMT_IS_VDPAU(image_format
)) {
820 struct vdpau_render_state
*rndr
= mpi
->priv
;
821 vid_surface_num
= rndr
- surface_render
;
822 } else if (!(mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)) {
824 void *destdata
[3] = {mpi
->planes
[0], mpi
->planes
[2], mpi
->planes
[1]};
825 struct vdpau_render_state
*rndr
= get_surface(0);
826 vid_surface_num
= rndr
- surface_render
;
827 vdp_st
= vdp_video_surface_put_bits_y_cb_cr(rndr
->surface
,
828 VDP_YCBCR_FORMAT_YV12
,
829 (const void *const*)destdata
,
830 mpi
->stride
); // pitch
831 CHECK_ST_ERROR("Error when calling vdp_video_surface_put_bits_y_cb_cr")
833 top_field_first
= !!(mpi
->fields
& MP_IMGFIELD_TOP_FIRST
);
835 video_to_output_surface();
839 static uint32_t get_image(mp_image_t
*mpi
)
841 struct vdpau_render_state
*rndr
;
843 // no dr for non-decoding for now
844 if (!IMGFMT_IS_VDPAU(image_format
)) return VO_FALSE
;
845 if (mpi
->type
!= MP_IMGTYPE_NUMBERED
) return VO_FALSE
;
847 rndr
= get_surface(mpi
->number
);
849 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] no surfaces available in get_image\n");
850 // TODO: this probably breaks things forever, provide a dummy buffer?
853 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
854 mpi
->stride
[0] = mpi
->stride
[1] = mpi
->stride
[2] = 0;
855 mpi
->planes
[0] = mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
856 // hack to get around a check and to avoid a special-case in vd_ffmpeg.c
857 mpi
->planes
[0] = (void *)rndr
;
863 static int query_format(uint32_t format
)
865 int default_flags
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
| VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_OSD
| VFCAP_EOSD
| VFCAP_EOSD_UNSCALED
;
868 return default_flags
| VOCAP_NOSLICES
;
869 case IMGFMT_VDPAU_MPEG1
:
870 case IMGFMT_VDPAU_MPEG2
:
871 case IMGFMT_VDPAU_H264
:
872 case IMGFMT_VDPAU_WMV3
:
873 case IMGFMT_VDPAU_VC1
:
874 return default_flags
;
879 static void DestroyVdpauObjects(void)
884 free_video_specific();
886 vdp_st
= vdp_presentation_queue_destroy(vdp_flip_queue
);
887 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy")
889 vdp_st
= vdp_presentation_queue_target_destroy(vdp_flip_target
);
890 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_target_destroy")
892 for (i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++) {
893 vdp_st
= vdp_output_surface_destroy(output_surfaces
[i
]);
894 output_surfaces
[i
] = VDP_INVALID_HANDLE
;
895 CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy")
898 for (i
= 0; i
<eosd_surface_count
; i
++) {
899 if (eosd_surfaces
[i
].surface
!= VDP_INVALID_HANDLE
) {
900 vdp_st
= vdp_bitmap_surface_destroy(eosd_surfaces
[i
].surface
);
901 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy")
903 eosd_surfaces
[i
].surface
= VDP_INVALID_HANDLE
;
906 vdp_st
= vdp_device_destroy(vdp_device
);
907 CHECK_ST_WARNING("Error when calling vdp_device_destroy")
910 static void uninit(void)
912 if (!vo_config_count
)
916 /* Destroy all vdpau objects */
917 DestroyVdpauObjects();
923 eosd_surfaces
= NULL
;
932 dlclose(vdpau_lib_handle
);
935 static opt_t subopts
[] = {
936 {"deint", OPT_ARG_INT
, &deint
, (opt_test_f
)int_non_neg
},
937 {"pullup", OPT_ARG_BOOL
, &pullup
, NULL
},
938 {"denoise", OPT_ARG_FLOAT
, &denoise
, NULL
},
939 {"sharpen", OPT_ARG_FLOAT
, &sharpen
, NULL
},
943 static const char help_msg
[] =
944 "\n-vo vdpau command line help:\n"
945 "Example: mplayer -vo vdpau:deint=2\n"
948 " 0: no deinterlacing\n"
949 " 1: bob deinterlacing (current fallback)\n"
950 " 2: temporal deinterlacing (not yet working)\n"
951 " 3: temporal-spatial deinterlacing (not yet working)\n"
953 " Try to apply inverse-telecine (needs deinterlacing, not working)\n"
955 " Apply denoising, argument is strength from 0.0 to 1.0\n"
957 " Apply sharpening or softening, argument is strength from -1.0 to 1.0\n"
960 static int preinit(const char *arg
)
963 static const char *vdpaulibrary
= "libvdpau.so.1";
964 static const char *vdpau_device_create
= "vdp_device_create_x11";
970 if (subopt_parse(arg
, subopts
) != 0) {
971 mp_msg(MSGT_VO
, MSGL_FATAL
, help_msg
);
975 vdpau_lib_handle
= dlopen(vdpaulibrary
, RTLD_LAZY
);
976 if (!vdpau_lib_handle
) {
977 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Could not open dynamic library %s\n",
981 vdp_device_create
= dlsym(vdpau_lib_handle
, vdpau_device_create
);
982 if (!vdp_device_create
) {
983 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Could not find function %s in %s\n",
984 vdpau_device_create
, vdpaulibrary
);
987 if (!vo_init() || win_x11_init_vdpau_procs())
990 decoder
= VDP_INVALID_HANDLE
;
991 for (i
= 0; i
< MAX_VIDEO_SURFACES
; i
++)
992 surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
993 video_mixer
= VDP_INVALID_HANDLE
;
994 for (i
= 0; i
< NUM_OUTPUT_SURFACES
; i
++)
995 output_surfaces
[i
] = VDP_INVALID_HANDLE
;
996 vdp_flip_queue
= VDP_INVALID_HANDLE
;
997 output_surface_width
= output_surface_height
= -1;
999 // full grayscale palette.
1000 for (i
= 0; i
< PALETTE_SIZE
; ++i
)
1001 palette
[i
] = (i
<< 16) | (i
<< 8) | i
;
1003 index_data_size
= 0;
1005 eosd_surface_count
= eosd_render_count
= 0;
1006 eosd_surfaces
= NULL
;
1007 eosd_targets
= NULL
;
1012 static int control(uint32_t request
, void *data
, ...)
1016 return (int_pause
= 1);
1018 return (int_pause
= 0);
1019 case VOCTRL_QUERY_FORMAT
:
1020 return query_format(*(uint32_t *)data
);
1021 case VOCTRL_GET_IMAGE
:
1022 return get_image(data
);
1023 case VOCTRL_DRAW_IMAGE
:
1024 return draw_image(data
);
1025 case VOCTRL_GUISUPPORT
:
1031 case VOCTRL_FULLSCREEN
:
1032 vo_x11_fullscreen();
1035 case VOCTRL_GET_PANSCAN
:
1037 case VOCTRL_SET_PANSCAN
:
1040 case VOCTRL_SET_EQUALIZER
: {
1045 value
= va_arg(ap
, int);
1048 return vo_x11_set_equalizer(data
, value
);
1050 case VOCTRL_GET_EQUALIZER
: {
1055 value
= va_arg(ap
, int *);
1058 return vo_x11_get_equalizer(data
, value
);
1063 case VOCTRL_UPDATE_SCREENINFO
:
1064 update_xinerama_info();
1066 case VOCTRL_DRAW_EOSD
:
1069 generate_eosd(data
);
1071 case VOCTRL_GET_EOSD_RES
: {
1072 mp_eosd_res_t
*r
= data
;
1073 r
->mt
= r
->mb
= r
->ml
= r
->mr
= 0;
1075 r
->w
= vo_screenwidth
;
1076 r
->h
= vo_screenheight
;
1077 r
->ml
= r
->mr
= border_x
;
1078 r
->mt
= r
->mb
= border_y
;
1080 r
->w
= vo_dwidth
; r
->h
= vo_dheight
;