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 * Actual decoding and presentation are implemented here.
25 * All necessary frame information is collected through
26 * the "vdpau_render_state" structure after parsing all headers
27 * etc. in libavcodec for different codecs.
39 #include "video_out.h"
40 #include "x11_common.h"
43 #include "subopt-helper.h"
44 #include "libmpcodecs/vfcap.h"
45 #include "libmpcodecs/mp_image.h"
47 #include "libavcodec/vdpau.h"
49 #include "font_load.h"
51 #include "libavutil/common.h"
52 #include "libavutil/mathematics.h"
56 #define CHECK_ST_ERROR(message) \
58 if (vdp_st != VDP_STATUS_OK) { \
59 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \
60 message, vdp->get_error_string(vdp_st)); \
65 #define CHECK_ST_WARNING(message) \
67 if (vdp_st != VDP_STATUS_OK) \
68 mp_msg(MSGT_VO, MSGL_WARN, "[ vdpau] %s: %s\n", \
69 message, vdp->get_error_string(vdp_st)); \
72 /* number of video and output surfaces */
73 #define NUM_OUTPUT_SURFACES 2
74 #define MAX_VIDEO_SURFACES 50
76 /* number of palette entries */
77 #define PALETTE_SIZE 256
79 /* Initial size of EOSD surface in pixels (x*x) */
80 #define EOSD_SURFACE_INITIAL_SIZE 256
83 * Global variable declaration - VDPAU specific
86 struct vdp_functions
{
87 #define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name;
88 #include "vdpau_template.c"
93 struct vdp_functions
*vdp
;
96 VdpDeviceCreateX11
*vdp_device_create
;
97 VdpGetProcAddress
*vdp_get_proc_address
;
99 VdpPresentationQueueTarget flip_target
;
100 VdpPresentationQueue flip_queue
;
102 void *vdpau_lib_handle
;
104 /* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */
105 #define osd_surface vc->output_surfaces[NUM_OUTPUT_SURFACES]
106 VdpOutputSurface output_surfaces
[NUM_OUTPUT_SURFACES
+ 1];
107 VdpVideoSurface deint_surfaces
[3];
108 mp_image_t
*deint_mpi
[2];
109 int output_surface_width
, output_surface_height
;
111 VdpVideoMixer video_mixer
;
115 int deint_buffer_past_frames
;
123 int decoder_max_refs
;
125 VdpRect src_rect_vid
;
126 VdpRect out_rect_vid
;
127 int border_x
, border_y
;
129 struct vdpau_render_state surface_render
[MAX_VIDEO_SURFACES
];
132 uint32_t vid_width
, vid_height
;
133 uint32_t image_format
;
134 VdpChromaType vdp_chroma_type
;
135 VdpYCbCrFormat vdp_pixel_format
;
138 unsigned char *index_data
;
140 uint32_t palette
[PALETTE_SIZE
];
144 struct eosd_bitmap_surface
{
145 VdpBitmapSurface surface
;
152 // List of surfaces to be rendered
158 int eosd_targets_size
;
161 int eosd_render_count
;
169 // These tell what's been initialized and uninit() should free/uninitialize
174 static void push_deint_surface(struct vo
*vo
, VdpVideoSurface surface
)
176 struct vdpctx
*vc
= vo
->priv
;
177 vc
->deint_surfaces
[2] = vc
->deint_surfaces
[1];
178 vc
->deint_surfaces
[1] = vc
->deint_surfaces
[0];
179 vc
->deint_surfaces
[0] = surface
;
182 static void flip_page(struct vo
*vo
);
183 static void video_to_output_surface(struct vo
*vo
)
185 struct vdpctx
*vc
= vo
->priv
;
186 struct vdp_functions
*vdp
= vc
->vdp
;
190 if (vc
->vid_surface_num
< 0)
193 if (vc
->deint
< 2 || vc
->deint_surfaces
[0] == VDP_INVALID_HANDLE
)
194 push_deint_surface(vo
, vc
->surface_render
[vc
->vid_surface_num
].surface
);
196 for (i
= 0; i
<= (vc
->deint
> 1); i
++) {
197 int field
= VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME
;
198 VdpOutputSurface output_surface
;
205 field
= (vc
->top_field_first
== i
) ^ (vc
->deint
> 1) ?
206 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD
:
207 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD
;
208 output_surface
= vc
->output_surfaces
[vc
->surface_num
];
210 presentation_queue_block_until_surface_idle(vc
->flip_queue
,
213 CHECK_ST_WARNING("Error when calling "
214 "vdp_presentation_queue_block_until_surface_idle");
216 vdp_st
= vdp
->video_mixer_render(vc
->video_mixer
, VDP_INVALID_HANDLE
,
217 0, field
, 2, vc
->deint_surfaces
+ 1,
218 vc
->deint_surfaces
[0], 1,
219 &vc
->surface_render
[vc
->vid_surface_num
].surface
,
220 &vc
->src_rect_vid
, output_surface
,
221 NULL
, &vc
->out_rect_vid
, 0, NULL
);
222 CHECK_ST_WARNING("Error when calling vdp_video_mixer_render");
223 push_deint_surface(vo
, vc
->surface_render
[vc
->vid_surface_num
].surface
);
227 static void resize(struct vo
*vo
)
229 struct vdpctx
*vc
= vo
->priv
;
230 struct vdp_functions
*vdp
= vc
->vdp
;
233 struct vo_rect src_rect
;
234 struct vo_rect dst_rect
;
235 struct vo_rect borders
;
236 calc_src_dst_rects(vo
, vc
->vid_width
, vc
->vid_height
, &src_rect
, &dst_rect
,
238 vc
->out_rect_vid
.x0
= dst_rect
.left
;
239 vc
->out_rect_vid
.x1
= dst_rect
.right
;
240 vc
->out_rect_vid
.y0
= dst_rect
.top
;
241 vc
->out_rect_vid
.y1
= dst_rect
.bottom
;
242 vc
->src_rect_vid
.x0
= src_rect
.left
;
243 vc
->src_rect_vid
.x1
= src_rect
.right
;
244 vc
->src_rect_vid
.y0
= src_rect
.top
;
245 vc
->src_rect_vid
.y1
= src_rect
.bottom
;
246 vc
->border_x
= borders
.left
;
247 vc
->border_y
= borders
.top
;
248 #ifdef CONFIG_FREETYPE
249 // adjust font size to display size
252 vo_osd_changed(OSDTYPE_OSD
);
254 if (vc
->output_surface_width
< vo
->dwidth
255 || vc
->output_surface_height
< vo
->dheight
) {
256 if (vc
->output_surface_width
< vo
->dwidth
) {
257 vc
->output_surface_width
+= vc
->output_surface_width
>> 1;
258 vc
->output_surface_width
= FFMAX(vc
->output_surface_width
,
261 if (vc
->output_surface_height
< vo
->dheight
) {
262 vc
->output_surface_height
+= vc
->output_surface_height
>> 1;
263 vc
->output_surface_height
= FFMAX(vc
->output_surface_height
,
266 // Creation of output_surfaces
267 for (i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++) {
268 if (vc
->output_surfaces
[i
] != VDP_INVALID_HANDLE
)
269 vdp
->output_surface_destroy(vc
->output_surfaces
[i
]);
270 vdp_st
= vdp
->output_surface_create(vc
->vdp_device
,
271 VDP_RGBA_FORMAT_B8G8R8A8
,
272 vc
->output_surface_width
,
273 vc
->output_surface_height
,
274 &vc
->output_surfaces
[i
]);
275 CHECK_ST_WARNING("Error when calling vdp_output_surface_create");
276 mp_msg(MSGT_VO
, MSGL_DBG2
, "OUT CREATE: %u\n",
277 vc
->output_surfaces
[i
]);
280 video_to_output_surface(vo
);
285 /* Initialize vdp_get_proc_address, called from preinit() */
286 static int win_x11_init_vdpau_procs(struct vo
*vo
)
288 struct vo_x11_state
*x11
= vo
->x11
;
289 struct vdpctx
*vc
= vo
->priv
;
290 struct vdp_functions
*vdp
= talloc_zero(vc
, struct vdp_functions
);
294 struct vdp_function
{
299 const struct vdp_function
*dsc
;
301 static const struct vdp_function vdp_func
[] = {
302 #define VDP_FUNCTION(_, macro_name, mp_name) {macro_name, offsetof(struct vdp_functions, mp_name)},
303 #include "vdpau_template.c"
308 vdp_st
= vc
->vdp_device_create(x11
->display
, x11
->screen
,&vc
->vdp_device
,
309 &vc
->vdp_get_proc_address
);
310 if (vdp_st
!= VDP_STATUS_OK
) {
311 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling "
312 "vdp_device_create_x11: %i\n", vdp_st
);
316 vdp
->get_error_string
= NULL
;
317 for (dsc
= vdp_func
; dsc
->offset
>= 0; dsc
++) {
318 vdp_st
= vc
->vdp_get_proc_address(vc
->vdp_device
, dsc
->id
,
319 (void **)((char *)vdp
+ dsc
->offset
));
320 if (vdp_st
!= VDP_STATUS_OK
) {
321 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling "
322 "vdp_get_proc_address(function id %d): %s\n", dsc
->id
,
323 vdp
->get_error_string
? vdp
->get_error_string(vdp_st
) : "?");
330 static int win_x11_init_vdpau_flip_queue(struct vo
*vo
)
332 struct vdpctx
*vc
= vo
->priv
;
333 struct vdp_functions
*vdp
= vc
->vdp
;
334 struct vo_x11_state
*x11
= vo
->x11
;
337 vdp_st
= vdp
->presentation_queue_target_create_x11(vc
->vdp_device
,
340 CHECK_ST_ERROR("Error when calling "
341 "vdp_presentation_queue_target_create_x11");
343 vdp_st
= vdp
->presentation_queue_create(vc
->vdp_device
, vc
->flip_target
,
345 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create");
350 static int create_vdp_mixer(struct vo
*vo
, VdpChromaType vdp_chroma_type
)
352 struct vdpctx
*vc
= vo
->priv
;
353 struct vdp_functions
*vdp
= vc
->vdp
;
354 #define VDP_NUM_MIXER_PARAMETER 3
355 #define MAX_NUM_FEATURES 5
358 int feature_count
= 0;
359 VdpVideoMixerFeature features
[MAX_NUM_FEATURES
];
360 VdpBool feature_enables
[MAX_NUM_FEATURES
];
361 static const VdpVideoMixerAttribute denoise_attrib
[] =
362 {VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL
};
363 const void * const denoise_value
[] = {&vc
->denoise
};
364 static const VdpVideoMixerAttribute sharpen_attrib
[] =
365 {VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL
};
366 const void * const sharpen_value
[] = {&vc
->sharpen
};
367 static const VdpVideoMixerAttribute skip_chroma_attrib
[] =
368 {VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE
};
369 const uint8_t skip_chroma_value
= 1;
370 const void * const skip_chroma_value_ptr
[] = {&skip_chroma_value
};
371 static const VdpVideoMixerParameter parameters
[VDP_NUM_MIXER_PARAMETER
] = {
372 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
,
373 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
,
374 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
,
376 const void *const parameter_values
[VDP_NUM_MIXER_PARAMETER
] = {
381 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
;
383 features
[feature_count
++] =
384 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
;
386 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
;
388 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
;
390 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS
;
392 vdp_st
= vdp
->video_mixer_create(vc
->vdp_device
, feature_count
, features
,
393 VDP_NUM_MIXER_PARAMETER
,
394 parameters
, parameter_values
,
396 CHECK_ST_ERROR("Error when calling vdp_video_mixer_create");
398 for (i
= 0; i
< feature_count
; i
++)
399 feature_enables
[i
] = VDP_TRUE
;
401 feature_enables
[0] = VDP_FALSE
;
403 vdp
->video_mixer_set_feature_enables(vc
->video_mixer
, feature_count
,
404 features
, feature_enables
);
406 vdp
->video_mixer_set_attribute_values(vc
->video_mixer
, 1,
407 denoise_attrib
, denoise_value
);
409 vdp
->video_mixer_set_attribute_values(vc
->video_mixer
, 1,
410 sharpen_attrib
, sharpen_value
);
411 if (!vc
->chroma_deint
)
412 vdp
->video_mixer_set_attribute_values(vc
->video_mixer
, 1,
414 skip_chroma_value_ptr
);
419 // Free everything specific to a certain video file
420 static void free_video_specific(struct vo
*vo
)
422 struct vdpctx
*vc
= vo
->priv
;
423 struct vdp_functions
*vdp
= vc
->vdp
;
427 if (vc
->decoder
!= VDP_INVALID_HANDLE
)
428 vdp
->decoder_destroy(vc
->decoder
);
429 vc
->decoder
= VDP_INVALID_HANDLE
;
430 vc
->decoder_max_refs
= -1;
432 for (i
= 0; i
< 3; i
++)
433 vc
->deint_surfaces
[i
] = VDP_INVALID_HANDLE
;
435 for (i
= 0; i
< 2; i
++)
436 if (vc
->deint_mpi
[i
]) {
437 vc
->deint_mpi
[i
]->usage_count
--;
438 vc
->deint_mpi
[i
] = NULL
;
441 for (i
= 0; i
< MAX_VIDEO_SURFACES
; i
++) {
442 if (vc
->surface_render
[i
].surface
!= VDP_INVALID_HANDLE
) {
443 vdp_st
= vdp
->video_surface_destroy(vc
->surface_render
[i
].surface
);
444 CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy");
446 vc
->surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
449 if (vc
->video_mixer
!= VDP_INVALID_HANDLE
) {
450 vdp_st
= vdp
->video_mixer_destroy(vc
->video_mixer
);
451 CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy");
453 vc
->video_mixer
= VDP_INVALID_HANDLE
;
456 static int create_vdp_decoder(struct vo
*vo
, int max_refs
)
458 struct vdpctx
*vc
= vo
->priv
;
459 struct vdp_functions
*vdp
= vc
->vdp
;
461 VdpDecoderProfile vdp_decoder_profile
;
462 if (vc
->decoder
!= VDP_INVALID_HANDLE
)
463 vdp
->decoder_destroy(vc
->decoder
);
464 switch (vc
->image_format
) {
465 case IMGFMT_VDPAU_MPEG1
:
466 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG1
;
468 case IMGFMT_VDPAU_MPEG2
:
469 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG2_MAIN
;
471 case IMGFMT_VDPAU_H264
:
472 vdp_decoder_profile
= VDP_DECODER_PROFILE_H264_HIGH
;
473 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Creating H264 hardware decoder "
474 "for %d reference frames.\n", max_refs
);
476 case IMGFMT_VDPAU_WMV3
:
477 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_MAIN
;
479 case IMGFMT_VDPAU_VC1
:
480 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_ADVANCED
;
483 vdp_st
= vdp
->decoder_create(vc
->vdp_device
, vdp_decoder_profile
,
484 vc
->vid_width
, vc
->vid_height
, max_refs
,
486 CHECK_ST_WARNING("Failed creating VDPAU decoder");
487 if (vdp_st
!= VDP_STATUS_OK
) {
488 vc
->decoder
= VDP_INVALID_HANDLE
;
489 vc
->decoder_max_refs
= 0;
492 vc
->decoder_max_refs
= max_refs
;
497 * connect to X server, create and map window, initialize all
498 * VDPAU objects, create different surfaces etc.
500 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
501 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
502 char *title
, uint32_t format
)
504 struct vdpctx
*vc
= vo
->priv
;
505 struct vo_x11_state
*x11
= vo
->x11
;
507 XSetWindowAttributes xswa
;
508 XWindowAttributes attribs
;
509 unsigned long xswamask
;
513 int vm
= flags
& VOFLAG_MODESWITCHING
;
516 vc
->image_format
= format
;
517 vc
->vid_width
= width
;
518 vc
->vid_height
= height
;
519 free_video_specific(vo
);
520 if (IMGFMT_IS_VDPAU(vc
->image_format
) && !create_vdp_decoder(vo
, 2))
523 vc
->visible_buf
= false;
528 vc
->mode_switched
= true;
531 XGetWindowAttributes(x11
->display
, DefaultRootWindow(x11
->display
),
533 depth
= attribs
.depth
;
534 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
536 XMatchVisualInfo(x11
->display
, x11
->screen
, depth
, TrueColor
, &vinfo
);
538 xswa
.background_pixel
= 0;
539 xswa
.border_pixel
= 0;
540 /* Do not use CWBackPixel: It leads to VDPAU errors after
541 * aspect ratio changes. */
542 xswamask
= CWBorderPixel
;
544 vo_x11_create_vo_window(vo
, &vinfo
, vo
->dx
, vo
->dy
, d_width
, d_height
,
545 flags
, CopyFromParent
, "vdpau", title
);
546 XChangeWindowAttributes(x11
->display
, x11
->window
, xswamask
, &xswa
);
550 /* Grab the mouse pointer in our window */
552 XGrabPointer(x11
->display
, x11
->window
, True
, 0,
553 GrabModeAsync
, GrabModeAsync
,
554 x11
->window
, None
, CurrentTime
);
555 XSetInputFocus(x11
->display
, x11
->window
, RevertToNone
, CurrentTime
);
559 if ((flags
& VOFLAG_FULLSCREEN
) && WinID
<= 0)
562 /* -----VDPAU related code here -------- */
563 if (vc
->flip_queue
== VDP_INVALID_HANDLE
564 && win_x11_init_vdpau_flip_queue(vo
))
567 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_420
;
568 switch (vc
->image_format
) {
572 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_YV12
;
575 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_NV12
;
578 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_YUYV
;
579 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_422
;
582 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_UYVY
;
583 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_422
;
585 if (create_vdp_mixer(vo
, vc
->vdp_chroma_type
))
588 vc
->vdp
->bitmap_surface_query_capabilities(vc
->vdp_device
,
591 &vc
->eosd_surface
.max_width
,
592 &vc
->eosd_surface
.max_height
);
594 vc
->vid_surface_num
= -1;
600 static void check_events(struct vo
*vo
)
602 struct vdpctx
*vc
= vo
->priv
;
603 struct vdp_functions
*vdp
= vc
->vdp
;
605 int e
= vo_x11_check_events(vo
);
607 if (e
& VO_EVENT_RESIZE
)
610 if ((e
& VO_EVENT_EXPOSE
|| e
& VO_EVENT_RESIZE
) && vc
->paused
) {
611 /* did we already draw a buffer */
612 if (vc
->visible_buf
) {
613 /* redraw the last visible buffer */
615 vdp_st
= vdp
->presentation_queue_display(vc
->flip_queue
,
616 vc
->output_surfaces
[vc
->surface_num
],
617 vo
->dwidth
, vo
->dheight
, 0);
618 CHECK_ST_WARNING("Error when calling "
619 "vdp_presentation_queue_display");
624 static void draw_osd_I8A8(void *ctx
, int x0
, int y0
, int w
, int h
,
625 unsigned char *src
, unsigned char *srca
, int stride
)
628 struct vdpctx
*vc
= vo
->priv
;
629 struct vdp_functions
*vdp
= vc
->vdp
;
630 VdpOutputSurface output_surface
= vc
->output_surfaces
[vc
->surface_num
];
634 int index_data_size_required
;
635 VdpRect output_indexed_rect_vid
;
640 index_data_size_required
= 2*w
*h
;
641 if (vc
->index_data_size
< index_data_size_required
) {
642 vc
->index_data
= talloc_realloc_size(vc
, vc
->index_data
,
643 index_data_size_required
);
644 vc
->index_data_size
= index_data_size_required
;
647 // index_data creation, component order - I, A, I, A, .....
648 for (i
= 0; i
< h
; i
++)
649 for (int j
= 0; j
< w
; j
++) {
650 vc
->index_data
[i
*2*w
+ j
*2] = src
[i
*stride
+j
];
651 vc
->index_data
[i
*2*w
+ j
*2 + 1] = -srca
[i
*stride
+j
];
654 output_indexed_rect_vid
.x0
= x0
;
655 output_indexed_rect_vid
.y0
= y0
;
656 output_indexed_rect_vid
.x1
= x0
+ w
;
657 output_indexed_rect_vid
.y1
= y0
+ h
;
661 // write source_data to osd_surface.
663 output_surface_put_bits_indexed(osd_surface
, VDP_INDEXED_FORMAT_I8A8
,
664 (const void *const*)&vc
->index_data
,
665 &pitch
, &output_indexed_rect_vid
,
666 VDP_COLOR_TABLE_FORMAT_B8G8R8X8
,
667 (void *)vc
->palette
);
668 CHECK_ST_WARNING("Error when calling vdp_output_surface_put_bits_indexed");
670 VdpOutputSurfaceRenderBlendState blend_state
= {
671 .struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
,
672 .blend_factor_source_color
=
673 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
674 .blend_factor_source_alpha
=
675 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
676 .blend_factor_destination_color
=
677 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
678 .blend_factor_destination_alpha
=
679 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
680 .blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
681 .blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
685 output_surface_render_output_surface(output_surface
,
686 &output_indexed_rect_vid
,
688 &output_indexed_rect_vid
,
690 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
691 CHECK_ST_WARNING("Error when calling "
692 "vdp_output_surface_render_output_surface");
695 static void draw_eosd(struct vo
*vo
)
697 struct vdpctx
*vc
= vo
->priv
;
698 struct vdp_functions
*vdp
= vc
->vdp
;
700 VdpOutputSurface output_surface
= vc
->output_surfaces
[vc
->surface_num
];
703 VdpOutputSurfaceRenderBlendState blend_state
= {
704 .struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
,
705 .blend_factor_source_color
=
706 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
707 .blend_factor_source_alpha
=
708 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
709 .blend_factor_destination_color
=
710 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
711 .blend_factor_destination_alpha
=
712 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
713 .blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
714 .blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
717 for (i
= 0; i
< vc
->eosd_render_count
; i
++) {
719 output_surface_render_bitmap_surface(output_surface
,
720 &vc
->eosd_targets
[i
].dest
,
721 vc
->eosd_surface
.surface
,
722 &vc
->eosd_targets
[i
].source
,
723 &vc
->eosd_targets
[i
].color
,
725 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
726 CHECK_ST_WARNING("EOSD: Error when rendering");
730 #define HEIGHT_SORT_BITS 4
731 static int size_index(struct eosd_target
*r
)
733 unsigned int h
= r
->source
.y1
;
734 int n
= av_log2_16bit(h
);
735 return (n
<< HEIGHT_SORT_BITS
)
736 + (- 1 - (h
<< HEIGHT_SORT_BITS
>> n
) & (1 << HEIGHT_SORT_BITS
) - 1);
739 /* Pack the given rectangles into an area of size w * h.
740 * The size of each rectangle is read from .source.x1/.source.y1.
741 * The height of each rectangle must be at least 1 and less than 65536.
742 * The .source rectangle is then set corresponding to the packed position.
743 * 'scratch' must point to work memory for num_rects+16 ints.
744 * Return 0 on success, -1 if the rectangles did not fit in w*h.
746 * The rectangles are placed in rows in order approximately sorted by
747 * height (the approximate sorting is simpler than a full one would be,
748 * and allows the algorithm to work in linear time). Additionally, to
749 * reduce wasted space when there are a few tall rectangles, empty
750 * lower-right parts of rows are filled recursively when the size of
751 * rectangles in the row drops past a power-of-two threshold. So if a
752 * row starts with rectangles of size 3x50, 10x40 and 5x20 then the
753 * free rectangle with corners (13, 20)-(w, 50) is filled recursively.
755 static int pack_rectangles(struct eosd_target
*rects
, int num_rects
,
756 int w
, int h
, int *scratch
)
758 int bins
[16 << HEIGHT_SORT_BITS
];
759 int sizes
[16 << HEIGHT_SORT_BITS
] = {};
760 for (int i
= 0; i
< num_rects
; i
++)
761 sizes
[size_index(rects
+ i
)]++;
763 for (int i
= 0; i
< 16 << HEIGHT_SORT_BITS
; i
+= 1 << HEIGHT_SORT_BITS
) {
764 for (int j
= 0; j
< 1 << HEIGHT_SORT_BITS
; j
++) {
770 for (int i
= 0; i
< num_rects
; i
++)
771 scratch
[bins
[size_index(rects
+ i
)]++] = i
;
772 for (int i
= 0; i
< 16; i
++)
773 bins
[i
] = bins
[i
<< HEIGHT_SORT_BITS
] - sizes
[i
<< HEIGHT_SORT_BITS
];
776 } stack
[16] = {{15, 0, h
}}, s
= {};
781 s
= stack
[--stackpos
];
786 while ((obj
= scratch
[bins
[s
.size
]]) >= 0) {
787 int bottom
= y
+ rects
[obj
].source
.y1
;
788 if (bottom
> s
.bottom
)
790 int right
= s
.x
+ rects
[obj
].source
.x1
;
794 rects
[obj
].source
.x0
= s
.x
;
795 rects
[obj
].source
.x1
+= s
.x
;
796 rects
[obj
].source
.y0
= y
;
797 rects
[obj
].source
.y1
+= y
;
800 stack
[stackpos
++] = s
;
802 maxy
= FFMAX(maxy
, bottom
);
808 return num_rects
? -1 : 0;
811 static void generate_eosd(struct vo
*vo
, mp_eosd_images_t
*imgs
)
813 struct vdpctx
*vc
= vo
->priv
;
814 struct vdp_functions
*vdp
= vc
->vdp
;
817 ASS_Image
*img
= imgs
->imgs
;
819 struct eosd_bitmap_surface
*sfc
= &vc
->eosd_surface
;
820 bool need_upload
= false;
822 if (imgs
->changed
== 0)
823 return; // Nothing changed, no need to redraw
825 vc
->eosd_render_count
= 0;
828 return; // There's nothing to render!
830 if (imgs
->changed
== 1)
831 goto eosd_skip_upload
;
834 bool reallocate
= false;
836 for (p
= img
, i
= 0; p
; p
= p
->next
) {
837 if (p
->w
<= 0 || p
->h
<= 0)
839 // Allocate new space for surface/target arrays
840 if (i
>= vc
->eosd_targets_size
) {
841 vc
->eosd_targets_size
= FFMAX(vc
->eosd_targets_size
* 2, 512);
843 talloc_realloc_size(vc
, vc
->eosd_targets
,
844 vc
->eosd_targets_size
845 * sizeof(*vc
->eosd_targets
));
847 talloc_realloc_size(vc
, vc
->eosd_scratch
,
848 (vc
->eosd_targets_size
+ 16)
849 * sizeof(*vc
->eosd_scratch
));
851 vc
->eosd_targets
[i
].source
.x1
= p
->w
;
852 vc
->eosd_targets
[i
].source
.y1
= p
->h
;
855 if (pack_rectangles(vc
->eosd_targets
, i
, sfc
->w
, sfc
->h
,
856 vc
->eosd_scratch
) >= 0)
858 int w
= FFMIN(FFMAX(sfc
->w
* 2, EOSD_SURFACE_INITIAL_SIZE
),
860 int h
= FFMIN(FFMAX(sfc
->h
* 2, EOSD_SURFACE_INITIAL_SIZE
),
862 if (w
== sfc
->w
&& h
== sfc
->h
) {
863 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] EOSD bitmaps do not fit on "
864 "a surface with the maximum supported size\n");
873 if (sfc
->surface
!= VDP_INVALID_HANDLE
)
874 vdp
->bitmap_surface_destroy(sfc
->surface
);
875 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Allocating a %dx%d surface for "
876 "EOSD bitmaps.\n", sfc
->w
, sfc
->h
);
877 vdp_st
= vdp
->bitmap_surface_create(vc
->vdp_device
, VDP_RGBA_FORMAT_A8
,
878 sfc
->w
, sfc
->h
, true,
880 if (vdp_st
!= VDP_STATUS_OK
)
881 sfc
->surface
= VDP_INVALID_HANDLE
;
882 CHECK_ST_WARNING("EOSD: error when creating surface");
886 if (sfc
->surface
== VDP_INVALID_HANDLE
)
888 for (p
= img
; p
; p
= p
->next
) {
889 if (p
->w
<= 0 || p
->h
<= 0)
891 struct eosd_target
*target
= &vc
->eosd_targets
[vc
->eosd_render_count
];
894 bitmap_surface_put_bits_native(sfc
->surface
,
895 (const void *) &p
->bitmap
,
896 &p
->stride
, &target
->source
);
897 CHECK_ST_WARNING("EOSD: putbits failed");
899 // Render dest, color, etc.
900 target
->color
.alpha
= 1.0 - ((p
->color
>> 0) & 0xff) / 255.0;
901 target
->color
.blue
= ((p
->color
>> 8) & 0xff) / 255.0;
902 target
->color
.green
= ((p
->color
>> 16) & 0xff) / 255.0;
903 target
->color
.red
= ((p
->color
>> 24) & 0xff) / 255.0;
904 target
->dest
.x0
= p
->dst_x
;
905 target
->dest
.y0
= p
->dst_y
;
906 target
->dest
.x1
= p
->w
+ p
->dst_x
;
907 target
->dest
.y1
= p
->h
+ p
->dst_y
;
908 vc
->eosd_render_count
++;
912 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
914 struct vdpctx
*vc
= vo
->priv
;
915 mp_msg(MSGT_VO
, MSGL_DBG2
, "DRAW_OSD\n");
917 osd_draw_text_ext(osd
, vo
->dwidth
, vo
->dheight
, vc
->border_x
, vc
->border_y
,
918 vc
->border_x
, vc
->border_y
, vc
->vid_width
,
919 vc
->vid_height
, draw_osd_I8A8
, vo
);
922 static void flip_page(struct vo
*vo
)
924 struct vdpctx
*vc
= vo
->priv
;
925 struct vdp_functions
*vdp
= vc
->vdp
;
928 mp_msg(MSGT_VO
, MSGL_DBG2
, "\nFLIP_PAGE VID:%u -> OUT:%u\n",
929 vc
->surface_render
[vc
->vid_surface_num
].surface
,
930 vc
->output_surfaces
[vc
->surface_num
]);
933 vdp
->presentation_queue_display(vc
->flip_queue
,
934 vc
->output_surfaces
[vc
->surface_num
],
935 vo
->dwidth
, vo
->dheight
, 0);
936 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display");
938 vc
->surface_num
= (vc
->surface_num
+ 1) % NUM_OUTPUT_SURFACES
;
939 vc
->visible_buf
= true;
942 static int draw_slice(struct vo
*vo
, uint8_t *image
[], int stride
[], int w
,
945 struct vdpctx
*vc
= vo
->priv
;
946 struct vdp_functions
*vdp
= vc
->vdp
;
948 struct vdpau_render_state
*rndr
= (struct vdpau_render_state
*)image
[0];
949 int max_refs
= vc
->image_format
== IMGFMT_VDPAU_H264
?
950 rndr
->info
.h264
.num_ref_frames
: 2;
951 if (!IMGFMT_IS_VDPAU(vc
->image_format
))
953 if ((vc
->decoder
== VDP_INVALID_HANDLE
|| vc
->decoder_max_refs
< max_refs
)
954 && !create_vdp_decoder(vo
, max_refs
))
957 vdp_st
= vdp
->decoder_render(vc
->decoder
, rndr
->surface
,
959 rndr
->bitstream_buffers_used
,
960 rndr
->bitstream_buffers
);
961 CHECK_ST_WARNING("Failed VDPAU decoder rendering");
966 static int draw_frame(struct vo
*vo
, uint8_t *src
[])
971 static struct vdpau_render_state
*get_surface(struct vo
*vo
, int number
)
973 struct vdpctx
*vc
= vo
->priv
;
974 struct vdp_functions
*vdp
= vc
->vdp
;
976 if (number
> MAX_VIDEO_SURFACES
)
978 if (vc
->surface_render
[number
].surface
== VDP_INVALID_HANDLE
) {
980 vdp_st
= vdp
->video_surface_create(vc
->vdp_device
, vc
->vdp_chroma_type
,
981 vc
->vid_width
, vc
->vid_height
,
982 &vc
->surface_render
[number
].surface
);
983 CHECK_ST_WARNING("Error when calling vdp_video_surface_create");
984 if (vdp_st
!= VDP_STATUS_OK
)
987 mp_msg(MSGT_VO
, MSGL_DBG2
, "VID CREATE: %u\n",
988 vc
->surface_render
[number
].surface
);
989 return &vc
->surface_render
[number
];
992 static uint32_t draw_image(struct vo
*vo
, mp_image_t
*mpi
)
994 struct vdpctx
*vc
= vo
->priv
;
995 struct vdp_functions
*vdp
= vc
->vdp
;
997 if (IMGFMT_IS_VDPAU(vc
->image_format
)) {
998 struct vdpau_render_state
*rndr
= mpi
->priv
;
999 vc
->vid_surface_num
= rndr
- vc
->surface_render
;
1000 if (vc
->deint_buffer_past_frames
) {
1002 if (vc
->deint_mpi
[1])
1003 vc
->deint_mpi
[1]->usage_count
--;
1004 vc
->deint_mpi
[1] = vc
->deint_mpi
[0];
1005 vc
->deint_mpi
[0] = mpi
;
1007 } else if (!(mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)) {
1009 void *destdata
[3] = {mpi
->planes
[0], mpi
->planes
[2], mpi
->planes
[1]};
1010 struct vdpau_render_state
*rndr
= get_surface(vo
, vc
->deint_counter
);
1011 vc
->deint_counter
= (vc
->deint_counter
+ 1) % 3;
1012 vc
->vid_surface_num
= rndr
- vc
->surface_render
;
1013 if (vc
->image_format
== IMGFMT_NV12
)
1014 destdata
[1] = destdata
[2];
1016 vdp
->video_surface_put_bits_y_cb_cr(rndr
->surface
,
1017 vc
->vdp_pixel_format
,
1018 (const void *const*)destdata
,
1019 mpi
->stride
); // pitch
1020 CHECK_ST_ERROR("Error when calling "
1021 "vdp_video_surface_put_bits_y_cb_cr");
1023 if (mpi
->fields
& MP_IMGFIELD_ORDERED
)
1024 vc
->top_field_first
= !!(mpi
->fields
& MP_IMGFIELD_TOP_FIRST
);
1026 vc
->top_field_first
= 1;
1028 video_to_output_surface(vo
);
1032 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
1034 struct vdpctx
*vc
= vo
->priv
;
1035 struct vdpau_render_state
*rndr
;
1037 // no dr for non-decoding for now
1038 if (!IMGFMT_IS_VDPAU(vc
->image_format
))
1040 if (mpi
->type
!= MP_IMGTYPE_NUMBERED
)
1043 rndr
= get_surface(vo
, mpi
->number
);
1045 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] no surfaces available in "
1047 // TODO: this probably breaks things forever, provide a dummy buffer?
1050 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1051 mpi
->stride
[0] = mpi
->stride
[1] = mpi
->stride
[2] = 0;
1052 mpi
->planes
[0] = mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
1053 // hack to get around a check and to avoid a special-case in vd_ffmpeg.c
1054 mpi
->planes
[0] = (void *)rndr
;
1055 mpi
->num_planes
= 1;
1060 static int query_format(uint32_t format
)
1062 int default_flags
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
1063 | VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_OSD
| VFCAP_EOSD
1064 | VFCAP_EOSD_UNSCALED
;
1072 return default_flags
| VOCAP_NOSLICES
;
1073 case IMGFMT_VDPAU_MPEG1
:
1074 case IMGFMT_VDPAU_MPEG2
:
1075 case IMGFMT_VDPAU_H264
:
1076 case IMGFMT_VDPAU_WMV3
:
1077 case IMGFMT_VDPAU_VC1
:
1078 return default_flags
;
1083 static void destroy_vdpau_objects(struct vo
*vo
)
1085 struct vdpctx
*vc
= vo
->priv
;
1086 struct vdp_functions
*vdp
= vc
->vdp
;
1091 free_video_specific(vo
);
1093 if (vc
->flip_queue
!= VDP_INVALID_HANDLE
) {
1094 vdp_st
= vdp
->presentation_queue_destroy(vc
->flip_queue
);
1095 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy");
1098 if (vc
->flip_target
!= VDP_INVALID_HANDLE
) {
1099 vdp_st
= vdp
->presentation_queue_target_destroy(vc
->flip_target
);
1100 CHECK_ST_WARNING("Error when calling "
1101 "vdp_presentation_queue_target_destroy");
1104 for (i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++) {
1105 if (vc
->output_surfaces
[i
] == VDP_INVALID_HANDLE
)
1107 vdp_st
= vdp
->output_surface_destroy(vc
->output_surfaces
[i
]);
1108 CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
1111 if (vc
->eosd_surface
.surface
!= VDP_INVALID_HANDLE
) {
1112 vdp_st
= vdp
->bitmap_surface_destroy(vc
->eosd_surface
.surface
);
1113 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
1116 vdp_st
= vdp
->device_destroy(vc
->vdp_device
);
1117 CHECK_ST_WARNING("Error when calling vdp_device_destroy");
1120 static void uninit(struct vo
*vo
)
1122 struct vdpctx
*vc
= vo
->priv
;
1124 /* Destroy all vdpau objects */
1125 destroy_vdpau_objects(vo
);
1127 #ifdef CONFIG_XF86VM
1128 if (vc
->mode_switched
)
1133 dlclose(vc
->vdpau_lib_handle
);
1136 static const char help_msg
[] =
1137 "\n-vo vdpau command line help:\n"
1138 "Example: mplayer -vo vdpau:deint=2\n"
1140 " deint (all modes > 0 respect -field-dominance)\n"
1141 " 0: no deinterlacing\n"
1142 " 1: only show first field\n"
1143 " 2: bob deinterlacing\n"
1144 " 3: temporal deinterlacing (resource-hungry)\n"
1145 " 4: temporal-spatial deinterlacing (very resource-hungry)\n"
1147 " Operate on luma and chroma when using temporal deinterlacing (default)\n"
1148 " Use nochroma-deint to speed up temporal deinterlacing\n"
1150 " Try to apply inverse-telecine (needs temporal deinterlacing)\n"
1152 " Apply denoising, argument is strength from 0.0 to 1.0\n"
1154 " Apply sharpening or softening, argument is strength from -1.0 to 1.0\n"
1157 static int preinit(struct vo
*vo
, const char *arg
)
1161 struct vdpctx
*vc
= talloc_zero(vo
, struct vdpctx
);
1164 // Mark everything as invalid first so uninit() can tell what has been
1166 vc
->decoder
= VDP_INVALID_HANDLE
;
1167 for (i
= 0; i
< MAX_VIDEO_SURFACES
; i
++)
1168 vc
->surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
1169 vc
->video_mixer
= VDP_INVALID_HANDLE
;
1170 vc
->flip_queue
= VDP_INVALID_HANDLE
;
1171 vc
->flip_target
= VDP_INVALID_HANDLE
;
1172 for (i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++)
1173 vc
->output_surfaces
[i
] = VDP_INVALID_HANDLE
;
1174 vc
->vdp_device
= VDP_INVALID_HANDLE
;
1175 vc
->eosd_surface
.surface
= VDP_INVALID_HANDLE
;
1178 vc
->chroma_deint
= 1;
1179 const opt_t subopts
[] = {
1180 {"deint", OPT_ARG_INT
, &vc
->deint
, (opt_test_f
)int_non_neg
},
1181 {"chroma-deint", OPT_ARG_BOOL
, &vc
->chroma_deint
, NULL
},
1182 {"pullup", OPT_ARG_BOOL
, &vc
->pullup
, NULL
},
1183 {"denoise", OPT_ARG_FLOAT
, &vc
->denoise
, NULL
},
1184 {"sharpen", OPT_ARG_FLOAT
, &vc
->sharpen
, NULL
},
1187 if (subopt_parse(arg
, subopts
) != 0) {
1188 mp_msg(MSGT_VO
, MSGL_FATAL
, help_msg
);
1192 vc
->deint_type
= vc
->deint
;
1194 vc
->deint_buffer_past_frames
= 1;
1196 char *vdpaulibrary
= "libvdpau.so.1";
1197 char *vdpau_device_create
= "vdp_device_create_x11";
1198 vc
->vdpau_lib_handle
= dlopen(vdpaulibrary
, RTLD_LAZY
);
1199 if (!vc
->vdpau_lib_handle
) {
1200 mp_msg(MSGT_VO
, MSGL_ERR
,
1201 "[vdpau] Could not open dynamic library %s\n", vdpaulibrary
);
1204 vc
->vdp_device_create
= dlsym(vc
->vdpau_lib_handle
, vdpau_device_create
);
1205 if (!vc
->vdp_device_create
) {
1206 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Could not find function %s in %s\n",
1207 vdpau_device_create
, vdpaulibrary
);
1208 dlclose(vc
->vdpau_lib_handle
);
1212 dlclose(vc
->vdpau_lib_handle
);
1216 // After this calling uninit() should work to free resources
1218 if (win_x11_init_vdpau_procs(vo
) < 0) {
1219 if (vc
->vdp
->device_destroy
)
1220 vc
->vdp
->device_destroy(vc
->vdp_device
);
1222 dlclose(vc
->vdpau_lib_handle
);
1226 vc
->output_surface_width
= vc
->output_surface_height
= -1;
1228 // full grayscale palette.
1229 for (i
= 0; i
< PALETTE_SIZE
; ++i
)
1230 vc
->palette
[i
] = (i
<< 16) | (i
<< 8) | i
;
1232 vc
->procamp
.struct_version
= VDP_PROCAMP_VERSION
;
1233 vc
->procamp
.brightness
= 0.0;
1234 vc
->procamp
.contrast
= 1.0;
1235 vc
->procamp
.saturation
= 1.0;
1236 vc
->procamp
.hue
= 0.0;
1241 static int get_equalizer(struct vo
*vo
, const char *name
, int *value
)
1243 struct vdpctx
*vc
= vo
->priv
;
1245 if (!strcasecmp(name
, "brightness"))
1246 *value
= vc
->procamp
.brightness
* 100;
1247 else if (!strcasecmp(name
, "contrast"))
1248 *value
= (vc
->procamp
.contrast
- 1.0) * 100;
1249 else if (!strcasecmp(name
, "saturation"))
1250 *value
= (vc
->procamp
.saturation
- 1.0) * 100;
1251 else if (!strcasecmp(name
, "hue"))
1252 *value
= vc
->procamp
.hue
* 100 / M_PI
;
1258 static int set_equalizer(struct vo
*vo
, const char *name
, int value
)
1260 struct vdpctx
*vc
= vo
->priv
;
1261 struct vdp_functions
*vdp
= vc
->vdp
;
1263 VdpCSCMatrix matrix
;
1264 static const VdpVideoMixerAttribute attributes
[] =
1265 {VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX
};
1266 const void *attribute_values
[] = {&matrix
};
1268 if (!strcasecmp(name
, "brightness"))
1269 vc
->procamp
.brightness
= value
/ 100.0;
1270 else if (!strcasecmp(name
, "contrast"))
1271 vc
->procamp
.contrast
= value
/ 100.0 + 1.0;
1272 else if (!strcasecmp(name
, "saturation"))
1273 vc
->procamp
.saturation
= value
/ 100.0 + 1.0;
1274 else if (!strcasecmp(name
, "hue"))
1275 vc
->procamp
.hue
= value
/ 100.0 * M_PI
;
1279 vdp_st
= vdp
->generate_csc_matrix(&vc
->procamp
,
1280 VDP_COLOR_STANDARD_ITUR_BT_601
,
1282 CHECK_ST_WARNING("Error when generating CSC matrix");
1283 vdp_st
= vdp
->video_mixer_set_attribute_values(vc
->video_mixer
, 1,
1286 CHECK_ST_WARNING("Error when setting CSC matrix");
1290 static int control(struct vo
*vo
, uint32_t request
, void *data
)
1292 struct vdpctx
*vc
= vo
->priv
;
1293 struct vdp_functions
*vdp
= vc
->vdp
;
1296 case VOCTRL_GET_DEINTERLACE
:
1297 *(int*)data
= vc
->deint
;
1299 case VOCTRL_SET_DEINTERLACE
:
1300 vc
->deint
= *(int*)data
;
1302 vc
->deint
= vc
->deint_type
;
1303 if (vc
->deint_type
> 2) {
1305 VdpVideoMixerFeature features
[1] =
1306 {vc
->deint_type
== 3 ?
1307 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
1308 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
};
1309 VdpBool feature_enables
[1] = {vc
->deint
? VDP_TRUE
: VDP_FALSE
};
1310 vdp_st
= vdp
->video_mixer_set_feature_enables(vc
->video_mixer
,
1313 CHECK_ST_WARNING("Error changing deinterlacing settings");
1314 vc
->deint_buffer_past_frames
= 1;
1318 return (vc
->paused
= true);
1320 return (vc
->paused
= false);
1321 case VOCTRL_QUERY_FORMAT
:
1322 return query_format(*(uint32_t *)data
);
1323 case VOCTRL_GET_IMAGE
:
1324 return get_image(vo
, data
);
1325 case VOCTRL_DRAW_IMAGE
:
1326 return draw_image(vo
, data
);
1331 case VOCTRL_FULLSCREEN
:
1332 vo_x11_fullscreen(vo
);
1335 case VOCTRL_GET_PANSCAN
:
1337 case VOCTRL_SET_PANSCAN
:
1340 case VOCTRL_SET_EQUALIZER
: {
1341 struct voctrl_set_equalizer_args
*args
= data
;
1342 return set_equalizer(vo
, args
->name
, args
->value
);
1344 case VOCTRL_GET_EQUALIZER
:
1346 struct voctrl_get_equalizer_args
*args
= data
;
1347 return get_equalizer(vo
, args
->name
, args
->valueptr
);
1352 case VOCTRL_UPDATE_SCREENINFO
:
1353 update_xinerama_info(vo
);
1355 case VOCTRL_DRAW_EOSD
:
1358 generate_eosd(vo
, data
);
1361 case VOCTRL_GET_EOSD_RES
: {
1362 mp_eosd_res_t
*r
= data
;
1363 r
->mt
= r
->mb
= r
->ml
= r
->mr
= 0;
1365 r
->w
= vo
->opts
->vo_screenwidth
;
1366 r
->h
= vo
->opts
->vo_screenheight
;
1367 r
->ml
= r
->mr
= vc
->border_x
;
1368 r
->mt
= r
->mb
= vc
->border_y
;
1379 const struct vo_driver video_out_vdpau
= {
1381 .info
= &(const struct vo_info_s
){
1384 "Rajib Mahapatra <rmahapatra@nvidia.com> and others",
1390 .draw_frame
= draw_frame
,
1391 .draw_slice
= draw_slice
,
1392 .draw_osd
= draw_osd
,
1393 .flip_page
= flip_page
,
1394 .check_events
= check_events
,