2 * VDPAU video output driver
4 * Copyright (C) 2008 NVIDIA
5 * Copyright (C) 2009 Uoti Urpala
7 * This file is part of MPlayer.
9 * MPlayer is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * MPlayer is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
21 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * Actual decoding and presentation are implemented here.
26 * All necessary frame information is collected through
27 * the "vdpau_render_state" structure after parsing all headers
28 * etc. in libavcodec for different codecs.
38 #include <libavutil/common.h>
39 #include <libavcodec/vdpau.h>
45 #include "video_out.h"
46 #include "x11_common.h"
51 #include "libmpcodecs/vfcap.h"
52 #include "libmpcodecs/mp_image.h"
53 #include "osdep/timer.h"
54 #include "sub/ass_mp.h"
55 #include "bitmap_packer.h"
57 #define WRAP_ADD(x, a, m) ((a) < 0 \
58 ? ((x)+(a)+(m) < (m) ? (x)+(a)+(m) : (x)+(a)) \
59 : ((x)+(a) < (m) ? (x)+(a) : (x)+(a)-(m)))
61 #define CHECK_ST_ERROR(message) \
63 if (vdp_st != VDP_STATUS_OK) { \
64 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \
65 message, vdp->get_error_string(vdp_st)); \
70 #define CHECK_ST_WARNING(message) \
72 if (vdp_st != VDP_STATUS_OK) \
73 mp_msg(MSGT_VO, MSGL_WARN, "[ vdpau] %s: %s\n", \
74 message, vdp->get_error_string(vdp_st)); \
77 /* number of video and output surfaces */
78 #define MAX_OUTPUT_SURFACES 15
79 #define MAX_VIDEO_SURFACES 50
80 #define NUM_BUFFERED_VIDEO 5
82 /* Pixelformat used for output surfaces */
83 #define OUTPUT_RGBA_FORMAT VDP_RGBA_FORMAT_B8G8R8A8
86 * Global variable declaration - VDPAU specific
89 struct vdp_functions
{
90 #define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name;
91 #include "vdpau_template.c"
95 #define MAX_OLD_OSD_BITMAPS 6
98 struct vdp_functions
*vdp
;
100 VdpDevice vdp_device
;
102 bool preemption_acked
;
103 bool preemption_user_notified
;
104 unsigned int last_preemption_retry_fail
;
105 VdpGetProcAddress
*vdp_get_proc_address
;
107 VdpPresentationQueueTarget flip_target
;
108 VdpPresentationQueue flip_queue
;
109 uint64_t last_vdp_time
;
110 unsigned int last_sync_update
;
112 VdpOutputSurface output_surfaces
[MAX_OUTPUT_SURFACES
];
113 VdpOutputSurface screenshot_surface
;
114 int num_output_surfaces
;
115 struct buffered_video_surface
{
116 VdpVideoSurface surface
;
119 } buffered_video
[NUM_BUFFERED_VIDEO
];
121 int output_surface_width
, output_surface_height
;
123 VdpVideoMixer video_mixer
;
124 struct mp_csp_details colorspace
;
133 int flip_offset_window
;
139 int decoder_max_refs
;
141 VdpRect src_rect_vid
;
142 VdpRect out_rect_vid
;
143 int border_x
, border_y
;
145 struct vdpau_render_state surface_render
[MAX_VIDEO_SURFACES
];
147 int query_surface_num
;
148 VdpTime recent_vsync_time
;
150 int composite_detect
;
151 unsigned int vsync_interval
;
152 uint64_t last_queue_time
;
153 uint64_t queue_time
[MAX_OUTPUT_SURFACES
];
154 uint64_t last_ideal_time
;
156 uint64_t dropped_time
;
157 uint32_t vid_width
, vid_height
;
158 uint32_t vid_d_width
, vid_d_height
;
159 uint32_t image_format
;
160 VdpChromaType vdp_chroma_type
;
161 VdpYCbCrFormat vdp_pixel_format
;
166 unsigned char *src
, *srca
;
168 } old_osd_elements
[MAX_OLD_OSD_BITMAPS
];
170 unsigned char *osd_data_temp
;
174 struct eosd_bitmap_surface
{
175 VdpRGBAFormat format
;
176 VdpBitmapSurface surface
;
179 struct bitmap_packer
*packer
;
180 } eosd_surface
, osd_surface
;
182 // List of surfaces to be rendered
187 } *eosd_targets
, osd_targets
[MAX_OLD_OSD_BITMAPS
][2];
188 int eosd_targets_size
;
189 int eosd_render_count
;
190 unsigned int bitmap_id
;
191 unsigned int bitmap_pos_id
;
194 struct mp_csp_equalizer video_eq
;
196 // These tell what's been initialized and uninit() should free/uninitialize
200 static int change_vdptime_sync(struct vdpctx
*vc
, unsigned int *t
)
202 struct vdp_functions
*vdp
= vc
->vdp
;
205 vdp_st
= vdp
->presentation_queue_get_time(vc
->flip_queue
, &vdp_time
);
206 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time");
207 unsigned int t1
= *t
;
208 unsigned int t2
= GetTimer();
209 uint64_t old
= vc
->last_vdp_time
+ (t1
- vc
->last_sync_update
) * 1000ULL;
211 if (vdp_time
> old
+ (t2
- t1
) * 1000ULL)
212 vdp_time
-= (t2
- t1
) * 1000ULL;
215 mp_msg(MSGT_VO
, MSGL_DBG2
, "[vdpau] adjusting VdpTime offset by %f µs\n",
216 (int64_t)(vdp_time
- old
) / 1000.);
217 vc
->last_vdp_time
= vdp_time
;
218 vc
->last_sync_update
= t1
;
223 static uint64_t sync_vdptime(struct vo
*vo
)
225 struct vdpctx
*vc
= vo
->priv
;
227 unsigned int t
= GetTimer();
228 if (t
- vc
->last_sync_update
> 5000000)
229 change_vdptime_sync(vc
, &t
);
230 uint64_t now
= (t
- vc
->last_sync_update
) * 1000ULL + vc
->last_vdp_time
;
231 // Make sure nanosecond inaccuracies don't make things inconsistent
232 now
= FFMAX(now
, vc
->recent_vsync_time
);
236 static uint64_t convert_to_vdptime(struct vo
*vo
, unsigned int t
)
238 struct vdpctx
*vc
= vo
->priv
;
239 return (int)(t
- vc
->last_sync_update
) * 1000LL + vc
->last_vdp_time
;
242 static int render_video_to_output_surface(struct vo
*vo
,
243 VdpOutputSurface output_surface
,
244 VdpRect
*output_rect
)
246 struct vdpctx
*vc
= vo
->priv
;
247 struct vdp_functions
*vdp
= vc
->vdp
;
250 if (vc
->deint_queue_pos
< 0)
253 struct buffered_video_surface
*bv
= vc
->buffered_video
;
254 int field
= VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME
;
255 unsigned int dp
= vc
->deint_queue_pos
;
256 // dp==0 means last field of latest frame, 1 earlier field of latest frame,
257 // 2 last field of previous frame and so on
259 field
= vc
->top_field_first
^ (dp
& 1) ?
260 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD
:
261 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD
;
263 const VdpVideoSurface
*past_fields
= (const VdpVideoSurface
[]){
264 bv
[(dp
+1)/2].surface
, bv
[(dp
+2)/2].surface
};
265 const VdpVideoSurface
*future_fields
= (const VdpVideoSurface
[]){
266 dp
>= 1 ? bv
[(dp
-1)/2].surface
: VDP_INVALID_HANDLE
};
267 vdp_st
= vdp
->presentation_queue_block_until_surface_idle(vc
->flip_queue
,
270 CHECK_ST_WARNING("Error when calling "
271 "vdp_presentation_queue_block_until_surface_idle");
273 vdp_st
= vdp
->video_mixer_render(vc
->video_mixer
, VDP_INVALID_HANDLE
,
274 0, field
, 2, past_fields
,
275 bv
[dp
/2].surface
, 1, future_fields
,
276 &vc
->src_rect_vid
, output_surface
,
277 NULL
, output_rect
, 0, NULL
);
278 CHECK_ST_WARNING("Error when calling vdp_video_mixer_render");
282 static int video_to_output_surface(struct vo
*vo
)
284 struct vdpctx
*vc
= vo
->priv
;
286 return render_video_to_output_surface(vo
,
287 vc
->output_surfaces
[vc
->surface_num
],
291 static int next_deint_queue_pos(struct vo
*vo
, bool eof
)
293 struct vdpctx
*vc
= vo
->priv
;
295 int dqp
= vc
->deint_queue_pos
;
299 dqp
= vc
->deint
>= 2 ? dqp
- 1 : dqp
- 2 | 1;
300 if (dqp
< (eof
? 0 : 3))
305 static void set_next_frame_info(struct vo
*vo
, bool eof
)
307 struct vdpctx
*vc
= vo
->priv
;
309 vo
->frame_loaded
= false;
310 int dqp
= next_deint_queue_pos(vo
, eof
);
313 vo
->frame_loaded
= true;
316 struct buffered_video_surface
*bv
= vc
->buffered_video
;
318 if (idx
== 0) { // no future frame/pts available
319 vo
->next_pts
= bv
[0].pts
;
320 vo
->next_pts2
= MP_NOPTS_VALUE
;
321 } else if (!(vc
->deint
>= 2)) { // no field-splitting deinterlace
322 vo
->next_pts
= bv
[idx
].pts
;
323 vo
->next_pts2
= bv
[idx
- 1].pts
;
324 } else { // deinterlace with separate fields
325 double intermediate_pts
;
326 double diff
= bv
[idx
- 1].pts
- bv
[idx
].pts
;
327 if (diff
> 0 && diff
< 0.5)
328 intermediate_pts
= (bv
[idx
].pts
+ bv
[idx
- 1].pts
) / 2;
330 intermediate_pts
= bv
[idx
].pts
;
331 if (dqp
& 1) { // first field
332 vo
->next_pts
= bv
[idx
].pts
;
333 vo
->next_pts2
= intermediate_pts
;
335 vo
->next_pts
= intermediate_pts
;
336 vo
->next_pts2
= bv
[idx
- 1].pts
;
341 static void add_new_video_surface(struct vo
*vo
, VdpVideoSurface surface
,
342 struct mp_image
*reserved_mpi
, double pts
)
344 struct vdpctx
*vc
= vo
->priv
;
345 struct buffered_video_surface
*bv
= vc
->buffered_video
;
348 reserved_mpi
->usage_count
++;
349 if (bv
[NUM_BUFFERED_VIDEO
- 1].mpi
)
350 bv
[NUM_BUFFERED_VIDEO
- 1].mpi
->usage_count
--;
352 for (int i
= NUM_BUFFERED_VIDEO
- 1; i
> 0; i
--)
354 bv
[0] = (struct buffered_video_surface
){
360 vc
->deint_queue_pos
= FFMIN(vc
->deint_queue_pos
+ 2,
361 NUM_BUFFERED_VIDEO
* 2 - 3);
362 set_next_frame_info(vo
, false);
365 static void forget_frames(struct vo
*vo
)
367 struct vdpctx
*vc
= vo
->priv
;
369 vc
->deint_queue_pos
= -1001;
370 vc
->dropped_frame
= false;
371 for (int i
= 0; i
< NUM_BUFFERED_VIDEO
; i
++) {
372 struct buffered_video_surface
*p
= vc
->buffered_video
+ i
;
374 p
->mpi
->usage_count
--;
375 *p
= (struct buffered_video_surface
){
376 .surface
= VDP_INVALID_HANDLE
,
381 static void resize(struct vo
*vo
)
383 struct vdpctx
*vc
= vo
->priv
;
384 struct vdp_functions
*vdp
= vc
->vdp
;
386 struct vo_rect src_rect
;
387 struct vo_rect dst_rect
;
388 struct vo_rect borders
;
389 calc_src_dst_rects(vo
, vc
->vid_width
, vc
->vid_height
, &src_rect
, &dst_rect
,
391 vc
->out_rect_vid
.x0
= dst_rect
.left
;
392 vc
->out_rect_vid
.x1
= dst_rect
.right
;
393 vc
->out_rect_vid
.y0
= dst_rect
.top
;
394 vc
->out_rect_vid
.y1
= dst_rect
.bottom
;
395 vc
->src_rect_vid
.x0
= src_rect
.left
;
396 vc
->src_rect_vid
.x1
= src_rect
.right
;
397 vc
->src_rect_vid
.y0
= vc
->flip
? src_rect
.bottom
: src_rect
.top
;
398 vc
->src_rect_vid
.y1
= vc
->flip
? src_rect
.top
: src_rect
.bottom
;
399 vc
->border_x
= borders
.left
;
400 vc
->border_y
= borders
.top
;
401 int flip_offset_ms
= vo_fs
? vc
->flip_offset_fs
: vc
->flip_offset_window
;
402 vo
->flip_queue_offset
= flip_offset_ms
/ 1000.;
404 if (vc
->output_surface_width
< vo
->dwidth
405 || vc
->output_surface_height
< vo
->dheight
) {
406 if (vc
->output_surface_width
< vo
->dwidth
) {
407 vc
->output_surface_width
+= vc
->output_surface_width
>> 1;
408 vc
->output_surface_width
= FFMAX(vc
->output_surface_width
,
411 if (vc
->output_surface_height
< vo
->dheight
) {
412 vc
->output_surface_height
+= vc
->output_surface_height
>> 1;
413 vc
->output_surface_height
= FFMAX(vc
->output_surface_height
,
416 // Creation of output_surfaces
417 for (int i
= 0; i
< vc
->num_output_surfaces
; i
++)
418 if (vc
->output_surfaces
[i
] != VDP_INVALID_HANDLE
) {
419 vdp_st
= vdp
->output_surface_destroy(vc
->output_surfaces
[i
]);
420 CHECK_ST_WARNING("Error when calling "
421 "vdp_output_surface_destroy");
423 for (int i
= 0; i
< vc
->num_output_surfaces
; i
++) {
424 vdp_st
= vdp
->output_surface_create(vc
->vdp_device
,
426 vc
->output_surface_width
,
427 vc
->output_surface_height
,
428 &vc
->output_surfaces
[i
]);
429 CHECK_ST_WARNING("Error when calling vdp_output_surface_create");
430 mp_msg(MSGT_VO
, MSGL_DBG2
, "vdpau out create: %u\n",
431 vc
->output_surfaces
[i
]);
434 vo
->want_redraw
= true;
437 static void preemption_callback(VdpDevice device
, void *context
)
439 struct vdpctx
*vc
= context
;
440 vc
->is_preempted
= true;
441 vc
->preemption_acked
= false;
444 /* Initialize vdp_get_proc_address, called from preinit() */
445 static int win_x11_init_vdpau_procs(struct vo
*vo
)
447 struct vo_x11_state
*x11
= vo
->x11
;
448 struct vdpctx
*vc
= vo
->priv
;
449 if (vc
->vdp
) // reinitialization after preemption
450 memset(vc
->vdp
, 0, sizeof(*vc
->vdp
));
452 vc
->vdp
= talloc_zero(vc
, struct vdp_functions
);
453 struct vdp_functions
*vdp
= vc
->vdp
;
456 struct vdp_function
{
461 const struct vdp_function
*dsc
;
463 static const struct vdp_function vdp_func
[] = {
464 #define VDP_FUNCTION(_, macro_name, mp_name) {macro_name, offsetof(struct vdp_functions, mp_name)},
465 #include "vdpau_template.c"
470 vdp_st
= vdp_device_create_x11(x11
->display
, x11
->screen
, &vc
->vdp_device
,
471 &vc
->vdp_get_proc_address
);
472 if (vdp_st
!= VDP_STATUS_OK
) {
473 if (vc
->is_preempted
)
474 mp_msg(MSGT_VO
, MSGL_DBG2
, "[vdpau] Error calling "
475 "vdp_device_create_x11 while preempted: %d\n", vdp_st
);
477 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling "
478 "vdp_device_create_x11: %d\n", vdp_st
);
482 vdp
->get_error_string
= NULL
;
483 for (dsc
= vdp_func
; dsc
->offset
>= 0; dsc
++) {
484 vdp_st
= vc
->vdp_get_proc_address(vc
->vdp_device
, dsc
->id
,
485 (void **)((char *)vdp
+ dsc
->offset
));
486 if (vdp_st
!= VDP_STATUS_OK
) {
487 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling "
488 "vdp_get_proc_address(function id %d): %s\n", dsc
->id
,
489 vdp
->get_error_string
? vdp
->get_error_string(vdp_st
) : "?");
493 vdp_st
= vdp
->preemption_callback_register(vc
->vdp_device
,
494 preemption_callback
, vc
);
498 static int win_x11_init_vdpau_flip_queue(struct vo
*vo
)
500 struct vdpctx
*vc
= vo
->priv
;
501 struct vdp_functions
*vdp
= vc
->vdp
;
502 struct vo_x11_state
*x11
= vo
->x11
;
505 if (vc
->flip_target
== VDP_INVALID_HANDLE
) {
506 vdp_st
= vdp
->presentation_queue_target_create_x11(vc
->vdp_device
,
509 CHECK_ST_ERROR("Error when calling "
510 "vdp_presentation_queue_target_create_x11");
513 /* Emperically this seems to be the first call which fails when we
514 * try to reinit after preemption while the user is still switched
515 * from X to a virtual terminal (creating the vdp_device initially
516 * succeeds, as does creating the flip_target above). This is
517 * probably not guaranteed behavior, but we'll assume it as a simple
518 * way to reduce warnings while trying to recover from preemption.
520 if (vc
->flip_queue
== VDP_INVALID_HANDLE
) {
521 vdp_st
= vdp
->presentation_queue_create(vc
->vdp_device
, vc
->flip_target
,
523 if (vc
->is_preempted
&& vdp_st
!= VDP_STATUS_OK
) {
524 mp_msg(MSGT_VO
, MSGL_DBG2
, "[vdpau] Failed to create flip queue "
525 "while preempted: %s\n", vdp
->get_error_string(vdp_st
));
528 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create");
532 vdp_st
= vdp
->presentation_queue_get_time(vc
->flip_queue
, &vdp_time
);
533 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time");
534 vc
->last_vdp_time
= vdp_time
;
535 vc
->last_sync_update
= GetTimer();
537 vc
->vsync_interval
= 1;
538 if (vc
->composite_detect
&& vo_x11_screen_is_composited(vo
)) {
539 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] Compositing window manager "
540 "detected. Assuming timing info is inaccurate.\n");
541 } else if (vc
->user_fps
> 0) {
542 vc
->vsync_interval
= 1e9
/ vc
->user_fps
;
543 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] Assuming user-specified display "
544 "refresh rate of %.3f Hz.\n", vc
->user_fps
);
545 } else if (vc
->user_fps
== 0) {
547 double fps
= vo_vm_get_fps(vo
);
549 mp_msg(MSGT_VO
, MSGL_WARN
, "[vdpau] Failed to get display FPS\n");
551 vc
->vsync_interval
= 1e9
/ fps
;
552 // This is verbose, but I'm not yet sure how common wrong values are
553 mp_msg(MSGT_VO
, MSGL_INFO
,
554 "[vdpau] Got display refresh rate %.3f Hz.\n"
555 "[vdpau] If that value looks wrong give the "
556 "-vo vdpau:fps=X suboption manually.\n", fps
);
559 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] This binary has been compiled "
560 "without XF86VidMode support.\n");
561 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] Can't use vsync-aware timing "
562 "without manually provided -vo vdpau:fps=X suboption.\n");
565 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] framedrop/timing logic disabled by "
571 static int set_video_attribute(struct vdpctx
*vc
, VdpVideoMixerAttribute attr
,
572 const void *value
, char *attr_name
)
574 struct vdp_functions
*vdp
= vc
->vdp
;
577 vdp_st
= vdp
->video_mixer_set_attribute_values(vc
->video_mixer
, 1, &attr
,
579 if (vdp_st
!= VDP_STATUS_OK
) {
580 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error setting video mixer "
581 "attribute %s: %s\n", attr_name
, vdp
->get_error_string(vdp_st
));
587 static void update_csc_matrix(struct vo
*vo
)
589 struct vdpctx
*vc
= vo
->priv
;
591 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Updating CSC matrix\n");
593 // VdpCSCMatrix happens to be compatible with mplayer's CSC matrix type
594 // both are float[3][4]
597 struct mp_csp_params cparams
= {
598 .colorspace
= vc
->colorspace
, .input_bits
= 8, .texture_bits
= 8 };
599 mp_csp_copy_equalizer_values(&cparams
, &vc
->video_eq
);
600 mp_get_yuv2rgb_coeffs(&cparams
, matrix
);
602 set_video_attribute(vc
, VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX
,
603 &matrix
, "CSC matrix");
606 #define SET_VIDEO_ATTR(attr_name, attr_type, value) set_video_attribute(vc, \
607 VDP_VIDEO_MIXER_ATTRIBUTE_ ## attr_name, &(attr_type){value},\
609 static int create_vdp_mixer(struct vo
*vo
, VdpChromaType vdp_chroma_type
)
611 struct vdpctx
*vc
= vo
->priv
;
612 struct vdp_functions
*vdp
= vc
->vdp
;
613 #define VDP_NUM_MIXER_PARAMETER 3
614 #define MAX_NUM_FEATURES 6
618 if (vc
->video_mixer
!= VDP_INVALID_HANDLE
)
621 int feature_count
= 0;
622 VdpVideoMixerFeature features
[MAX_NUM_FEATURES
];
623 VdpBool feature_enables
[MAX_NUM_FEATURES
];
624 static const VdpVideoMixerParameter parameters
[VDP_NUM_MIXER_PARAMETER
] = {
625 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
,
626 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
,
627 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
,
629 const void *const parameter_values
[VDP_NUM_MIXER_PARAMETER
] = {
634 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
;
635 if (vc
->deint_type
== 4)
636 features
[feature_count
++] =
637 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
;
639 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
;
641 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
;
643 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS
;
645 VdpVideoMixerFeature hqscaling_feature
=
646 VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
+ vc
->hqscaling
-1;
647 VdpBool hqscaling_available
;
648 vdp_st
= vdp
->video_mixer_query_feature_support(vc
->vdp_device
,
650 &hqscaling_available
);
651 CHECK_ST_ERROR("Error when calling video_mixer_query_feature_support");
652 if (hqscaling_available
)
653 features
[feature_count
++] = hqscaling_feature
;
655 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Your hardware or VDPAU "
656 "library does not support requested hqscaling.\n");
659 vdp_st
= vdp
->video_mixer_create(vc
->vdp_device
, feature_count
, features
,
660 VDP_NUM_MIXER_PARAMETER
,
661 parameters
, parameter_values
,
663 CHECK_ST_ERROR("Error when calling vdp_video_mixer_create");
665 for (i
= 0; i
< feature_count
; i
++)
666 feature_enables
[i
] = VDP_TRUE
;
668 feature_enables
[0] = VDP_FALSE
;
669 if (vc
->deint_type
== 4 && vc
->deint
< 4)
670 feature_enables
[1] = VDP_FALSE
;
672 vdp_st
= vdp
->video_mixer_set_feature_enables(vc
->video_mixer
,
673 feature_count
, features
,
675 CHECK_ST_WARNING("Error calling vdp_video_mixer_set_feature_enables");
678 SET_VIDEO_ATTR(NOISE_REDUCTION_LEVEL
, float, vc
->denoise
);
680 SET_VIDEO_ATTR(SHARPNESS_LEVEL
, float, vc
->sharpen
);
681 if (!vc
->chroma_deint
)
682 SET_VIDEO_ATTR(SKIP_CHROMA_DEINTERLACE
, uint8_t, 1);
684 update_csc_matrix(vo
);
688 // Free everything specific to a certain video file
689 static void free_video_specific(struct vo
*vo
)
691 struct vdpctx
*vc
= vo
->priv
;
692 struct vdp_functions
*vdp
= vc
->vdp
;
696 if (vc
->decoder
!= VDP_INVALID_HANDLE
)
697 vdp
->decoder_destroy(vc
->decoder
);
698 vc
->decoder
= VDP_INVALID_HANDLE
;
699 vc
->decoder_max_refs
= -1;
703 for (i
= 0; i
< MAX_VIDEO_SURFACES
; i
++) {
704 if (vc
->surface_render
[i
].surface
!= VDP_INVALID_HANDLE
) {
705 vdp_st
= vdp
->video_surface_destroy(vc
->surface_render
[i
].surface
);
706 CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy");
708 vc
->surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
711 if (vc
->video_mixer
!= VDP_INVALID_HANDLE
) {
712 vdp_st
= vdp
->video_mixer_destroy(vc
->video_mixer
);
713 CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy");
715 vc
->video_mixer
= VDP_INVALID_HANDLE
;
717 if (vc
->screenshot_surface
!= VDP_INVALID_HANDLE
) {
718 vdp_st
= vdp
->output_surface_destroy(vc
->screenshot_surface
);
719 CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
721 vc
->screenshot_surface
= VDP_INVALID_HANDLE
;
724 static int create_vdp_decoder(struct vo
*vo
, int max_refs
)
726 struct vdpctx
*vc
= vo
->priv
;
727 struct vdp_functions
*vdp
= vc
->vdp
;
729 VdpDecoderProfile vdp_decoder_profile
;
730 if (vc
->decoder
!= VDP_INVALID_HANDLE
)
731 vdp
->decoder_destroy(vc
->decoder
);
732 switch (vc
->image_format
) {
733 case IMGFMT_VDPAU_MPEG1
:
734 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG1
;
736 case IMGFMT_VDPAU_MPEG2
:
737 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG2_MAIN
;
739 case IMGFMT_VDPAU_H264
:
740 vdp_decoder_profile
= VDP_DECODER_PROFILE_H264_HIGH
;
741 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Creating H264 hardware decoder "
742 "for %d reference frames.\n", max_refs
);
744 case IMGFMT_VDPAU_WMV3
:
745 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_MAIN
;
747 case IMGFMT_VDPAU_VC1
:
748 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_ADVANCED
;
750 case IMGFMT_VDPAU_MPEG4
:
751 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG4_PART2_ASP
;
754 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Unknown image format!\n");
757 vdp_st
= vdp
->decoder_create(vc
->vdp_device
, vdp_decoder_profile
,
758 vc
->vid_width
, vc
->vid_height
, max_refs
,
760 CHECK_ST_WARNING("Failed creating VDPAU decoder");
761 if (vdp_st
!= VDP_STATUS_OK
) {
763 vc
->decoder
= VDP_INVALID_HANDLE
;
764 vc
->decoder_max_refs
= 0;
767 vc
->decoder_max_refs
= max_refs
;
771 static int initialize_vdpau_objects(struct vo
*vo
)
773 struct vdpctx
*vc
= vo
->priv
;
775 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_420
;
776 switch (vc
->image_format
) {
780 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_YV12
;
783 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_NV12
;
786 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_YUYV
;
787 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_422
;
790 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_UYVY
;
791 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_422
;
793 if (win_x11_init_vdpau_flip_queue(vo
) < 0)
796 if (create_vdp_mixer(vo
, vc
->vdp_chroma_type
) < 0)
804 static void mark_vdpau_objects_uninitialized(struct vo
*vo
)
806 struct vdpctx
*vc
= vo
->priv
;
808 vc
->decoder
= VDP_INVALID_HANDLE
;
809 for (int i
= 0; i
< MAX_VIDEO_SURFACES
; i
++)
810 vc
->surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
812 vc
->video_mixer
= VDP_INVALID_HANDLE
;
813 vc
->flip_queue
= VDP_INVALID_HANDLE
;
814 vc
->flip_target
= VDP_INVALID_HANDLE
;
815 for (int i
= 0; i
< MAX_OUTPUT_SURFACES
; i
++)
816 vc
->output_surfaces
[i
] = VDP_INVALID_HANDLE
;
817 vc
->screenshot_surface
= VDP_INVALID_HANDLE
;
818 vc
->vdp_device
= VDP_INVALID_HANDLE
;
819 talloc_free(vc
->osd_surface
.packer
);
820 talloc_free(vc
->eosd_surface
.packer
);
821 vc
->bitmap_id
= vc
->bitmap_pos_id
= 0;
822 vc
->osd_surface
= vc
->eosd_surface
= (struct eosd_bitmap_surface
){
823 .surface
= VDP_INVALID_HANDLE
,
825 vc
->output_surface_width
= vc
->output_surface_height
= -1;
826 vc
->eosd_render_count
= 0;
829 static int handle_preemption(struct vo
*vo
)
831 struct vdpctx
*vc
= vo
->priv
;
833 if (!vc
->is_preempted
)
835 if (!vc
->preemption_acked
)
836 mark_vdpau_objects_uninitialized(vo
);
837 vc
->preemption_acked
= true;
838 if (!vc
->preemption_user_notified
) {
839 mp_tmsg(MSGT_VO
, MSGL_ERR
, "[vdpau] Got display preemption notice! "
840 "Will attempt to recover.\n");
841 vc
->preemption_user_notified
= true;
843 /* Trying to initialize seems to be quite slow, so only try once a
844 * second to avoid using 100% CPU. */
845 if (vc
->last_preemption_retry_fail
846 && GetTimerMS() - vc
->last_preemption_retry_fail
< 1000)
848 if (win_x11_init_vdpau_procs(vo
) < 0 || initialize_vdpau_objects(vo
) < 0) {
849 vc
->last_preemption_retry_fail
= GetTimerMS() | 1;
852 vc
->last_preemption_retry_fail
= 0;
853 vc
->is_preempted
= false;
854 vc
->preemption_user_notified
= false;
855 mp_tmsg(MSGT_VO
, MSGL_INFO
, "[vdpau] Recovered from display preemption.\n");
860 * connect to X server, create and map window, initialize all
861 * VDPAU objects, create different surfaces etc.
863 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
864 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
867 struct vdpctx
*vc
= vo
->priv
;
868 struct vo_x11_state
*x11
= vo
->x11
;
870 XSetWindowAttributes xswa
;
871 XWindowAttributes attribs
;
872 unsigned long xswamask
;
876 int vm
= flags
& VOFLAG_MODESWITCHING
;
879 if (handle_preemption(vo
) < 0)
882 vc
->flip
= flags
& VOFLAG_FLIPPING
;
883 vc
->image_format
= format
;
884 vc
->vid_width
= width
;
885 vc
->vid_height
= height
;
886 vc
->vid_d_width
= d_width
;
887 vc
->vid_d_height
= d_height
;
889 free_video_specific(vo
);
890 if (IMGFMT_IS_VDPAU(vc
->image_format
) && !create_vdp_decoder(vo
, 2))
896 vc
->mode_switched
= true;
899 XGetWindowAttributes(x11
->display
, DefaultRootWindow(x11
->display
),
901 depth
= attribs
.depth
;
902 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
904 XMatchVisualInfo(x11
->display
, x11
->screen
, depth
, TrueColor
, &vinfo
);
906 xswa
.background_pixel
= 0;
907 xswa
.border_pixel
= 0;
908 /* Do not use CWBackPixel: It leads to VDPAU errors after
909 * aspect ratio changes. */
910 xswamask
= CWBorderPixel
;
912 vo_x11_create_vo_window(vo
, &vinfo
, vo
->dx
, vo
->dy
, d_width
, d_height
,
913 flags
, CopyFromParent
, "vdpau");
914 XChangeWindowAttributes(x11
->display
, x11
->window
, xswamask
, &xswa
);
918 /* Grab the mouse pointer in our window */
920 XGrabPointer(x11
->display
, x11
->window
, True
, 0,
921 GrabModeAsync
, GrabModeAsync
,
922 x11
->window
, None
, CurrentTime
);
923 XSetInputFocus(x11
->display
, x11
->window
, RevertToNone
, CurrentTime
);
927 if ((flags
& VOFLAG_FULLSCREEN
) && WinID
<= 0)
930 if (initialize_vdpau_objects(vo
) < 0)
936 static void check_events(struct vo
*vo
)
938 if (handle_preemption(vo
) < 0)
941 int e
= vo_x11_check_events(vo
);
943 if (e
& VO_EVENT_RESIZE
)
945 else if (e
& VO_EVENT_EXPOSE
) {
946 vo
->want_redraw
= true;
950 static struct bitmap_packer
*make_packer(struct vo
*vo
, VdpRGBAFormat format
)
952 struct vdpctx
*vc
= vo
->priv
;
953 struct vdp_functions
*vdp
= vc
->vdp
;
955 struct bitmap_packer
*packer
= talloc_zero(vo
, struct bitmap_packer
);
956 uint32_t w_max
= 0, h_max
= 0;
957 VdpStatus vdp_st
= vdp
->
958 bitmap_surface_query_capabilities(vc
->vdp_device
, format
,
959 &(VdpBool
){0}, &w_max
, &h_max
);
960 CHECK_ST_WARNING("Query to get max EOSD surface size failed");
961 packer
->w_max
= w_max
;
962 packer
->h_max
= h_max
;
966 static void draw_eosd(struct vo
*vo
)
968 struct vdpctx
*vc
= vo
->priv
;
969 struct vdp_functions
*vdp
= vc
->vdp
;
971 VdpOutputSurface output_surface
= vc
->output_surfaces
[vc
->surface_num
];
974 VdpOutputSurfaceRenderBlendState blend_state
= {
975 .struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
,
976 .blend_factor_source_color
=
977 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
978 .blend_factor_source_alpha
=
979 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
980 .blend_factor_destination_color
=
981 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
982 .blend_factor_destination_alpha
=
983 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
984 .blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
985 .blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
988 for (i
= 0; i
< vc
->eosd_render_count
; i
++) {
990 output_surface_render_bitmap_surface(output_surface
,
991 &vc
->eosd_targets
[i
].dest
,
992 vc
->eosd_surface
.surface
,
993 &vc
->eosd_targets
[i
].source
,
994 &vc
->eosd_targets
[i
].color
,
996 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
997 CHECK_ST_WARNING("EOSD: Error when rendering");
1001 static void generate_eosd(struct vo
*vo
, mp_eosd_images_t
*imgs
)
1003 struct vdpctx
*vc
= vo
->priv
;
1004 struct vdp_functions
*vdp
= vc
->vdp
;
1006 struct eosd_bitmap_surface
*sfc
= &vc
->eosd_surface
;
1007 bool need_upload
= false;
1009 if (imgs
->bitmap_pos_id
== vc
->bitmap_pos_id
)
1010 return; // Nothing changed and we still have the old data
1012 vc
->eosd_render_count
= 0;
1014 if (imgs
->type
== SUBBITMAP_EMPTY
)
1017 if (imgs
->bitmap_id
== vc
->bitmap_id
)
1018 goto eosd_skip_upload
;
1021 VdpRGBAFormat format
;
1023 switch (imgs
->type
) {
1024 case SUBBITMAP_LIBASS
:
1025 format
= VDP_RGBA_FORMAT_A8
;
1028 case SUBBITMAP_RGBA
:
1029 format
= VDP_RGBA_FORMAT_B8G8R8A8
;
1035 if (sfc
->format
!= format
) {
1036 talloc_free(sfc
->packer
);
1039 sfc
->format
= format
;
1041 sfc
->packer
= make_packer(vo
, format
);
1042 int r
= packer_pack_from_subbitmaps(sfc
->packer
, imgs
, imgs
->scaled
);
1044 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] EOSD bitmaps do not fit on "
1045 "a surface with the maximum supported size\n");
1047 } else if (r
== 1) {
1048 if (sfc
->surface
!= VDP_INVALID_HANDLE
) {
1049 vdp_st
= vdp
->bitmap_surface_destroy(sfc
->surface
);
1050 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
1052 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Allocating a %dx%d surface for "
1053 "EOSD bitmaps.\n", sfc
->packer
->w
, sfc
->packer
->h
);
1054 vdp_st
= vdp
->bitmap_surface_create(vc
->vdp_device
, format
,
1055 sfc
->packer
->w
, sfc
->packer
->h
,
1056 true, &sfc
->surface
);
1057 if (vdp_st
!= VDP_STATUS_OK
)
1058 sfc
->surface
= VDP_INVALID_HANDLE
;
1059 CHECK_ST_WARNING("EOSD: error when creating surface");
1062 char zeros
[sfc
->packer
->used_width
* format_size
];
1063 memset(zeros
, 0, sizeof(zeros
));
1064 vdp_st
= vdp
->bitmap_surface_put_bits_native(sfc
->surface
,
1065 &(const void *){zeros
}, &(uint32_t){0},
1066 &(VdpRect
){0, 0, sfc
->packer
->used_width
,
1067 sfc
->packer
->used_height
});
1071 if (sfc
->surface
== VDP_INVALID_HANDLE
)
1073 if (sfc
->packer
->count
> vc
->eosd_targets_size
) {
1074 talloc_free(vc
->eosd_targets
);
1075 vc
->eosd_targets_size
= sfc
->packer
->count
;
1076 vc
->eosd_targets
= talloc_size(vc
, vc
->eosd_targets_size
1077 * sizeof(*vc
->eosd_targets
));
1080 if (imgs
->type
== SUBBITMAP_LIBASS
) {
1082 for (ASS_Image
*p
= imgs
->imgs
; p
; p
= p
->next
, i
++) {
1083 if (p
->w
== 0 || p
->h
== 0)
1085 struct eosd_target
*target
= vc
->eosd_targets
+
1086 vc
->eosd_render_count
;
1087 int x
= sfc
->packer
->result
[i
].x
;
1088 int y
= sfc
->packer
->result
[i
].y
;
1089 target
->source
= (VdpRect
){x
, y
, x
+ p
->w
, y
+ p
->h
};
1092 bitmap_surface_put_bits_native(sfc
->surface
,
1093 (const void *) &p
->bitmap
,
1094 &p
->stride
, &target
->source
);
1095 CHECK_ST_WARNING("EOSD: putbits failed");
1097 // Render dest, color, etc.
1098 target
->color
.alpha
= 1.0 - ((p
->color
>> 0) & 0xff) / 255.0;
1099 target
->color
.blue
= ((p
->color
>> 8) & 0xff) / 255.0;
1100 target
->color
.green
= ((p
->color
>> 16) & 0xff) / 255.0;
1101 target
->color
.red
= ((p
->color
>> 24) & 0xff) / 255.0;
1102 target
->dest
.x0
= p
->dst_x
;
1103 target
->dest
.y0
= p
->dst_y
;
1104 target
->dest
.x1
= p
->w
+ p
->dst_x
;
1105 target
->dest
.y1
= p
->h
+ p
->dst_y
;
1106 vc
->eosd_render_count
++;
1109 for (int i
= 0 ;i
< sfc
->packer
->count
; i
++) {
1110 struct sub_bitmap
*b
= &imgs
->parts
[i
];
1111 struct eosd_target
*target
= vc
->eosd_targets
+
1112 vc
->eosd_render_count
;
1113 int x
= sfc
->packer
->result
[i
].x
;
1114 int y
= sfc
->packer
->result
[i
].y
;
1115 target
->source
= (VdpRect
){x
, y
, x
+ b
->w
, y
+ b
->h
};
1118 bitmap_surface_put_bits_native(sfc
->surface
,
1119 &(const void *){b
->bitmap
},
1120 &(uint32_t){b
->w
* 4},
1122 CHECK_ST_WARNING("EOSD: putbits failed");
1124 target
->color
= (VdpColor
){1, 1, 1, 1};
1125 target
->dest
= (VdpRect
){b
->x
, b
->y
, b
->x
+ b
->dw
, b
->y
+ b
->dh
};
1126 vc
->eosd_render_count
++;
1129 vc
->bitmap_id
= imgs
->bitmap_id
;
1130 vc
->bitmap_pos_id
= imgs
->bitmap_pos_id
;
1133 static void record_osd(void *ctx
, int x0
, int y0
, int w
, int h
,
1134 unsigned char *src
, unsigned char *srca
, int stride
)
1136 struct vo
*vo
= ctx
;
1137 struct vdpctx
*vc
= vo
->priv
;
1139 assert(vc
->old_osd_count
< MAX_OLD_OSD_BITMAPS
);
1142 vc
->old_osd_elements
[vc
->old_osd_count
++] = (struct old_osd
){
1143 x0
, y0
, w
, h
, src
, srca
, stride
};
1146 static void render_old_osd(struct vo
*vo
)
1148 struct vdpctx
*vc
= vo
->priv
;
1149 struct vdp_functions
*vdp
= vc
->vdp
;
1150 VdpOutputSurface output_surface
= vc
->output_surfaces
[vc
->surface_num
];
1152 struct eosd_bitmap_surface
*sfc
= &vc
->osd_surface
;
1155 sfc
->packer
= make_packer(vo
, VDP_RGBA_FORMAT_A8
);
1157 packer_set_size(sfc
->packer
, vc
->old_osd_count
* 2);
1158 for (int i
= 0; i
< vc
->old_osd_count
; i
++) {
1159 struct old_osd
*o
= &vc
->old_osd_elements
[i
];
1160 sfc
->packer
->in
[i
*2] = sfc
->packer
->in
[i
*2 + 1] =
1161 (struct pos
){o
->w
, o
->h
};
1163 int r
= packer_pack(sfc
->packer
);
1165 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] OSD bitmaps do not fit on "
1166 "a surface with the maximum supported size\n");
1167 vc
->old_osd_count
= 0;
1169 } else if (r
== 1) {
1170 if (sfc
->surface
!= VDP_INVALID_HANDLE
) {
1171 vdp_st
= vdp
->bitmap_surface_destroy(sfc
->surface
);
1172 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
1174 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Allocating a %dx%d surface for "
1175 "OSD bitmaps.\n", sfc
->packer
->w
, sfc
->packer
->h
);
1176 vdp_st
= vdp
->bitmap_surface_create(vc
->vdp_device
, VDP_RGBA_FORMAT_A8
,
1177 sfc
->packer
->w
, sfc
->packer
->h
,
1178 true, &sfc
->surface
);
1179 if (vdp_st
!= VDP_STATUS_OK
)
1180 sfc
->surface
= VDP_INVALID_HANDLE
;
1181 CHECK_ST_WARNING("OSD: error when creating surface");
1184 for (int i
= 0; i
< vc
->old_osd_count
; i
++) {
1185 struct old_osd
*o
= &vc
->old_osd_elements
[i
];
1186 struct eosd_target
*target1
= &vc
->osd_targets
[i
][0];
1187 struct eosd_target
*target2
= &vc
->osd_targets
[i
][1];
1188 int w
= o
->w
, h
= o
->h
;
1189 int sx
= sfc
->packer
->result
[i
* 2].x
;
1190 int sy
= sfc
->packer
->result
[i
* 2].y
;
1191 target1
->source
= (VdpRect
){ sx
, sy
, sx
+ w
, sy
+ h
};
1192 target1
->dest
= (VdpRect
){ o
->x0
, o
->y0
, o
->x0
+ w
, o
->y0
+ h
};
1193 sx
= sfc
->packer
->result
[i
* 2 + 1].x
;
1194 sy
= sfc
->packer
->result
[i
* 2 + 1].y
;
1195 target2
->source
= (VdpRect
){ sx
, sy
, sx
+ w
, sy
+ h
};
1196 target2
->dest
= target1
->dest
;
1197 vdp_st
= vdp
->bitmap_surface_put_bits_native(sfc
->surface
,
1198 &(const void *){o
->src
},
1199 &(uint32_t){o
->stride
},
1201 CHECK_ST_WARNING("OSD: putbits failed");
1202 int size_required
= w
* h
;
1203 if (vc
->osd_data_size
< size_required
) {
1204 talloc_free(vc
->osd_data_temp
);
1205 vc
->osd_data_temp
= talloc_size(vc
, size_required
);
1206 vc
->osd_data_size
= size_required
;
1208 for (int y
= 0; y
< h
; y
++)
1209 for (int x
= 0; x
< w
; x
++)
1210 vc
->osd_data_temp
[y
* w
+ x
] = -o
->srca
[y
* o
->stride
+ x
];
1211 vdp_st
= vdp
->bitmap_surface_put_bits_native(sfc
->surface
,
1212 &(const void *){vc
->osd_data_temp
},
1215 CHECK_ST_WARNING("OSD: putbits failed");
1218 VdpOutputSurfaceRenderBlendState blend_state_alpha
= {
1219 .struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
,
1220 .blend_factor_source_color
=
1221 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO
,
1222 .blend_factor_source_alpha
=
1223 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ZERO
,
1224 .blend_factor_destination_color
=
1225 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
1226 .blend_factor_destination_alpha
=
1227 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
1228 .blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1229 .blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1232 VdpOutputSurfaceRenderBlendState blend_state_gray
= {
1233 .struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
,
1234 .blend_factor_source_color
=
1235 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
1236 .blend_factor_source_alpha
=
1237 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
1238 .blend_factor_destination_color
=
1239 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
1240 .blend_factor_destination_alpha
=
1241 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
1242 .blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1243 .blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1246 for (int i
= 0; i
< vc
->old_osd_count
; i
++) {
1247 struct eosd_target
*target1
= &vc
->osd_targets
[i
][0];
1248 struct eosd_target
*target2
= &vc
->osd_targets
[i
][1];
1250 output_surface_render_bitmap_surface(output_surface
,
1252 vc
->osd_surface
.surface
,
1254 &(VdpColor
){1, 1, 1, 1},
1256 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
1257 CHECK_ST_WARNING("OSD: Error when rendering");
1259 output_surface_render_bitmap_surface(output_surface
,
1261 vc
->osd_surface
.surface
,
1263 &(VdpColor
){1, 1, 1, 1},
1265 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
1266 CHECK_ST_WARNING("OSD: Error when rendering");
1270 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
1272 struct vdpctx
*vc
= vo
->priv
;
1274 if (handle_preemption(vo
) < 0)
1277 vc
->old_osd_count
= 0;
1278 osd_draw_text_ext(osd
, vo
->dwidth
, vo
->dheight
, vc
->border_x
, vc
->border_y
,
1279 vc
->border_x
, vc
->border_y
, vc
->vid_width
,
1280 vc
->vid_height
, record_osd
, vo
);
1284 static int update_presentation_queue_status(struct vo
*vo
)
1286 struct vdpctx
*vc
= vo
->priv
;
1287 struct vdp_functions
*vdp
= vc
->vdp
;
1290 while (vc
->query_surface_num
!= vc
->surface_num
) {
1292 VdpPresentationQueueStatus status
;
1293 VdpOutputSurface surface
= vc
->output_surfaces
[vc
->query_surface_num
];
1294 vdp_st
= vdp
->presentation_queue_query_surface_status(vc
->flip_queue
,
1297 CHECK_ST_WARNING("Error calling "
1298 "presentation_queue_query_surface_status");
1299 if (status
== VDP_PRESENTATION_QUEUE_STATUS_QUEUED
)
1301 if (vc
->vsync_interval
> 1) {
1302 uint64_t qtime
= vc
->queue_time
[vc
->query_surface_num
];
1303 if (vtime
< qtime
+ vc
->vsync_interval
/ 2)
1304 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Frame shown too early\n");
1305 if (vtime
> qtime
+ vc
->vsync_interval
)
1306 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Frame shown late\n");
1308 vc
->query_surface_num
= WRAP_ADD(vc
->query_surface_num
, 1,
1309 vc
->num_output_surfaces
);
1310 vc
->recent_vsync_time
= vtime
;
1312 int num_queued
= WRAP_ADD(vc
->surface_num
, -vc
->query_surface_num
,
1313 vc
->num_output_surfaces
);
1314 mp_msg(MSGT_VO
, MSGL_DBG3
, "[vdpau] Queued surface count (before add): "
1315 "%d\n", num_queued
);
1319 static inline uint64_t prev_vs2(struct vdpctx
*vc
, uint64_t ts
, int shift
)
1321 uint64_t offset
= ts
- vc
->recent_vsync_time
;
1322 // Fix negative values for 1<<shift vsyncs before vc->recent_vsync_time
1323 offset
+= (uint64_t)vc
->vsync_interval
<< shift
;
1324 offset
%= vc
->vsync_interval
;
1328 static void flip_page_timed(struct vo
*vo
, unsigned int pts_us
, int duration
)
1330 struct vdpctx
*vc
= vo
->priv
;
1331 struct vdp_functions
*vdp
= vc
->vdp
;
1333 uint32_t vsync_interval
= vc
->vsync_interval
;
1335 if (handle_preemption(vo
) < 0)
1338 if (duration
> INT_MAX
/ 1000)
1343 if (vc
->vsync_interval
== 1)
1344 duration
= -1; // Make sure drop logic is disabled
1346 uint64_t now
= sync_vdptime(vo
);
1347 uint64_t pts
= pts_us
? convert_to_vdptime(vo
, pts_us
) : now
;
1348 uint64_t ideal_pts
= pts
;
1349 uint64_t npts
= duration
>= 0 ? pts
+ duration
: UINT64_MAX
;
1351 #define PREV_VS2(ts, shift) prev_vs2(vc, ts, shift)
1352 // Only gives accurate results for ts >= vc->recent_vsync_time
1353 #define PREV_VSYNC(ts) PREV_VS2(ts, 0)
1355 /* We hope to be here at least one vsync before the frame should be shown.
1356 * If we are running late then don't drop the frame unless there is
1357 * already one queued for the next vsync; even if we _hope_ to show the
1358 * next frame soon enough to mean this one should be dropped we might
1359 * not make the target time in reality. Without this check we could drop
1360 * every frame, freezing the display completely if video lags behind.
1362 if (now
> PREV_VSYNC(FFMAX(pts
, vc
->last_queue_time
+ vsync_interval
)))
1365 /* Allow flipping a frame at a vsync if its presentation time is a
1366 * bit after that vsync and the change makes the flip time delta
1367 * from previous frame better match the target timestamp delta.
1368 * This avoids instability with frame timestamps falling near vsyncs.
1369 * For example if the frame timestamps were (with vsyncs at
1370 * integer values) 0.01, 1.99, 4.01, 5.99, 8.01, ... then
1371 * straightforward timing at next vsync would flip the frames at
1372 * 1, 2, 5, 6, 9; this changes it to 1, 2, 4, 6, 8 and so on with
1373 * regular 2-vsync intervals.
1375 * Also allow moving the frame forward if it looks like we dropped
1376 * the previous frame incorrectly (now that we know better after
1377 * having final exact timestamp information for this frame) and
1378 * there would unnecessarily be a vsync without a frame change.
1380 uint64_t vsync
= PREV_VSYNC(pts
);
1381 if (pts
< vsync
+ vsync_interval
/ 4
1382 && (vsync
- PREV_VS2(vc
->last_queue_time
, 16)
1383 > pts
- vc
->last_ideal_time
+ vsync_interval
/ 2
1384 || vc
->dropped_frame
&& vsync
> vc
->dropped_time
))
1385 pts
-= vsync_interval
/ 2;
1387 vc
->dropped_frame
= true; // changed at end if false
1388 vc
->dropped_time
= ideal_pts
;
1390 pts
= FFMAX(pts
, vc
->last_queue_time
+ vsync_interval
);
1391 pts
= FFMAX(pts
, now
);
1392 if (npts
< PREV_VSYNC(pts
) + vsync_interval
)
1395 int num_flips
= update_presentation_queue_status(vo
);
1396 vsync
= vc
->recent_vsync_time
+ num_flips
* vc
->vsync_interval
;
1397 now
= sync_vdptime(vo
);
1398 pts
= FFMAX(pts
, now
);
1399 pts
= FFMAX(pts
, vsync
+ (vsync_interval
>> 2));
1400 vsync
= PREV_VSYNC(pts
);
1401 if (npts
< vsync
+ vsync_interval
)
1403 pts
= vsync
+ (vsync_interval
>> 2);
1405 vdp
->presentation_queue_display(vc
->flip_queue
,
1406 vc
->output_surfaces
[vc
->surface_num
],
1407 vo
->dwidth
, vo
->dheight
, pts
);
1408 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display");
1410 vc
->last_queue_time
= pts
;
1411 vc
->queue_time
[vc
->surface_num
] = pts
;
1412 vc
->last_ideal_time
= ideal_pts
;
1413 vc
->dropped_frame
= false;
1414 vc
->surface_num
= WRAP_ADD(vc
->surface_num
, 1, vc
->num_output_surfaces
);
1417 static int draw_slice(struct vo
*vo
, uint8_t *image
[], int stride
[], int w
,
1418 int h
, int x
, int y
)
1420 struct vdpctx
*vc
= vo
->priv
;
1421 struct vdp_functions
*vdp
= vc
->vdp
;
1424 if (handle_preemption(vo
) < 0)
1427 struct vdpau_render_state
*rndr
= (struct vdpau_render_state
*)image
[0];
1428 int max_refs
= vc
->image_format
== IMGFMT_VDPAU_H264
?
1429 rndr
->info
.h264
.num_ref_frames
: 2;
1430 if (!IMGFMT_IS_VDPAU(vc
->image_format
))
1432 if ((vc
->decoder
== VDP_INVALID_HANDLE
|| vc
->decoder_max_refs
< max_refs
)
1433 && !create_vdp_decoder(vo
, max_refs
))
1436 vdp_st
= vdp
->decoder_render(vc
->decoder
, rndr
->surface
,
1437 (void *)&rndr
->info
,
1438 rndr
->bitstream_buffers_used
,
1439 rndr
->bitstream_buffers
);
1440 CHECK_ST_WARNING("Failed VDPAU decoder rendering");
1445 static struct vdpau_render_state
*get_surface(struct vo
*vo
, int number
)
1447 struct vdpctx
*vc
= vo
->priv
;
1448 struct vdp_functions
*vdp
= vc
->vdp
;
1450 if (number
> MAX_VIDEO_SURFACES
)
1452 if (vc
->surface_render
[number
].surface
== VDP_INVALID_HANDLE
1453 && !vc
->is_preempted
) {
1455 vdp_st
= vdp
->video_surface_create(vc
->vdp_device
, vc
->vdp_chroma_type
,
1456 vc
->vid_width
, vc
->vid_height
,
1457 &vc
->surface_render
[number
].surface
);
1458 CHECK_ST_WARNING("Error when calling vdp_video_surface_create");
1460 mp_msg(MSGT_VO
, MSGL_DBG3
, "vdpau vid create: %u\n",
1461 vc
->surface_render
[number
].surface
);
1462 return &vc
->surface_render
[number
];
1465 static void draw_image(struct vo
*vo
, mp_image_t
*mpi
, double pts
)
1467 struct vdpctx
*vc
= vo
->priv
;
1468 struct vdp_functions
*vdp
= vc
->vdp
;
1469 struct mp_image
*reserved_mpi
= NULL
;
1470 struct vdpau_render_state
*rndr
;
1472 if (IMGFMT_IS_VDPAU(vc
->image_format
)) {
1475 } else if (!(mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)) {
1476 rndr
= get_surface(vo
, vc
->deint_counter
);
1477 vc
->deint_counter
= WRAP_ADD(vc
->deint_counter
, 1, NUM_BUFFERED_VIDEO
);
1478 if (handle_preemption(vo
) >= 0) {
1480 const void *destdata
[3] = {mpi
->planes
[0], mpi
->planes
[2],
1482 if (vc
->image_format
== IMGFMT_NV12
)
1483 destdata
[1] = destdata
[2];
1484 vdp_st
= vdp
->video_surface_put_bits_y_cb_cr(rndr
->surface
,
1485 vc
->vdp_pixel_format
, destdata
, mpi
->stride
);
1486 CHECK_ST_WARNING("Error when calling "
1487 "vdp_video_surface_put_bits_y_cb_cr");
1490 // We don't support slice callbacks so this shouldn't occur -
1491 // I think the flags test above in pointless, but I'm adding
1492 // this instead of removing it just in case.
1494 if (mpi
->fields
& MP_IMGFIELD_ORDERED
)
1495 vc
->top_field_first
= !!(mpi
->fields
& MP_IMGFIELD_TOP_FIRST
);
1497 vc
->top_field_first
= 1;
1499 add_new_video_surface(vo
, rndr
->surface
, reserved_mpi
, pts
);
1504 // warning: the size and pixel format of surface must match that of the
1505 // surfaces in vc->output_surfaces
1506 static struct mp_image
*read_output_surface(struct vdpctx
*vc
,
1507 VdpOutputSurface surface
,
1508 int width
, int height
)
1511 struct vdp_functions
*vdp
= vc
->vdp
;
1512 struct mp_image
*image
= alloc_mpi(width
, height
, IMGFMT_BGR32
);
1514 void *dst_planes
[] = { image
->planes
[0] };
1515 uint32_t dst_pitches
[] = { image
->stride
[0] };
1516 vdp_st
= vdp
->output_surface_get_bits_native(surface
, NULL
, dst_planes
,
1518 CHECK_ST_WARNING("Error when calling vdp_output_surface_get_bits_native");
1523 static struct mp_image
*get_screenshot(struct vo
*vo
)
1525 struct vdpctx
*vc
= vo
->priv
;
1527 struct vdp_functions
*vdp
= vc
->vdp
;
1529 if (vc
->screenshot_surface
== VDP_INVALID_HANDLE
) {
1530 vdp_st
= vdp
->output_surface_create(vc
->vdp_device
,
1532 vc
->vid_width
, vc
->vid_height
,
1533 &vc
->screenshot_surface
);
1534 CHECK_ST_WARNING("Error when calling vdp_output_surface_create");
1537 VdpRect rc
= { .x1
= vc
->vid_width
, .y1
= vc
->vid_height
};
1538 render_video_to_output_surface(vo
, vc
->screenshot_surface
, &rc
);
1540 struct mp_image
*image
= read_output_surface(vc
, vc
->screenshot_surface
,
1541 vc
->vid_width
, vc
->vid_height
);
1543 image
->width
= vc
->vid_width
;
1544 image
->height
= vc
->vid_height
;
1545 image
->w
= vc
->vid_d_width
;
1546 image
->h
= vc
->vid_d_height
;
1551 static struct mp_image
*get_window_screenshot(struct vo
*vo
)
1553 struct vdpctx
*vc
= vo
->priv
;
1554 int last_surface
= WRAP_ADD(vc
->surface_num
, -1, vc
->num_output_surfaces
);
1555 VdpOutputSurface screen
= vc
->output_surfaces
[last_surface
];
1556 struct mp_image
*image
= read_output_surface(vo
->priv
, screen
,
1557 vc
->output_surface_width
,
1558 vc
->output_surface_height
);
1559 image
->width
= image
->w
= vo
->dwidth
;
1560 image
->height
= image
->h
= vo
->dheight
;
1564 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
1566 struct vdpctx
*vc
= vo
->priv
;
1567 struct vdpau_render_state
*rndr
;
1569 // no dr for non-decoding for now
1570 if (!IMGFMT_IS_VDPAU(vc
->image_format
))
1572 if (mpi
->type
!= MP_IMGTYPE_NUMBERED
)
1575 rndr
= get_surface(vo
, mpi
->number
);
1577 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] no surfaces available in "
1579 // TODO: this probably breaks things forever, provide a dummy buffer?
1582 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1583 mpi
->stride
[0] = mpi
->stride
[1] = mpi
->stride
[2] = 0;
1584 mpi
->planes
[0] = mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
1585 // hack to get around a check and to avoid a special-case in vd_ffmpeg.c
1586 mpi
->planes
[0] = (void *)rndr
;
1587 mpi
->num_planes
= 1;
1592 static int query_format(uint32_t format
)
1594 int default_flags
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
1595 | VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_OSD
| VFCAP_EOSD
1596 | VFCAP_EOSD_UNSCALED
| VFCAP_EOSD_RGBA
| VFCAP_FLIP
;
1604 return default_flags
| VOCAP_NOSLICES
;
1605 case IMGFMT_VDPAU_MPEG1
:
1606 case IMGFMT_VDPAU_MPEG2
:
1607 case IMGFMT_VDPAU_H264
:
1608 case IMGFMT_VDPAU_WMV3
:
1609 case IMGFMT_VDPAU_VC1
:
1610 case IMGFMT_VDPAU_MPEG4
:
1611 return default_flags
;
1616 static void destroy_vdpau_objects(struct vo
*vo
)
1618 struct vdpctx
*vc
= vo
->priv
;
1619 struct vdp_functions
*vdp
= vc
->vdp
;
1624 free_video_specific(vo
);
1626 if (vc
->flip_queue
!= VDP_INVALID_HANDLE
) {
1627 vdp_st
= vdp
->presentation_queue_destroy(vc
->flip_queue
);
1628 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy");
1631 if (vc
->flip_target
!= VDP_INVALID_HANDLE
) {
1632 vdp_st
= vdp
->presentation_queue_target_destroy(vc
->flip_target
);
1633 CHECK_ST_WARNING("Error when calling "
1634 "vdp_presentation_queue_target_destroy");
1637 for (i
= 0; i
< vc
->num_output_surfaces
; i
++) {
1638 if (vc
->output_surfaces
[i
] == VDP_INVALID_HANDLE
)
1640 vdp_st
= vdp
->output_surface_destroy(vc
->output_surfaces
[i
]);
1641 CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
1644 if (vc
->eosd_surface
.surface
!= VDP_INVALID_HANDLE
) {
1645 vdp_st
= vdp
->bitmap_surface_destroy(vc
->eosd_surface
.surface
);
1646 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
1649 if (vc
->osd_surface
.surface
!= VDP_INVALID_HANDLE
) {
1650 vdp_st
= vdp
->bitmap_surface_destroy(vc
->osd_surface
.surface
);
1651 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
1654 vdp_st
= vdp
->device_destroy(vc
->vdp_device
);
1655 CHECK_ST_WARNING("Error when calling vdp_device_destroy");
1658 static void uninit(struct vo
*vo
)
1660 struct vdpctx
*vc
= vo
->priv
;
1662 /* Destroy all vdpau objects */
1663 destroy_vdpau_objects(vo
);
1665 #ifdef CONFIG_XF86VM
1666 if (vc
->mode_switched
)
1671 // Free bitstream buffers allocated by FFmpeg
1672 for (int i
= 0; i
< MAX_VIDEO_SURFACES
; i
++)
1673 av_freep(&vc
->surface_render
[i
].bitstream_buffers
);
1676 static int preinit(struct vo
*vo
, const char *arg
)
1678 struct vdpctx
*vc
= vo
->priv
;
1680 // Mark everything as invalid first so uninit() can tell what has been
1682 mark_vdpau_objects_uninitialized(vo
);
1684 vc
->colorspace
= (struct mp_csp_details
) MP_CSP_DETAILS_DEFAULTS
;
1685 vc
->video_eq
.capabilities
= MP_CSP_EQ_CAPS_COLORMATRIX
;
1687 vc
->deint_type
= vc
->deint
? FFABS(vc
->deint
) : 3;
1694 // After this calling uninit() should work to free resources
1696 if (win_x11_init_vdpau_procs(vo
) < 0) {
1697 if (vc
->vdp
->device_destroy
)
1698 vc
->vdp
->device_destroy(vc
->vdp_device
);
1706 static int get_equalizer(struct vo
*vo
, const char *name
, int *value
)
1708 struct vdpctx
*vc
= vo
->priv
;
1709 return mp_csp_equalizer_get(&vc
->video_eq
, name
, value
) >= 0 ?
1710 VO_TRUE
: VO_NOTIMPL
;
1713 static bool status_ok(struct vo
*vo
)
1715 if (!vo
->config_ok
|| handle_preemption(vo
) < 0)
1720 static int set_equalizer(struct vo
*vo
, const char *name
, int value
)
1722 struct vdpctx
*vc
= vo
->priv
;
1724 if (mp_csp_equalizer_set(&vc
->video_eq
, name
, value
) < 0)
1728 update_csc_matrix(vo
);
1732 static void checked_resize(struct vo
*vo
)
1739 static int control(struct vo
*vo
, uint32_t request
, void *data
)
1741 struct vdpctx
*vc
= vo
->priv
;
1742 struct vdp_functions
*vdp
= vc
->vdp
;
1744 handle_preemption(vo
);
1747 case VOCTRL_GET_DEINTERLACE
:
1748 *(int *)data
= vc
->deint
;
1750 case VOCTRL_SET_DEINTERLACE
:
1751 vc
->deint
= *(int *)data
;
1753 vc
->deint
= vc
->deint_type
;
1754 if (vc
->deint_type
> 2 && status_ok(vo
)) {
1756 VdpVideoMixerFeature features
[1] =
1757 {vc
->deint_type
== 3 ?
1758 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
1759 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
};
1760 VdpBool feature_enables
[1] = {vc
->deint
? VDP_TRUE
: VDP_FALSE
};
1761 vdp_st
= vdp
->video_mixer_set_feature_enables(vc
->video_mixer
,
1764 CHECK_ST_WARNING("Error changing deinterlacing settings");
1766 vo
->want_redraw
= true;
1769 if (vc
->dropped_frame
)
1770 vo
->want_redraw
= true;
1772 case VOCTRL_QUERY_FORMAT
:
1773 return query_format(*(uint32_t *)data
);
1774 case VOCTRL_GET_IMAGE
:
1775 return get_image(vo
, data
);
1776 case VOCTRL_DRAW_IMAGE
:
1777 abort(); // draw_image() should get called directly
1782 case VOCTRL_FULLSCREEN
:
1783 vo_x11_fullscreen(vo
);
1786 case VOCTRL_GET_PANSCAN
:
1788 case VOCTRL_SET_PANSCAN
:
1791 case VOCTRL_SET_EQUALIZER
: {
1792 vo
->want_redraw
= true;
1793 struct voctrl_set_equalizer_args
*args
= data
;
1794 return set_equalizer(vo
, args
->name
, args
->value
);
1796 case VOCTRL_GET_EQUALIZER
: {
1797 struct voctrl_get_equalizer_args
*args
= data
;
1798 return get_equalizer(vo
, args
->name
, args
->valueptr
);
1800 case VOCTRL_SET_YUV_COLORSPACE
:
1801 vc
->colorspace
= *(struct mp_csp_details
*)data
;
1803 update_csc_matrix(vo
);
1804 vo
->want_redraw
= true;
1806 case VOCTRL_GET_YUV_COLORSPACE
:
1807 *(struct mp_csp_details
*)data
= vc
->colorspace
;
1812 case VOCTRL_UPDATE_SCREENINFO
:
1813 update_xinerama_info(vo
);
1815 case VOCTRL_DRAW_EOSD
:
1818 if (status_ok(vo
)) {
1819 generate_eosd(vo
, data
);
1823 case VOCTRL_GET_EOSD_RES
: {
1824 struct mp_eosd_res
*r
= data
;
1827 r
->ml
= r
->mr
= vc
->border_x
;
1828 r
->mt
= r
->mb
= vc
->border_y
;
1831 case VOCTRL_NEWFRAME
:
1832 vc
->deint_queue_pos
= next_deint_queue_pos(vo
, true);
1834 video_to_output_surface(vo
);
1836 case VOCTRL_SKIPFRAME
:
1837 vc
->deint_queue_pos
= next_deint_queue_pos(vo
, true);
1839 case VOCTRL_REDRAW_FRAME
:
1841 video_to_output_surface(vo
);
1846 case VOCTRL_SCREENSHOT
: {
1849 struct voctrl_screenshot_args
*args
= data
;
1850 if (args
->full_window
)
1851 args
->out_image
= get_window_screenshot(vo
);
1853 args
->out_image
= get_screenshot(vo
);
1860 #undef OPT_BASE_STRUCT
1861 #define OPT_BASE_STRUCT struct vdpctx
1863 const struct vo_driver video_out_vdpau
= {
1865 .buffer_frames
= true,
1866 .info
= &(const struct vo_info_s
){
1869 "Rajib Mahapatra <rmahapatra@nvidia.com> and others",
1875 .draw_image
= draw_image
,
1876 .get_buffered_frame
= set_next_frame_info
,
1877 .draw_slice
= draw_slice
,
1878 .draw_osd
= draw_osd
,
1879 .flip_page_timed
= flip_page_timed
,
1880 .check_events
= check_events
,
1882 .privsize
= sizeof(struct vdpctx
),
1883 .options
= (const struct m_option
[]){
1884 OPT_INTRANGE("deint", deint
, 0, -4, 4),
1885 OPT_FLAG_ON("chroma-deint", chroma_deint
, 0, OPTDEF_INT(1)),
1886 OPT_FLAG_OFF("nochroma-deint", chroma_deint
, 0),
1887 OPT_MAKE_FLAGS("pullup", pullup
, 0),
1888 OPT_FLOATRANGE("denoise", denoise
, 0, 0, 1),
1889 OPT_FLOATRANGE("sharpen", sharpen
, 0, -1, 1),
1890 OPT_ERRORMESSAGE("colorspace", "vo_vdpau suboption \"colorspace\" has "
1891 "been removed. Use --colormatrix instead.\n"),
1892 OPT_ERRORMESSAGE("studio", "vo_vdpau suboption \"studio\" has been "
1893 "removed. Use --colormatrix-output-range=limited "
1895 OPT_INTRANGE("hqscaling", hqscaling
, 0, 0, 9),
1896 OPT_FLOAT("fps", user_fps
, 0),
1897 OPT_FLAG_ON("composite-detect", composite_detect
, 0, OPTDEF_INT(1)),
1898 OPT_INT("queuetime_windowed", flip_offset_window
, 0, OPTDEF_INT(50)),
1899 OPT_INT("queuetime_fs", flip_offset_fs
, 0, OPTDEF_INT(50)),
1900 OPT_INTRANGE("output_surfaces", num_output_surfaces
, 0,
1901 2, MAX_OUTPUT_SURFACES
, OPTDEF_INT(3)),