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.
41 #include "video_out.h"
42 #include "x11_common.h"
47 #include "libmpcodecs/vfcap.h"
48 #include "libmpcodecs/mp_image.h"
49 #include "osdep/timer.h"
51 #include "libavcodec/vdpau.h"
53 #include "sub/font_load.h"
55 #include "libavutil/common.h"
56 #include "libavutil/mathematics.h"
58 #include "sub/ass_mp.h"
60 #define WRAP_ADD(x, a, m) ((a) < 0 \
61 ? ((x)+(a)+(m) < (m) ? (x)+(a)+(m) : (x)+(a)) \
62 : ((x)+(a) < (m) ? (x)+(a) : (x)+(a)-(m)))
64 #define CHECK_ST_ERROR(message) \
66 if (vdp_st != VDP_STATUS_OK) { \
67 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \
68 message, vdp->get_error_string(vdp_st)); \
73 #define CHECK_ST_WARNING(message) \
75 if (vdp_st != VDP_STATUS_OK) \
76 mp_msg(MSGT_VO, MSGL_WARN, "[ vdpau] %s: %s\n", \
77 message, vdp->get_error_string(vdp_st)); \
80 /* number of video and output surfaces */
81 #define MAX_OUTPUT_SURFACES 15
82 #define MAX_VIDEO_SURFACES 50
83 #define NUM_BUFFERED_VIDEO 5
85 /* number of palette entries */
86 #define PALETTE_SIZE 256
88 /* Initial size of EOSD surface in pixels (x*x) */
89 #define EOSD_SURFACE_INITIAL_SIZE 256
91 /* Pixelformat used for output surfaces */
92 #define OUTPUT_RGBA_FORMAT VDP_RGBA_FORMAT_B8G8R8A8
95 * Global variable declaration - VDPAU specific
98 struct vdp_functions
{
99 #define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name;
100 #include "vdpau_template.c"
105 struct vdp_functions
*vdp
;
107 VdpDevice vdp_device
;
109 bool preemption_acked
;
110 bool preemption_user_notified
;
111 unsigned int last_preemption_retry_fail
;
112 VdpGetProcAddress
*vdp_get_proc_address
;
114 VdpPresentationQueueTarget flip_target
;
115 VdpPresentationQueue flip_queue
;
116 uint64_t last_vdp_time
;
117 unsigned int last_sync_update
;
119 /* an extra last output surface is used for OSD and screenshots */
120 VdpOutputSurface output_surfaces
[MAX_OUTPUT_SURFACES
+ 1];
121 int num_output_surfaces
;
122 struct buffered_video_surface
{
123 VdpVideoSurface surface
;
126 } buffered_video
[NUM_BUFFERED_VIDEO
];
128 int output_surface_width
, output_surface_height
;
130 VdpVideoMixer video_mixer
;
131 struct mp_csp_details colorspace
;
140 int flip_offset_window
;
146 int decoder_max_refs
;
148 VdpRect src_rect_vid
;
149 VdpRect out_rect_vid
;
150 int border_x
, border_y
;
152 struct vdpau_render_state surface_render
[MAX_VIDEO_SURFACES
];
154 int query_surface_num
;
155 VdpTime recent_vsync_time
;
157 int composite_detect
;
158 unsigned int vsync_interval
;
159 uint64_t last_queue_time
;
160 uint64_t queue_time
[MAX_OUTPUT_SURFACES
];
161 uint64_t last_ideal_time
;
163 uint64_t dropped_time
;
164 uint32_t vid_width
, vid_height
;
165 uint32_t vid_d_width
, vid_d_height
;
166 uint32_t image_format
;
167 VdpChromaType vdp_chroma_type
;
168 VdpYCbCrFormat vdp_pixel_format
;
171 unsigned char *index_data
;
173 uint32_t palette
[PALETTE_SIZE
];
177 struct eosd_bitmap_surface
{
178 VdpBitmapSurface surface
;
185 // List of surfaces to be rendered
191 int eosd_targets_size
;
194 int eosd_render_count
;
197 struct mp_csp_equalizer video_eq
;
199 // These tell what's been initialized and uninit() should free/uninitialize
203 static int change_vdptime_sync(struct vdpctx
*vc
, unsigned int *t
)
205 struct vdp_functions
*vdp
= vc
->vdp
;
208 vdp_st
= vdp
->presentation_queue_get_time(vc
->flip_queue
, &vdp_time
);
209 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time");
210 unsigned int t1
= *t
;
211 unsigned int t2
= GetTimer();
212 uint64_t old
= vc
->last_vdp_time
+ (t1
- vc
->last_sync_update
) * 1000ULL;
214 if (vdp_time
> old
+ (t2
- t1
) * 1000ULL)
215 vdp_time
-= (t2
- t1
) * 1000ULL;
218 mp_msg(MSGT_VO
, MSGL_DBG2
, "[vdpau] adjusting VdpTime offset by %f µs\n",
219 (int64_t)(vdp_time
- old
) / 1000.);
220 vc
->last_vdp_time
= vdp_time
;
221 vc
->last_sync_update
= t1
;
226 static uint64_t sync_vdptime(struct vo
*vo
)
228 struct vdpctx
*vc
= vo
->priv
;
230 unsigned int t
= GetTimer();
231 if (t
- vc
->last_sync_update
> 5000000)
232 change_vdptime_sync(vc
, &t
);
233 uint64_t now
= (t
- vc
->last_sync_update
) * 1000ULL + vc
->last_vdp_time
;
234 // Make sure nanosecond inaccuracies don't make things inconsistent
235 now
= FFMAX(now
, vc
->recent_vsync_time
);
239 static uint64_t convert_to_vdptime(struct vo
*vo
, unsigned int t
)
241 struct vdpctx
*vc
= vo
->priv
;
242 return (int)(t
- vc
->last_sync_update
) * 1000LL + vc
->last_vdp_time
;
245 static int render_video_to_output_surface(struct vo
*vo
,
246 VdpOutputSurface output_surface
,
247 VdpRect
*output_rect
)
249 struct vdpctx
*vc
= vo
->priv
;
250 struct vdp_functions
*vdp
= vc
->vdp
;
253 if (vc
->deint_queue_pos
< 0)
256 struct buffered_video_surface
*bv
= vc
->buffered_video
;
257 int field
= VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME
;
258 unsigned int dp
= vc
->deint_queue_pos
;
259 // dp==0 means last field of latest frame, 1 earlier field of latest frame,
260 // 2 last field of previous frame and so on
262 field
= vc
->top_field_first
^ (dp
& 1) ?
263 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD
:
264 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD
;
266 const VdpVideoSurface
*past_fields
= (const VdpVideoSurface
[]){
267 bv
[(dp
+1)/2].surface
, bv
[(dp
+2)/2].surface
};
268 const VdpVideoSurface
*future_fields
= (const VdpVideoSurface
[]){
269 dp
>= 1 ? bv
[(dp
-1)/2].surface
: VDP_INVALID_HANDLE
};
270 vdp_st
= vdp
->presentation_queue_block_until_surface_idle(vc
->flip_queue
,
273 CHECK_ST_WARNING("Error when calling "
274 "vdp_presentation_queue_block_until_surface_idle");
276 vdp_st
= vdp
->video_mixer_render(vc
->video_mixer
, VDP_INVALID_HANDLE
,
277 0, field
, 2, past_fields
,
278 bv
[dp
/2].surface
, 1, future_fields
,
279 &vc
->src_rect_vid
, output_surface
,
280 NULL
, output_rect
, 0, NULL
);
281 CHECK_ST_WARNING("Error when calling vdp_video_mixer_render");
285 static int video_to_output_surface(struct vo
*vo
)
287 struct vdpctx
*vc
= vo
->priv
;
289 return render_video_to_output_surface(vo
,
290 vc
->output_surfaces
[vc
->surface_num
],
294 static int next_deint_queue_pos(struct vo
*vo
, bool eof
)
296 struct vdpctx
*vc
= vo
->priv
;
298 int dqp
= vc
->deint_queue_pos
;
302 dqp
= vc
->deint
>= 2 ? dqp
- 1 : dqp
- 2 | 1;
303 if (dqp
< (eof
? 0 : 3))
308 static void set_next_frame_info(struct vo
*vo
, bool eof
)
310 struct vdpctx
*vc
= vo
->priv
;
312 vo
->frame_loaded
= false;
313 int dqp
= next_deint_queue_pos(vo
, eof
);
316 vo
->frame_loaded
= true;
319 struct buffered_video_surface
*bv
= vc
->buffered_video
;
321 if (idx
== 0) { // no future frame/pts available
322 vo
->next_pts
= bv
[0].pts
;
323 vo
->next_pts2
= MP_NOPTS_VALUE
;
324 } else if (!(vc
->deint
>= 2)) { // no field-splitting deinterlace
325 vo
->next_pts
= bv
[idx
].pts
;
326 vo
->next_pts2
= bv
[idx
- 1].pts
;
327 } else { // deinterlace with separate fields
328 double intermediate_pts
;
329 double diff
= bv
[idx
- 1].pts
- bv
[idx
].pts
;
330 if (diff
> 0 && diff
< 0.5)
331 intermediate_pts
= (bv
[idx
].pts
+ bv
[idx
- 1].pts
) / 2;
333 intermediate_pts
= bv
[idx
].pts
;
334 if (dqp
& 1) { // first field
335 vo
->next_pts
= bv
[idx
].pts
;
336 vo
->next_pts2
= intermediate_pts
;
338 vo
->next_pts
= intermediate_pts
;
339 vo
->next_pts2
= bv
[idx
- 1].pts
;
344 static void add_new_video_surface(struct vo
*vo
, VdpVideoSurface surface
,
345 struct mp_image
*reserved_mpi
, double pts
)
347 struct vdpctx
*vc
= vo
->priv
;
348 struct buffered_video_surface
*bv
= vc
->buffered_video
;
351 reserved_mpi
->usage_count
++;
352 if (bv
[NUM_BUFFERED_VIDEO
- 1].mpi
)
353 bv
[NUM_BUFFERED_VIDEO
- 1].mpi
->usage_count
--;
355 for (int i
= NUM_BUFFERED_VIDEO
- 1; i
> 0; i
--)
357 bv
[0] = (struct buffered_video_surface
){
363 vc
->deint_queue_pos
= FFMIN(vc
->deint_queue_pos
+ 2,
364 NUM_BUFFERED_VIDEO
* 2 - 3);
365 set_next_frame_info(vo
, false);
368 static void forget_frames(struct vo
*vo
)
370 struct vdpctx
*vc
= vo
->priv
;
372 vc
->deint_queue_pos
= -1001;
373 vc
->dropped_frame
= false;
374 for (int i
= 0; i
< NUM_BUFFERED_VIDEO
; i
++) {
375 struct buffered_video_surface
*p
= vc
->buffered_video
+ i
;
377 p
->mpi
->usage_count
--;
378 *p
= (struct buffered_video_surface
){
379 .surface
= VDP_INVALID_HANDLE
,
384 static void resize(struct vo
*vo
)
386 struct vdpctx
*vc
= vo
->priv
;
387 struct vdp_functions
*vdp
= vc
->vdp
;
390 struct vo_rect src_rect
;
391 struct vo_rect dst_rect
;
392 struct vo_rect borders
;
393 calc_src_dst_rects(vo
, vc
->vid_width
, vc
->vid_height
, &src_rect
, &dst_rect
,
395 vc
->out_rect_vid
.x0
= dst_rect
.left
;
396 vc
->out_rect_vid
.x1
= dst_rect
.right
;
397 vc
->out_rect_vid
.y0
= dst_rect
.top
;
398 vc
->out_rect_vid
.y1
= dst_rect
.bottom
;
399 vc
->src_rect_vid
.x0
= src_rect
.left
;
400 vc
->src_rect_vid
.x1
= src_rect
.right
;
401 vc
->src_rect_vid
.y0
= vc
->flip
? src_rect
.bottom
: src_rect
.top
;
402 vc
->src_rect_vid
.y1
= vc
->flip
? src_rect
.top
: src_rect
.bottom
;
403 vc
->border_x
= borders
.left
;
404 vc
->border_y
= borders
.top
;
405 #ifdef CONFIG_FREETYPE
406 // adjust font size to display size
409 vo_osd_changed(OSDTYPE_OSD
);
410 int flip_offset_ms
= vo_fs
? vc
->flip_offset_fs
: vc
->flip_offset_window
;
411 vo
->flip_queue_offset
= flip_offset_ms
/ 1000.;
413 int min_output_width
= FFMAX(vo
->dwidth
, vc
->vid_width
);
414 int min_output_height
= FFMAX(vo
->dheight
, vc
->vid_height
);
416 if (vc
->output_surface_width
< min_output_width
417 || vc
->output_surface_height
< min_output_height
) {
418 if (vc
->output_surface_width
< min_output_width
) {
419 vc
->output_surface_width
+= vc
->output_surface_width
>> 1;
420 vc
->output_surface_width
= FFMAX(vc
->output_surface_width
,
423 if (vc
->output_surface_height
< min_output_height
) {
424 vc
->output_surface_height
+= vc
->output_surface_height
>> 1;
425 vc
->output_surface_height
= FFMAX(vc
->output_surface_height
,
428 // Creation of output_surfaces
429 for (i
= 0; i
<= vc
->num_output_surfaces
; i
++) {
430 if (vc
->output_surfaces
[i
] != VDP_INVALID_HANDLE
) {
431 vdp_st
= vdp
->output_surface_destroy(vc
->output_surfaces
[i
]);
432 CHECK_ST_WARNING("Error when calling "
433 "vdp_output_surface_destroy");
435 vdp_st
= vdp
->output_surface_create(vc
->vdp_device
,
437 vc
->output_surface_width
,
438 vc
->output_surface_height
,
439 &vc
->output_surfaces
[i
]);
440 CHECK_ST_WARNING("Error when calling vdp_output_surface_create");
441 mp_msg(MSGT_VO
, MSGL_DBG2
, "vdpau out create: %u\n",
442 vc
->output_surfaces
[i
]);
445 vo
->want_redraw
= true;
448 static void preemption_callback(VdpDevice device
, void *context
)
450 struct vdpctx
*vc
= context
;
451 vc
->is_preempted
= true;
452 vc
->preemption_acked
= false;
455 /* Initialize vdp_get_proc_address, called from preinit() */
456 static int win_x11_init_vdpau_procs(struct vo
*vo
)
458 struct vo_x11_state
*x11
= vo
->x11
;
459 struct vdpctx
*vc
= vo
->priv
;
460 if (vc
->vdp
) // reinitialization after preemption
461 memset(vc
->vdp
, 0, sizeof(*vc
->vdp
));
463 vc
->vdp
= talloc_zero(vc
, struct vdp_functions
);
464 struct vdp_functions
*vdp
= vc
->vdp
;
467 struct vdp_function
{
472 const struct vdp_function
*dsc
;
474 static const struct vdp_function vdp_func
[] = {
475 #define VDP_FUNCTION(_, macro_name, mp_name) {macro_name, offsetof(struct vdp_functions, mp_name)},
476 #include "vdpau_template.c"
481 vdp_st
= vdp_device_create_x11(x11
->display
, x11
->screen
, &vc
->vdp_device
,
482 &vc
->vdp_get_proc_address
);
483 if (vdp_st
!= VDP_STATUS_OK
) {
484 if (vc
->is_preempted
)
485 mp_msg(MSGT_VO
, MSGL_DBG2
, "[vdpau] Error calling "
486 "vdp_device_create_x11 while preempted: %d\n", vdp_st
);
488 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling "
489 "vdp_device_create_x11: %d\n", vdp_st
);
493 vdp
->get_error_string
= NULL
;
494 for (dsc
= vdp_func
; dsc
->offset
>= 0; dsc
++) {
495 vdp_st
= vc
->vdp_get_proc_address(vc
->vdp_device
, dsc
->id
,
496 (void **)((char *)vdp
+ dsc
->offset
));
497 if (vdp_st
!= VDP_STATUS_OK
) {
498 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling "
499 "vdp_get_proc_address(function id %d): %s\n", dsc
->id
,
500 vdp
->get_error_string
? vdp
->get_error_string(vdp_st
) : "?");
504 vdp_st
= vdp
->preemption_callback_register(vc
->vdp_device
,
505 preemption_callback
, vc
);
509 static int win_x11_init_vdpau_flip_queue(struct vo
*vo
)
511 struct vdpctx
*vc
= vo
->priv
;
512 struct vdp_functions
*vdp
= vc
->vdp
;
513 struct vo_x11_state
*x11
= vo
->x11
;
516 if (vc
->flip_target
== VDP_INVALID_HANDLE
) {
517 vdp_st
= vdp
->presentation_queue_target_create_x11(vc
->vdp_device
,
520 CHECK_ST_ERROR("Error when calling "
521 "vdp_presentation_queue_target_create_x11");
524 /* Emperically this seems to be the first call which fails when we
525 * try to reinit after preemption while the user is still switched
526 * from X to a virtual terminal (creating the vdp_device initially
527 * succeeds, as does creating the flip_target above). This is
528 * probably not guaranteed behavior, but we'll assume it as a simple
529 * way to reduce warnings while trying to recover from preemption.
531 if (vc
->flip_queue
== VDP_INVALID_HANDLE
) {
532 vdp_st
= vdp
->presentation_queue_create(vc
->vdp_device
, vc
->flip_target
,
534 if (vc
->is_preempted
&& vdp_st
!= VDP_STATUS_OK
) {
535 mp_msg(MSGT_VO
, MSGL_DBG2
, "[vdpau] Failed to create flip queue "
536 "while preempted: %s\n", vdp
->get_error_string(vdp_st
));
539 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create");
543 vdp_st
= vdp
->presentation_queue_get_time(vc
->flip_queue
, &vdp_time
);
544 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time");
545 vc
->last_vdp_time
= vdp_time
;
546 vc
->last_sync_update
= GetTimer();
548 vc
->vsync_interval
= 1;
549 if (vc
->composite_detect
&& vo_x11_screen_is_composited(vo
)) {
550 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] Compositing window manager "
551 "detected. Assuming timing info is inaccurate.\n");
552 } else if (vc
->user_fps
> 0) {
553 vc
->vsync_interval
= 1e9
/ vc
->user_fps
;
554 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] Assuming user-specified display "
555 "refresh rate of %.3f Hz.\n", vc
->user_fps
);
556 } else if (vc
->user_fps
== 0) {
558 double fps
= vo_vm_get_fps(vo
);
560 mp_msg(MSGT_VO
, MSGL_WARN
, "[vdpau] Failed to get display FPS\n");
562 vc
->vsync_interval
= 1e9
/ fps
;
563 // This is verbose, but I'm not yet sure how common wrong values are
564 mp_msg(MSGT_VO
, MSGL_INFO
,
565 "[vdpau] Got display refresh rate %.3f Hz.\n"
566 "[vdpau] If that value looks wrong give the "
567 "-vo vdpau:fps=X suboption manually.\n", fps
);
570 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] This binary has been compiled "
571 "without XF86VidMode support.\n");
572 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] Can't use vsync-aware timing "
573 "without manually provided -vo vdpau:fps=X suboption.\n");
576 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] framedrop/timing logic disabled by "
582 static int set_video_attribute(struct vdpctx
*vc
, VdpVideoMixerAttribute attr
,
583 const void *value
, char *attr_name
)
585 struct vdp_functions
*vdp
= vc
->vdp
;
588 vdp_st
= vdp
->video_mixer_set_attribute_values(vc
->video_mixer
, 1, &attr
,
590 if (vdp_st
!= VDP_STATUS_OK
) {
591 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error setting video mixer "
592 "attribute %s: %s\n", attr_name
, vdp
->get_error_string(vdp_st
));
598 static void update_csc_matrix(struct vo
*vo
)
600 struct vdpctx
*vc
= vo
->priv
;
602 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Updating CSC matrix\n");
604 // VdpCSCMatrix happens to be compatible with mplayer's CSC matrix type
605 // both are float[3][4]
608 struct mp_csp_params cparams
= {
609 .colorspace
= vc
->colorspace
, .input_bits
= 8, .texture_bits
= 8 };
610 mp_csp_copy_equalizer_values(&cparams
, &vc
->video_eq
);
611 mp_get_yuv2rgb_coeffs(&cparams
, matrix
);
613 set_video_attribute(vc
, VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX
,
614 &matrix
, "CSC matrix");
617 #define SET_VIDEO_ATTR(attr_name, attr_type, value) set_video_attribute(vc, \
618 VDP_VIDEO_MIXER_ATTRIBUTE_ ## attr_name, &(attr_type){value},\
620 static int create_vdp_mixer(struct vo
*vo
, VdpChromaType vdp_chroma_type
)
622 struct vdpctx
*vc
= vo
->priv
;
623 struct vdp_functions
*vdp
= vc
->vdp
;
624 #define VDP_NUM_MIXER_PARAMETER 3
625 #define MAX_NUM_FEATURES 6
629 if (vc
->video_mixer
!= VDP_INVALID_HANDLE
)
632 int feature_count
= 0;
633 VdpVideoMixerFeature features
[MAX_NUM_FEATURES
];
634 VdpBool feature_enables
[MAX_NUM_FEATURES
];
635 static const VdpVideoMixerParameter parameters
[VDP_NUM_MIXER_PARAMETER
] = {
636 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
,
637 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
,
638 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
,
640 const void *const parameter_values
[VDP_NUM_MIXER_PARAMETER
] = {
645 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
;
646 if (vc
->deint_type
== 4)
647 features
[feature_count
++] =
648 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
;
650 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
;
652 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
;
654 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS
;
656 VdpVideoMixerFeature hqscaling_feature
=
657 VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
+ vc
->hqscaling
-1;
658 VdpBool hqscaling_available
;
659 vdp_st
= vdp
->video_mixer_query_feature_support(vc
->vdp_device
,
661 &hqscaling_available
);
662 CHECK_ST_ERROR("Error when calling video_mixer_query_feature_support");
663 if (hqscaling_available
)
664 features
[feature_count
++] = hqscaling_feature
;
666 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Your hardware or VDPAU "
667 "library does not support requested hqscaling.\n");
670 vdp_st
= vdp
->video_mixer_create(vc
->vdp_device
, feature_count
, features
,
671 VDP_NUM_MIXER_PARAMETER
,
672 parameters
, parameter_values
,
674 CHECK_ST_ERROR("Error when calling vdp_video_mixer_create");
676 for (i
= 0; i
< feature_count
; i
++)
677 feature_enables
[i
] = VDP_TRUE
;
679 feature_enables
[0] = VDP_FALSE
;
680 if (vc
->deint_type
== 4 && vc
->deint
< 4)
681 feature_enables
[1] = VDP_FALSE
;
683 vdp_st
= vdp
->video_mixer_set_feature_enables(vc
->video_mixer
,
684 feature_count
, features
,
686 CHECK_ST_WARNING("Error calling vdp_video_mixer_set_feature_enables");
689 SET_VIDEO_ATTR(NOISE_REDUCTION_LEVEL
, float, vc
->denoise
);
691 SET_VIDEO_ATTR(SHARPNESS_LEVEL
, float, vc
->sharpen
);
692 if (!vc
->chroma_deint
)
693 SET_VIDEO_ATTR(SKIP_CHROMA_DEINTERLACE
, uint8_t, 1);
695 update_csc_matrix(vo
);
699 // Free everything specific to a certain video file
700 static void free_video_specific(struct vo
*vo
)
702 struct vdpctx
*vc
= vo
->priv
;
703 struct vdp_functions
*vdp
= vc
->vdp
;
707 if (vc
->decoder
!= VDP_INVALID_HANDLE
)
708 vdp
->decoder_destroy(vc
->decoder
);
709 vc
->decoder
= VDP_INVALID_HANDLE
;
710 vc
->decoder_max_refs
= -1;
714 for (i
= 0; i
< MAX_VIDEO_SURFACES
; i
++) {
715 if (vc
->surface_render
[i
].surface
!= VDP_INVALID_HANDLE
) {
716 vdp_st
= vdp
->video_surface_destroy(vc
->surface_render
[i
].surface
);
717 CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy");
719 vc
->surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
722 if (vc
->video_mixer
!= VDP_INVALID_HANDLE
) {
723 vdp_st
= vdp
->video_mixer_destroy(vc
->video_mixer
);
724 CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy");
726 vc
->video_mixer
= VDP_INVALID_HANDLE
;
729 static int create_vdp_decoder(struct vo
*vo
, int max_refs
)
731 struct vdpctx
*vc
= vo
->priv
;
732 struct vdp_functions
*vdp
= vc
->vdp
;
734 VdpDecoderProfile vdp_decoder_profile
;
735 if (vc
->decoder
!= VDP_INVALID_HANDLE
)
736 vdp
->decoder_destroy(vc
->decoder
);
737 switch (vc
->image_format
) {
738 case IMGFMT_VDPAU_MPEG1
:
739 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG1
;
741 case IMGFMT_VDPAU_MPEG2
:
742 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG2_MAIN
;
744 case IMGFMT_VDPAU_H264
:
745 vdp_decoder_profile
= VDP_DECODER_PROFILE_H264_HIGH
;
746 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Creating H264 hardware decoder "
747 "for %d reference frames.\n", max_refs
);
749 case IMGFMT_VDPAU_WMV3
:
750 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_MAIN
;
752 case IMGFMT_VDPAU_VC1
:
753 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_ADVANCED
;
755 case IMGFMT_VDPAU_MPEG4
:
756 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG4_PART2_ASP
;
759 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Unknown image format!\n");
762 vdp_st
= vdp
->decoder_create(vc
->vdp_device
, vdp_decoder_profile
,
763 vc
->vid_width
, vc
->vid_height
, max_refs
,
765 CHECK_ST_WARNING("Failed creating VDPAU decoder");
766 if (vdp_st
!= VDP_STATUS_OK
) {
768 vc
->decoder
= VDP_INVALID_HANDLE
;
769 vc
->decoder_max_refs
= 0;
772 vc
->decoder_max_refs
= max_refs
;
776 static int initialize_vdpau_objects(struct vo
*vo
)
778 struct vdpctx
*vc
= vo
->priv
;
779 struct vdp_functions
*vdp
= vc
->vdp
;
782 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_420
;
783 switch (vc
->image_format
) {
787 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_YV12
;
790 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_NV12
;
793 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_YUYV
;
794 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_422
;
797 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_UYVY
;
798 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_422
;
800 if (win_x11_init_vdpau_flip_queue(vo
) < 0)
803 if (create_vdp_mixer(vo
, vc
->vdp_chroma_type
) < 0)
807 bitmap_surface_query_capabilities(vc
->vdp_device
,
810 &vc
->eosd_surface
.max_width
,
811 &vc
->eosd_surface
.max_height
);
812 CHECK_ST_WARNING("Query to get max EOSD surface size failed");
818 static void mark_vdpau_objects_uninitialized(struct vo
*vo
)
820 struct vdpctx
*vc
= vo
->priv
;
822 vc
->decoder
= VDP_INVALID_HANDLE
;
823 for (int i
= 0; i
< MAX_VIDEO_SURFACES
; i
++)
824 vc
->surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
826 vc
->video_mixer
= VDP_INVALID_HANDLE
;
827 vc
->flip_queue
= VDP_INVALID_HANDLE
;
828 vc
->flip_target
= VDP_INVALID_HANDLE
;
829 for (int i
= 0; i
<= MAX_OUTPUT_SURFACES
; i
++)
830 vc
->output_surfaces
[i
] = VDP_INVALID_HANDLE
;
831 vc
->vdp_device
= VDP_INVALID_HANDLE
;
832 vc
->eosd_surface
= (struct eosd_bitmap_surface
){
833 .surface
= VDP_INVALID_HANDLE
,
835 vc
->output_surface_width
= vc
->output_surface_height
= -1;
836 vc
->eosd_render_count
= 0;
839 static int handle_preemption(struct vo
*vo
)
841 struct vdpctx
*vc
= vo
->priv
;
843 if (!vc
->is_preempted
)
845 if (!vc
->preemption_acked
)
846 mark_vdpau_objects_uninitialized(vo
);
847 vc
->preemption_acked
= true;
848 if (!vc
->preemption_user_notified
) {
849 mp_tmsg(MSGT_VO
, MSGL_ERR
, "[vdpau] Got display preemption notice! "
850 "Will attempt to recover.\n");
851 vc
->preemption_user_notified
= true;
853 /* Trying to initialize seems to be quite slow, so only try once a
854 * second to avoid using 100% CPU. */
855 if (vc
->last_preemption_retry_fail
856 && GetTimerMS() - vc
->last_preemption_retry_fail
< 1000)
858 if (win_x11_init_vdpau_procs(vo
) < 0 || initialize_vdpau_objects(vo
) < 0) {
859 vc
->last_preemption_retry_fail
= GetTimerMS() | 1;
862 vc
->last_preemption_retry_fail
= 0;
863 vc
->is_preempted
= false;
864 vc
->preemption_user_notified
= false;
865 mp_tmsg(MSGT_VO
, MSGL_INFO
, "[vdpau] Recovered from display preemption.\n");
870 * connect to X server, create and map window, initialize all
871 * VDPAU objects, create different surfaces etc.
873 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
874 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
877 struct vdpctx
*vc
= vo
->priv
;
878 struct vo_x11_state
*x11
= vo
->x11
;
880 XSetWindowAttributes xswa
;
881 XWindowAttributes attribs
;
882 unsigned long xswamask
;
886 int vm
= flags
& VOFLAG_MODESWITCHING
;
889 if (handle_preemption(vo
) < 0)
892 vc
->flip
= flags
& VOFLAG_FLIPPING
;
893 vc
->image_format
= format
;
894 vc
->vid_width
= width
;
895 vc
->vid_height
= height
;
896 vc
->vid_d_width
= d_width
;
897 vc
->vid_d_height
= d_height
;
899 free_video_specific(vo
);
900 if (IMGFMT_IS_VDPAU(vc
->image_format
) && !create_vdp_decoder(vo
, 2))
906 vc
->mode_switched
= true;
909 XGetWindowAttributes(x11
->display
, DefaultRootWindow(x11
->display
),
911 depth
= attribs
.depth
;
912 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
914 XMatchVisualInfo(x11
->display
, x11
->screen
, depth
, TrueColor
, &vinfo
);
916 xswa
.background_pixel
= 0;
917 xswa
.border_pixel
= 0;
918 /* Do not use CWBackPixel: It leads to VDPAU errors after
919 * aspect ratio changes. */
920 xswamask
= CWBorderPixel
;
922 vo_x11_create_vo_window(vo
, &vinfo
, vo
->dx
, vo
->dy
, d_width
, d_height
,
923 flags
, CopyFromParent
, "vdpau");
924 XChangeWindowAttributes(x11
->display
, x11
->window
, xswamask
, &xswa
);
928 /* Grab the mouse pointer in our window */
930 XGrabPointer(x11
->display
, x11
->window
, True
, 0,
931 GrabModeAsync
, GrabModeAsync
,
932 x11
->window
, None
, CurrentTime
);
933 XSetInputFocus(x11
->display
, x11
->window
, RevertToNone
, CurrentTime
);
937 if ((flags
& VOFLAG_FULLSCREEN
) && WinID
<= 0)
940 if (initialize_vdpau_objects(vo
) < 0)
946 static void check_events(struct vo
*vo
)
948 if (handle_preemption(vo
) < 0)
951 int e
= vo_x11_check_events(vo
);
953 if (e
& VO_EVENT_RESIZE
)
955 else if (e
& VO_EVENT_EXPOSE
) {
956 vo
->want_redraw
= true;
960 static void draw_osd_I8A8(void *ctx
, int x0
, int y0
, int w
, int h
,
961 unsigned char *src
, unsigned char *srca
, int stride
)
964 struct vdpctx
*vc
= vo
->priv
;
965 struct vdp_functions
*vdp
= vc
->vdp
;
966 VdpOutputSurface output_surface
= vc
->output_surfaces
[vc
->surface_num
];
970 int index_data_size_required
;
971 VdpRect output_indexed_rect_vid
;
976 index_data_size_required
= 2*w
*h
;
977 if (vc
->index_data_size
< index_data_size_required
) {
978 vc
->index_data
= talloc_realloc_size(vc
, vc
->index_data
,
979 index_data_size_required
);
980 vc
->index_data_size
= index_data_size_required
;
983 // index_data creation, component order - I, A, I, A, .....
984 for (i
= 0; i
< h
; i
++)
985 for (int j
= 0; j
< w
; j
++) {
986 vc
->index_data
[i
*2*w
+ j
*2] = src
[i
*stride
+j
];
987 vc
->index_data
[i
*2*w
+ j
*2 + 1] = -srca
[i
*stride
+j
];
990 output_indexed_rect_vid
.x0
= x0
;
991 output_indexed_rect_vid
.y0
= y0
;
992 output_indexed_rect_vid
.x1
= x0
+ w
;
993 output_indexed_rect_vid
.y1
= y0
+ h
;
997 // write source_data to osd_surface.
998 VdpOutputSurface osd_surface
= vc
->output_surfaces
[vc
->num_output_surfaces
];
1000 output_surface_put_bits_indexed(osd_surface
, VDP_INDEXED_FORMAT_I8A8
,
1001 (const void *const*)&vc
->index_data
,
1002 &pitch
, &output_indexed_rect_vid
,
1003 VDP_COLOR_TABLE_FORMAT_B8G8R8X8
,
1004 (void *)vc
->palette
);
1005 CHECK_ST_WARNING("Error when calling vdp_output_surface_put_bits_indexed");
1007 VdpOutputSurfaceRenderBlendState blend_state
= {
1008 .struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
,
1009 .blend_factor_source_color
=
1010 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
1011 .blend_factor_source_alpha
=
1012 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
1013 .blend_factor_destination_color
=
1014 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
1015 .blend_factor_destination_alpha
=
1016 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
1017 .blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1018 .blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1022 output_surface_render_output_surface(output_surface
,
1023 &output_indexed_rect_vid
,
1025 &output_indexed_rect_vid
,
1027 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
1028 CHECK_ST_WARNING("Error when calling "
1029 "vdp_output_surface_render_output_surface");
1032 static void draw_eosd(struct vo
*vo
)
1034 struct vdpctx
*vc
= vo
->priv
;
1035 struct vdp_functions
*vdp
= vc
->vdp
;
1037 VdpOutputSurface output_surface
= vc
->output_surfaces
[vc
->surface_num
];
1040 VdpOutputSurfaceRenderBlendState blend_state
= {
1041 .struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
,
1042 .blend_factor_source_color
=
1043 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
1044 .blend_factor_source_alpha
=
1045 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
1046 .blend_factor_destination_color
=
1047 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
1048 .blend_factor_destination_alpha
=
1049 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
1050 .blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1051 .blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1054 for (i
= 0; i
< vc
->eosd_render_count
; i
++) {
1056 output_surface_render_bitmap_surface(output_surface
,
1057 &vc
->eosd_targets
[i
].dest
,
1058 vc
->eosd_surface
.surface
,
1059 &vc
->eosd_targets
[i
].source
,
1060 &vc
->eosd_targets
[i
].color
,
1062 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
1063 CHECK_ST_WARNING("EOSD: Error when rendering");
1067 #define HEIGHT_SORT_BITS 4
1068 static int size_index(struct eosd_target
*r
)
1070 unsigned int h
= r
->source
.y1
;
1071 int n
= av_log2_16bit(h
);
1072 return (n
<< HEIGHT_SORT_BITS
)
1073 + (- 1 - (h
<< HEIGHT_SORT_BITS
>> n
) & (1 << HEIGHT_SORT_BITS
) - 1);
1076 /* Pack the given rectangles into an area of size w * h.
1077 * The size of each rectangle is read from .source.x1/.source.y1.
1078 * The height of each rectangle must be at least 1 and less than 65536.
1079 * The .source rectangle is then set corresponding to the packed position.
1080 * 'scratch' must point to work memory for num_rects+16 ints.
1081 * Return 0 on success, -1 if the rectangles did not fit in w*h.
1083 * The rectangles are placed in rows in order approximately sorted by
1084 * height (the approximate sorting is simpler than a full one would be,
1085 * and allows the algorithm to work in linear time). Additionally, to
1086 * reduce wasted space when there are a few tall rectangles, empty
1087 * lower-right parts of rows are filled recursively when the size of
1088 * rectangles in the row drops past a power-of-two threshold. So if a
1089 * row starts with rectangles of size 3x50, 10x40 and 5x20 then the
1090 * free rectangle with corners (13, 20)-(w, 50) is filled recursively.
1092 static int pack_rectangles(struct eosd_target
*rects
, int num_rects
,
1093 int w
, int h
, int *scratch
)
1095 int bins
[16 << HEIGHT_SORT_BITS
];
1096 int sizes
[16 << HEIGHT_SORT_BITS
] = {};
1097 for (int i
= 0; i
< num_rects
; i
++)
1098 sizes
[size_index(rects
+ i
)]++;
1100 for (int i
= 0; i
< 16 << HEIGHT_SORT_BITS
; i
+= 1 << HEIGHT_SORT_BITS
) {
1101 for (int j
= 0; j
< 1 << HEIGHT_SORT_BITS
; j
++) {
1103 idx
+= sizes
[i
+ j
];
1105 scratch
[idx
++] = -1;
1107 for (int i
= 0; i
< num_rects
; i
++)
1108 scratch
[bins
[size_index(rects
+ i
)]++] = i
;
1109 for (int i
= 0; i
< 16; i
++)
1110 bins
[i
] = bins
[i
<< HEIGHT_SORT_BITS
] - sizes
[i
<< HEIGHT_SORT_BITS
];
1112 int size
, x
, bottom
;
1113 } stack
[16] = {{15, 0, h
}}, s
= {};
1118 s
= stack
[--stackpos
];
1123 while ((obj
= scratch
[bins
[s
.size
]]) >= 0) {
1124 int bottom
= y
+ rects
[obj
].source
.y1
;
1125 if (bottom
> s
.bottom
)
1127 int right
= s
.x
+ rects
[obj
].source
.x1
;
1131 rects
[obj
].source
.x0
= s
.x
;
1132 rects
[obj
].source
.x1
+= s
.x
;
1133 rects
[obj
].source
.y0
= y
;
1134 rects
[obj
].source
.y1
+= y
;
1137 stack
[stackpos
++] = s
;
1139 maxy
= FFMAX(maxy
, bottom
);
1145 return num_rects
? -1 : 0;
1148 static void generate_eosd(struct vo
*vo
, mp_eosd_images_t
*imgs
)
1150 struct vdpctx
*vc
= vo
->priv
;
1151 struct vdp_functions
*vdp
= vc
->vdp
;
1154 ASS_Image
*img
= imgs
->imgs
;
1156 struct eosd_bitmap_surface
*sfc
= &vc
->eosd_surface
;
1157 bool need_upload
= false;
1159 if (imgs
->changed
== 0)
1160 return; // Nothing changed, no need to redraw
1162 vc
->eosd_render_count
= 0;
1165 return; // There's nothing to render!
1167 if (imgs
->changed
== 1)
1168 goto eosd_skip_upload
;
1171 bool reallocate
= false;
1173 for (p
= img
, i
= 0; p
; p
= p
->next
) {
1174 if (p
->w
<= 0 || p
->h
<= 0)
1176 // Allocate new space for surface/target arrays
1177 if (i
>= vc
->eosd_targets_size
) {
1178 vc
->eosd_targets_size
= FFMAX(vc
->eosd_targets_size
* 2, 512);
1180 talloc_realloc_size(vc
, vc
->eosd_targets
,
1181 vc
->eosd_targets_size
1182 * sizeof(*vc
->eosd_targets
));
1184 talloc_realloc_size(vc
, vc
->eosd_scratch
,
1185 (vc
->eosd_targets_size
+ 16)
1186 * sizeof(*vc
->eosd_scratch
));
1188 vc
->eosd_targets
[i
].source
.x1
= p
->w
;
1189 vc
->eosd_targets
[i
].source
.y1
= p
->h
;
1192 if (pack_rectangles(vc
->eosd_targets
, i
, sfc
->w
, sfc
->h
,
1193 vc
->eosd_scratch
) >= 0)
1195 int w
= FFMIN(FFMAX(sfc
->w
* 2, EOSD_SURFACE_INITIAL_SIZE
),
1197 int h
= FFMIN(FFMAX(sfc
->h
* 2, EOSD_SURFACE_INITIAL_SIZE
),
1199 if (w
== sfc
->w
&& h
== sfc
->h
) {
1200 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] EOSD bitmaps do not fit on "
1201 "a surface with the maximum supported size\n");
1210 if (sfc
->surface
!= VDP_INVALID_HANDLE
) {
1211 vdp_st
= vdp
->bitmap_surface_destroy(sfc
->surface
);
1212 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
1214 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Allocating a %dx%d surface for "
1215 "EOSD bitmaps.\n", sfc
->w
, sfc
->h
);
1216 vdp_st
= vdp
->bitmap_surface_create(vc
->vdp_device
, VDP_RGBA_FORMAT_A8
,
1217 sfc
->w
, sfc
->h
, true,
1219 if (vdp_st
!= VDP_STATUS_OK
)
1220 sfc
->surface
= VDP_INVALID_HANDLE
;
1221 CHECK_ST_WARNING("EOSD: error when creating surface");
1225 if (sfc
->surface
== VDP_INVALID_HANDLE
)
1227 for (p
= img
; p
; p
= p
->next
) {
1228 if (p
->w
<= 0 || p
->h
<= 0)
1230 struct eosd_target
*target
= &vc
->eosd_targets
[vc
->eosd_render_count
];
1233 bitmap_surface_put_bits_native(sfc
->surface
,
1234 (const void *) &p
->bitmap
,
1235 &p
->stride
, &target
->source
);
1236 CHECK_ST_WARNING("EOSD: putbits failed");
1238 // Render dest, color, etc.
1239 target
->color
.alpha
= 1.0 - ((p
->color
>> 0) & 0xff) / 255.0;
1240 target
->color
.blue
= ((p
->color
>> 8) & 0xff) / 255.0;
1241 target
->color
.green
= ((p
->color
>> 16) & 0xff) / 255.0;
1242 target
->color
.red
= ((p
->color
>> 24) & 0xff) / 255.0;
1243 target
->dest
.x0
= p
->dst_x
;
1244 target
->dest
.y0
= p
->dst_y
;
1245 target
->dest
.x1
= p
->w
+ p
->dst_x
;
1246 target
->dest
.y1
= p
->h
+ p
->dst_y
;
1247 vc
->eosd_render_count
++;
1251 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
1253 struct vdpctx
*vc
= vo
->priv
;
1255 if (handle_preemption(vo
) < 0)
1258 osd_draw_text_ext(osd
, vo
->dwidth
, vo
->dheight
, vc
->border_x
, vc
->border_y
,
1259 vc
->border_x
, vc
->border_y
, vc
->vid_width
,
1260 vc
->vid_height
, draw_osd_I8A8
, vo
);
1263 static int update_presentation_queue_status(struct vo
*vo
)
1265 struct vdpctx
*vc
= vo
->priv
;
1266 struct vdp_functions
*vdp
= vc
->vdp
;
1269 while (vc
->query_surface_num
!= vc
->surface_num
) {
1271 VdpPresentationQueueStatus status
;
1272 VdpOutputSurface surface
= vc
->output_surfaces
[vc
->query_surface_num
];
1273 vdp_st
= vdp
->presentation_queue_query_surface_status(vc
->flip_queue
,
1276 CHECK_ST_WARNING("Error calling "
1277 "presentation_queue_query_surface_status");
1278 if (status
== VDP_PRESENTATION_QUEUE_STATUS_QUEUED
)
1280 if (vc
->vsync_interval
> 1) {
1281 uint64_t qtime
= vc
->queue_time
[vc
->query_surface_num
];
1282 if (vtime
< qtime
+ vc
->vsync_interval
/ 2)
1283 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Frame shown too early\n");
1284 if (vtime
> qtime
+ vc
->vsync_interval
)
1285 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Frame shown late\n");
1287 vc
->query_surface_num
= WRAP_ADD(vc
->query_surface_num
, 1,
1288 vc
->num_output_surfaces
);
1289 vc
->recent_vsync_time
= vtime
;
1291 int num_queued
= WRAP_ADD(vc
->surface_num
, -vc
->query_surface_num
,
1292 vc
->num_output_surfaces
);
1293 mp_msg(MSGT_VO
, MSGL_DBG3
, "[vdpau] Queued surface count (before add): "
1294 "%d\n", num_queued
);
1298 static inline uint64_t prev_vs2(struct vdpctx
*vc
, uint64_t ts
, int shift
)
1300 uint64_t offset
= ts
- vc
->recent_vsync_time
;
1301 // Fix negative values for 1<<shift vsyncs before vc->recent_vsync_time
1302 offset
+= (uint64_t)vc
->vsync_interval
<< shift
;
1303 offset
%= vc
->vsync_interval
;
1307 static void flip_page_timed(struct vo
*vo
, unsigned int pts_us
, int duration
)
1309 struct vdpctx
*vc
= vo
->priv
;
1310 struct vdp_functions
*vdp
= vc
->vdp
;
1312 uint32_t vsync_interval
= vc
->vsync_interval
;
1314 if (handle_preemption(vo
) < 0)
1317 if (duration
> INT_MAX
/ 1000)
1322 if (vc
->vsync_interval
== 1)
1323 duration
= -1; // Make sure drop logic is disabled
1325 uint64_t now
= sync_vdptime(vo
);
1326 uint64_t pts
= pts_us
? convert_to_vdptime(vo
, pts_us
) : now
;
1327 uint64_t ideal_pts
= pts
;
1328 uint64_t npts
= duration
>= 0 ? pts
+ duration
: UINT64_MAX
;
1330 #define PREV_VS2(ts, shift) prev_vs2(vc, ts, shift)
1331 // Only gives accurate results for ts >= vc->recent_vsync_time
1332 #define PREV_VSYNC(ts) PREV_VS2(ts, 0)
1334 /* We hope to be here at least one vsync before the frame should be shown.
1335 * If we are running late then don't drop the frame unless there is
1336 * already one queued for the next vsync; even if we _hope_ to show the
1337 * next frame soon enough to mean this one should be dropped we might
1338 * not make the target time in reality. Without this check we could drop
1339 * every frame, freezing the display completely if video lags behind.
1341 if (now
> PREV_VSYNC(FFMAX(pts
, vc
->last_queue_time
+ vsync_interval
)))
1344 /* Allow flipping a frame at a vsync if its presentation time is a
1345 * bit after that vsync and the change makes the flip time delta
1346 * from previous frame better match the target timestamp delta.
1347 * This avoids instability with frame timestamps falling near vsyncs.
1348 * For example if the frame timestamps were (with vsyncs at
1349 * integer values) 0.01, 1.99, 4.01, 5.99, 8.01, ... then
1350 * straightforward timing at next vsync would flip the frames at
1351 * 1, 2, 5, 6, 9; this changes it to 1, 2, 4, 6, 8 and so on with
1352 * regular 2-vsync intervals.
1354 * Also allow moving the frame forward if it looks like we dropped
1355 * the previous frame incorrectly (now that we know better after
1356 * having final exact timestamp information for this frame) and
1357 * there would unnecessarily be a vsync without a frame change.
1359 uint64_t vsync
= PREV_VSYNC(pts
);
1360 if (pts
< vsync
+ vsync_interval
/ 4
1361 && (vsync
- PREV_VS2(vc
->last_queue_time
, 16)
1362 > pts
- vc
->last_ideal_time
+ vsync_interval
/ 2
1363 || vc
->dropped_frame
&& vsync
> vc
->dropped_time
))
1364 pts
-= vsync_interval
/ 2;
1366 vc
->dropped_frame
= true; // changed at end if false
1367 vc
->dropped_time
= ideal_pts
;
1369 pts
= FFMAX(pts
, vc
->last_queue_time
+ vsync_interval
);
1370 pts
= FFMAX(pts
, now
);
1371 if (npts
< PREV_VSYNC(pts
) + vsync_interval
)
1374 int num_flips
= update_presentation_queue_status(vo
);
1375 vsync
= vc
->recent_vsync_time
+ num_flips
* vc
->vsync_interval
;
1376 now
= sync_vdptime(vo
);
1377 pts
= FFMAX(pts
, now
);
1378 pts
= FFMAX(pts
, vsync
+ (vsync_interval
>> 2));
1379 vsync
= PREV_VSYNC(pts
);
1380 if (npts
< vsync
+ vsync_interval
)
1382 pts
= vsync
+ (vsync_interval
>> 2);
1384 vdp
->presentation_queue_display(vc
->flip_queue
,
1385 vc
->output_surfaces
[vc
->surface_num
],
1386 vo
->dwidth
, vo
->dheight
, pts
);
1387 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display");
1389 vc
->last_queue_time
= pts
;
1390 vc
->queue_time
[vc
->surface_num
] = pts
;
1391 vc
->last_ideal_time
= ideal_pts
;
1392 vc
->dropped_frame
= false;
1393 vc
->surface_num
= WRAP_ADD(vc
->surface_num
, 1, vc
->num_output_surfaces
);
1396 static int draw_slice(struct vo
*vo
, uint8_t *image
[], int stride
[], int w
,
1397 int h
, int x
, int y
)
1399 struct vdpctx
*vc
= vo
->priv
;
1400 struct vdp_functions
*vdp
= vc
->vdp
;
1403 if (handle_preemption(vo
) < 0)
1406 struct vdpau_render_state
*rndr
= (struct vdpau_render_state
*)image
[0];
1407 int max_refs
= vc
->image_format
== IMGFMT_VDPAU_H264
?
1408 rndr
->info
.h264
.num_ref_frames
: 2;
1409 if (!IMGFMT_IS_VDPAU(vc
->image_format
))
1411 if ((vc
->decoder
== VDP_INVALID_HANDLE
|| vc
->decoder_max_refs
< max_refs
)
1412 && !create_vdp_decoder(vo
, max_refs
))
1415 vdp_st
= vdp
->decoder_render(vc
->decoder
, rndr
->surface
,
1416 (void *)&rndr
->info
,
1417 rndr
->bitstream_buffers_used
,
1418 rndr
->bitstream_buffers
);
1419 CHECK_ST_WARNING("Failed VDPAU decoder rendering");
1424 static struct vdpau_render_state
*get_surface(struct vo
*vo
, int number
)
1426 struct vdpctx
*vc
= vo
->priv
;
1427 struct vdp_functions
*vdp
= vc
->vdp
;
1429 if (number
> MAX_VIDEO_SURFACES
)
1431 if (vc
->surface_render
[number
].surface
== VDP_INVALID_HANDLE
1432 && !vc
->is_preempted
) {
1434 vdp_st
= vdp
->video_surface_create(vc
->vdp_device
, vc
->vdp_chroma_type
,
1435 vc
->vid_width
, vc
->vid_height
,
1436 &vc
->surface_render
[number
].surface
);
1437 CHECK_ST_WARNING("Error when calling vdp_video_surface_create");
1439 mp_msg(MSGT_VO
, MSGL_DBG3
, "vdpau vid create: %u\n",
1440 vc
->surface_render
[number
].surface
);
1441 return &vc
->surface_render
[number
];
1444 static void draw_image(struct vo
*vo
, mp_image_t
*mpi
, double pts
)
1446 struct vdpctx
*vc
= vo
->priv
;
1447 struct vdp_functions
*vdp
= vc
->vdp
;
1448 struct mp_image
*reserved_mpi
= NULL
;
1449 struct vdpau_render_state
*rndr
;
1451 if (IMGFMT_IS_VDPAU(vc
->image_format
)) {
1454 } else if (!(mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)) {
1455 rndr
= get_surface(vo
, vc
->deint_counter
);
1456 vc
->deint_counter
= WRAP_ADD(vc
->deint_counter
, 1, NUM_BUFFERED_VIDEO
);
1457 if (handle_preemption(vo
) >= 0) {
1459 const void *destdata
[3] = {mpi
->planes
[0], mpi
->planes
[2],
1461 if (vc
->image_format
== IMGFMT_NV12
)
1462 destdata
[1] = destdata
[2];
1463 vdp_st
= vdp
->video_surface_put_bits_y_cb_cr(rndr
->surface
,
1464 vc
->vdp_pixel_format
, destdata
, mpi
->stride
);
1465 CHECK_ST_WARNING("Error when calling "
1466 "vdp_video_surface_put_bits_y_cb_cr");
1469 // We don't support slice callbacks so this shouldn't occur -
1470 // I think the flags test above in pointless, but I'm adding
1471 // this instead of removing it just in case.
1473 if (mpi
->fields
& MP_IMGFIELD_ORDERED
)
1474 vc
->top_field_first
= !!(mpi
->fields
& MP_IMGFIELD_TOP_FIRST
);
1476 vc
->top_field_first
= 1;
1478 add_new_video_surface(vo
, rndr
->surface
, reserved_mpi
, pts
);
1483 // warning: the size and pixel format of surface must match that of the
1484 // surfaces in vc->output_surfaces
1485 static struct mp_image
*read_output_surface(struct vdpctx
*vc
,
1486 VdpOutputSurface surface
)
1489 struct vdp_functions
*vdp
= vc
->vdp
;
1490 struct mp_image
*image
= alloc_mpi(vc
->output_surface_width
,
1491 vc
->output_surface_height
, IMGFMT_BGR32
);
1493 void *dst_planes
[] = { image
->planes
[0] };
1494 uint32_t dst_pitches
[] = { image
->stride
[0] };
1495 vdp_st
= vdp
->output_surface_get_bits_native(surface
, NULL
, dst_planes
,
1497 CHECK_ST_WARNING("Error when calling vdp_output_surface_get_bits_native");
1502 static struct mp_image
*get_screenshot(struct vo
*vo
)
1504 struct vdpctx
*vc
= vo
->priv
;
1506 VdpOutputSurface screenshot_surface
=
1507 vc
->output_surfaces
[vc
->num_output_surfaces
];
1509 VdpRect rc
= { .x1
= vc
->vid_width
, .y1
= vc
->vid_height
};
1510 render_video_to_output_surface(vo
, screenshot_surface
, &rc
);
1512 struct mp_image
*image
= read_output_surface(vc
, screenshot_surface
);
1514 image
->width
= vc
->vid_width
;
1515 image
->height
= vc
->vid_height
;
1516 image
->w
= vc
->vid_d_width
;
1517 image
->h
= vc
->vid_d_height
;
1522 static struct mp_image
*get_window_screenshot(struct vo
*vo
)
1524 struct vdpctx
*vc
= vo
->priv
;
1525 int last_surface
= WRAP_ADD(vc
->surface_num
, -1, vc
->num_output_surfaces
);
1526 VdpOutputSurface screen
= vc
->output_surfaces
[last_surface
];
1527 struct mp_image
*image
= read_output_surface(vo
->priv
, screen
);
1528 image
->width
= image
->w
= vo
->dwidth
;
1529 image
->height
= image
->h
= vo
->dheight
;
1533 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
1535 struct vdpctx
*vc
= vo
->priv
;
1536 struct vdpau_render_state
*rndr
;
1538 // no dr for non-decoding for now
1539 if (!IMGFMT_IS_VDPAU(vc
->image_format
))
1541 if (mpi
->type
!= MP_IMGTYPE_NUMBERED
)
1544 rndr
= get_surface(vo
, mpi
->number
);
1546 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] no surfaces available in "
1548 // TODO: this probably breaks things forever, provide a dummy buffer?
1551 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1552 mpi
->stride
[0] = mpi
->stride
[1] = mpi
->stride
[2] = 0;
1553 mpi
->planes
[0] = mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
1554 // hack to get around a check and to avoid a special-case in vd_ffmpeg.c
1555 mpi
->planes
[0] = (void *)rndr
;
1556 mpi
->num_planes
= 1;
1561 static int query_format(uint32_t format
)
1563 int default_flags
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
1564 | VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_OSD
| VFCAP_EOSD
1565 | VFCAP_EOSD_UNSCALED
| VFCAP_FLIP
;
1573 return default_flags
| VOCAP_NOSLICES
;
1574 case IMGFMT_VDPAU_MPEG1
:
1575 case IMGFMT_VDPAU_MPEG2
:
1576 case IMGFMT_VDPAU_H264
:
1577 case IMGFMT_VDPAU_WMV3
:
1578 case IMGFMT_VDPAU_VC1
:
1579 case IMGFMT_VDPAU_MPEG4
:
1580 return default_flags
;
1585 static void destroy_vdpau_objects(struct vo
*vo
)
1587 struct vdpctx
*vc
= vo
->priv
;
1588 struct vdp_functions
*vdp
= vc
->vdp
;
1593 free_video_specific(vo
);
1595 if (vc
->flip_queue
!= VDP_INVALID_HANDLE
) {
1596 vdp_st
= vdp
->presentation_queue_destroy(vc
->flip_queue
);
1597 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy");
1600 if (vc
->flip_target
!= VDP_INVALID_HANDLE
) {
1601 vdp_st
= vdp
->presentation_queue_target_destroy(vc
->flip_target
);
1602 CHECK_ST_WARNING("Error when calling "
1603 "vdp_presentation_queue_target_destroy");
1606 for (i
= 0; i
<= vc
->num_output_surfaces
; i
++) {
1607 if (vc
->output_surfaces
[i
] == VDP_INVALID_HANDLE
)
1609 vdp_st
= vdp
->output_surface_destroy(vc
->output_surfaces
[i
]);
1610 CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
1613 if (vc
->eosd_surface
.surface
!= VDP_INVALID_HANDLE
) {
1614 vdp_st
= vdp
->bitmap_surface_destroy(vc
->eosd_surface
.surface
);
1615 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
1618 vdp_st
= vdp
->device_destroy(vc
->vdp_device
);
1619 CHECK_ST_WARNING("Error when calling vdp_device_destroy");
1622 static void uninit(struct vo
*vo
)
1624 struct vdpctx
*vc
= vo
->priv
;
1626 /* Destroy all vdpau objects */
1627 destroy_vdpau_objects(vo
);
1629 #ifdef CONFIG_XF86VM
1630 if (vc
->mode_switched
)
1635 // Free bitstream buffers allocated by FFmpeg
1636 for (int i
= 0; i
< MAX_VIDEO_SURFACES
; i
++)
1637 av_freep(&vc
->surface_render
[i
].bitstream_buffers
);
1640 static int preinit(struct vo
*vo
, const char *arg
)
1642 struct vdpctx
*vc
= vo
->priv
;
1644 // Mark everything as invalid first so uninit() can tell what has been
1646 mark_vdpau_objects_uninitialized(vo
);
1648 vc
->colorspace
= (struct mp_csp_details
) MP_CSP_DETAILS_DEFAULTS
;
1649 vc
->video_eq
.capabilities
= MP_CSP_EQ_CAPS_COLORMATRIX
;
1651 vc
->deint_type
= vc
->deint
? FFABS(vc
->deint
) : 3;
1658 // After this calling uninit() should work to free resources
1660 if (win_x11_init_vdpau_procs(vo
) < 0) {
1661 if (vc
->vdp
->device_destroy
)
1662 vc
->vdp
->device_destroy(vc
->vdp_device
);
1667 // full grayscale palette.
1668 for (int i
= 0; i
< PALETTE_SIZE
; ++i
)
1669 vc
->palette
[i
] = (i
<< 16) | (i
<< 8) | i
;
1674 static int get_equalizer(struct vo
*vo
, const char *name
, int *value
)
1676 struct vdpctx
*vc
= vo
->priv
;
1677 return mp_csp_equalizer_get(&vc
->video_eq
, name
, value
) >= 0 ?
1678 VO_TRUE
: VO_NOTIMPL
;
1681 static bool status_ok(struct vo
*vo
)
1683 if (!vo
->config_ok
|| handle_preemption(vo
) < 0)
1688 static int set_equalizer(struct vo
*vo
, const char *name
, int value
)
1690 struct vdpctx
*vc
= vo
->priv
;
1692 if (mp_csp_equalizer_set(&vc
->video_eq
, name
, value
) < 0)
1696 update_csc_matrix(vo
);
1700 static void checked_resize(struct vo
*vo
)
1707 static int control(struct vo
*vo
, uint32_t request
, void *data
)
1709 struct vdpctx
*vc
= vo
->priv
;
1710 struct vdp_functions
*vdp
= vc
->vdp
;
1712 handle_preemption(vo
);
1715 case VOCTRL_GET_DEINTERLACE
:
1716 *(int *)data
= vc
->deint
;
1718 case VOCTRL_SET_DEINTERLACE
:
1719 vc
->deint
= *(int *)data
;
1721 vc
->deint
= vc
->deint_type
;
1722 if (vc
->deint_type
> 2 && status_ok(vo
)) {
1724 VdpVideoMixerFeature features
[1] =
1725 {vc
->deint_type
== 3 ?
1726 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
1727 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
};
1728 VdpBool feature_enables
[1] = {vc
->deint
? VDP_TRUE
: VDP_FALSE
};
1729 vdp_st
= vdp
->video_mixer_set_feature_enables(vc
->video_mixer
,
1732 CHECK_ST_WARNING("Error changing deinterlacing settings");
1734 vo
->want_redraw
= true;
1737 if (vc
->dropped_frame
)
1738 vo
->want_redraw
= true;
1740 case VOCTRL_QUERY_FORMAT
:
1741 return query_format(*(uint32_t *)data
);
1742 case VOCTRL_GET_IMAGE
:
1743 return get_image(vo
, data
);
1744 case VOCTRL_DRAW_IMAGE
:
1745 abort(); // draw_image() should get called directly
1750 case VOCTRL_FULLSCREEN
:
1751 vo_x11_fullscreen(vo
);
1754 case VOCTRL_GET_PANSCAN
:
1756 case VOCTRL_SET_PANSCAN
:
1759 case VOCTRL_SET_EQUALIZER
: {
1760 vo
->want_redraw
= true;
1761 struct voctrl_set_equalizer_args
*args
= data
;
1762 return set_equalizer(vo
, args
->name
, args
->value
);
1764 case VOCTRL_GET_EQUALIZER
: {
1765 struct voctrl_get_equalizer_args
*args
= data
;
1766 return get_equalizer(vo
, args
->name
, args
->valueptr
);
1768 case VOCTRL_SET_YUV_COLORSPACE
:
1769 vc
->colorspace
= *(struct mp_csp_details
*)data
;
1771 update_csc_matrix(vo
);
1772 vo
->want_redraw
= true;
1774 case VOCTRL_GET_YUV_COLORSPACE
:
1775 *(struct mp_csp_details
*)data
= vc
->colorspace
;
1780 case VOCTRL_UPDATE_SCREENINFO
:
1781 update_xinerama_info(vo
);
1783 case VOCTRL_DRAW_EOSD
:
1786 if (status_ok(vo
)) {
1787 generate_eosd(vo
, data
);
1791 case VOCTRL_GET_EOSD_RES
: {
1792 struct mp_eosd_res
*r
= data
;
1795 r
->ml
= r
->mr
= vc
->border_x
;
1796 r
->mt
= r
->mb
= vc
->border_y
;
1799 case VOCTRL_NEWFRAME
:
1800 vc
->deint_queue_pos
= next_deint_queue_pos(vo
, true);
1802 video_to_output_surface(vo
);
1804 case VOCTRL_SKIPFRAME
:
1805 vc
->deint_queue_pos
= next_deint_queue_pos(vo
, true);
1807 case VOCTRL_REDRAW_FRAME
:
1809 video_to_output_surface(vo
);
1814 case VOCTRL_SCREENSHOT
: {
1817 struct voctrl_screenshot_args
*args
= data
;
1818 if (args
->full_window
)
1819 args
->out_image
= get_window_screenshot(vo
);
1821 args
->out_image
= get_screenshot(vo
);
1828 #undef OPT_BASE_STRUCT
1829 #define OPT_BASE_STRUCT struct vdpctx
1831 const struct vo_driver video_out_vdpau
= {
1833 .buffer_frames
= true,
1834 .info
= &(const struct vo_info_s
){
1837 "Rajib Mahapatra <rmahapatra@nvidia.com> and others",
1843 .draw_image
= draw_image
,
1844 .get_buffered_frame
= set_next_frame_info
,
1845 .draw_slice
= draw_slice
,
1846 .draw_osd
= draw_osd
,
1847 .flip_page_timed
= flip_page_timed
,
1848 .check_events
= check_events
,
1850 .privsize
= sizeof(struct vdpctx
),
1851 .options
= (const struct m_option
[]){
1852 OPT_INTRANGE("deint", deint
, 0, -4, 4),
1853 OPT_FLAG_ON("chroma-deint", chroma_deint
, 0, OPTDEF_INT(1)),
1854 OPT_FLAG_OFF("nochroma-deint", chroma_deint
, 0),
1855 OPT_MAKE_FLAGS("pullup", pullup
, 0),
1856 OPT_FLOATRANGE("denoise", denoise
, 0, 0, 1),
1857 OPT_FLOATRANGE("sharpen", sharpen
, 0, -1, 1),
1858 OPT_ERRORMESSAGE("colorspace", "vo_vdpau suboption \"colorspace\" has "
1859 "been removed. Use --colormatrix instead.\n"),
1860 OPT_ERRORMESSAGE("studio", "vo_vdpau suboption \"studio\" has been "
1861 "removed. Use --colormatrix-output-range=limited "
1863 OPT_INTRANGE("hqscaling", hqscaling
, 0, 0, 9),
1864 OPT_FLOAT("fps", user_fps
, 0),
1865 OPT_FLAG_ON("composite-detect", composite_detect
, 0, OPTDEF_INT(1)),
1866 OPT_INT("queuetime_windowed", flip_offset_window
, 0, OPTDEF_INT(50)),
1867 OPT_INT("queuetime_fs", flip_offset_fs
, 0, OPTDEF_INT(50)),
1868 OPT_INTRANGE("output_surfaces", num_output_surfaces
, 0,
1869 2, MAX_OUTPUT_SURFACES
, OPTDEF_INT(3)),