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"
45 #include "subopt-helper.h"
46 #include "libmpcodecs/vfcap.h"
47 #include "libmpcodecs/mp_image.h"
48 #include "osdep/timer.h"
50 #include "libavcodec/vdpau.h"
52 #include "font_load.h"
54 #include "libavutil/common.h"
55 #include "libavutil/mathematics.h"
59 #define CHECK_ST_ERROR(message) \
61 if (vdp_st != VDP_STATUS_OK) { \
62 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \
63 message, vdp->get_error_string(vdp_st)); \
68 #define CHECK_ST_WARNING(message) \
70 if (vdp_st != VDP_STATUS_OK) \
71 mp_msg(MSGT_VO, MSGL_WARN, "[ vdpau] %s: %s\n", \
72 message, vdp->get_error_string(vdp_st)); \
75 /* number of video and output surfaces */
76 #define NUM_OUTPUT_SURFACES 3
77 #define MAX_VIDEO_SURFACES 50
78 #define NUM_BUFFERED_VIDEO 4
80 /* number of palette entries */
81 #define PALETTE_SIZE 256
83 /* Initial size of EOSD surface in pixels (x*x) */
84 #define EOSD_SURFACE_INITIAL_SIZE 256
87 * Global variable declaration - VDPAU specific
90 struct vdp_functions
{
91 #define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name;
92 #include "vdpau_template.c"
97 struct vdp_functions
*vdp
;
101 bool preemption_acked
;
102 bool preemption_user_notified
;
103 unsigned int last_preemption_retry_fail
;
104 VdpGetProcAddress
*vdp_get_proc_address
;
106 VdpPresentationQueueTarget flip_target
;
107 VdpPresentationQueue flip_queue
;
108 uint64_t last_vdp_time
;
109 unsigned int last_sync_update
;
111 /* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */
112 #define osd_surface vc->output_surfaces[NUM_OUTPUT_SURFACES]
113 VdpOutputSurface output_surfaces
[NUM_OUTPUT_SURFACES
+ 1];
114 struct buffered_video_surface
{
115 VdpVideoSurface surface
;
118 } buffered_video
[NUM_BUFFERED_VIDEO
];
120 int output_surface_width
, output_surface_height
;
122 VdpVideoMixer video_mixer
;
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 VdpTime recent_vsync_time
;
149 unsigned int vsync_interval
;
150 uint64_t last_queue_time
;
151 uint64_t last_ideal_time
;
153 uint64_t dropped_time
;
154 uint32_t vid_width
, vid_height
;
155 uint32_t image_format
;
156 VdpChromaType vdp_chroma_type
;
157 VdpYCbCrFormat vdp_pixel_format
;
160 unsigned char *index_data
;
162 uint32_t palette
[PALETTE_SIZE
];
166 struct eosd_bitmap_surface
{
167 VdpBitmapSurface surface
;
174 // List of surfaces to be rendered
180 int eosd_targets_size
;
183 int eosd_render_count
;
188 int num_shown_frames
;
191 // These tell what's been initialized and uninit() should free/uninitialize
195 static int change_vdptime_sync(struct vdpctx
*vc
, unsigned int *t
)
197 struct vdp_functions
*vdp
= vc
->vdp
;
200 vdp_st
= vdp
->presentation_queue_get_time(vc
->flip_queue
, &vdp_time
);
201 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time");
202 unsigned int t1
= *t
;
203 unsigned int t2
= GetTimer();
204 uint64_t old
= vc
->last_vdp_time
+ (t1
- vc
->last_sync_update
) * 1000ULL;
206 if (vdp_time
> old
+ (t2
- t1
) * 1000ULL)
207 vdp_time
-= (t2
- t1
) * 1000ULL;
210 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] adjusting VdpTime offset by %f µs\n",
211 (int64_t)(vdp_time
- old
) / 1000.);
212 vc
->last_vdp_time
= vdp_time
;
213 vc
->last_sync_update
= t1
;
218 static uint64_t sync_vdptime(struct vo
*vo
)
220 struct vdpctx
*vc
= vo
->priv
;
222 unsigned int t
= GetTimer();
223 if (t
- vc
->last_sync_update
> 5000000)
224 change_vdptime_sync(vc
, &t
);
225 uint64_t now
= (t
- vc
->last_sync_update
) * 1000ULL + vc
->last_vdp_time
;
226 // Make sure nanosecond inaccuracies don't make things inconsistent
227 now
= FFMAX(now
, vc
->recent_vsync_time
);
231 static uint64_t convert_to_vdptime(struct vo
*vo
, unsigned int t
)
233 struct vdpctx
*vc
= vo
->priv
;
234 return (int)(t
- vc
->last_sync_update
) * 1000LL + vc
->last_vdp_time
;
237 static void flip_page_timed(struct vo
*vo
, unsigned int pts_us
, int duration
);
239 static int video_to_output_surface(struct vo
*vo
)
241 struct vdpctx
*vc
= vo
->priv
;
242 struct vdp_functions
*vdp
= vc
->vdp
;
245 if (vc
->deint_queue_pos
< 0)
248 struct buffered_video_surface
*bv
= vc
->buffered_video
;
249 int field
= VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME
;
250 unsigned int dp
= vc
->deint_queue_pos
;
251 // dp==0 means last field of latest frame, 1 earlier field of latest frame,
252 // 2 last field of previous frame and so on
254 field
= vc
->top_field_first
^ (dp
& 1) ?
255 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD
:
256 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD
;
258 const VdpVideoSurface
*past_fields
= (const VdpVideoSurface
[]){
259 bv
[(dp
+1)/2].surface
, bv
[(dp
+2)/2].surface
};
260 const VdpVideoSurface
*future_fields
= (const VdpVideoSurface
[]){
261 dp
>= 1 ? bv
[(dp
-1)/2].surface
: VDP_INVALID_HANDLE
};
262 VdpOutputSurface output_surface
= vc
->output_surfaces
[vc
->surface_num
];
263 vdp_st
= vdp
->presentation_queue_block_until_surface_idle(vc
->flip_queue
,
266 CHECK_ST_WARNING("Error when calling "
267 "vdp_presentation_queue_block_until_surface_idle");
269 vdp_st
= vdp
->video_mixer_render(vc
->video_mixer
, VDP_INVALID_HANDLE
,
270 0, field
, 2, past_fields
,
271 bv
[dp
/2].surface
, 1, future_fields
,
272 &vc
->src_rect_vid
, output_surface
,
273 NULL
, &vc
->out_rect_vid
, 0, NULL
);
274 CHECK_ST_WARNING("Error when calling vdp_video_mixer_render");
278 static void get_buffered_frame(struct vo
*vo
, bool eof
)
280 struct vdpctx
*vc
= vo
->priv
;
282 int dqp
= vc
->deint_queue_pos
;
286 dqp
= vc
->deint
>= 2 ? dqp
- 1 : dqp
- 2 | 1;
287 if (dqp
< (eof
? 0 : 3))
291 vc
->deint_queue_pos
= dqp
;
292 vo
->frame_loaded
= true;
295 struct buffered_video_surface
*bv
= vc
->buffered_video
;
296 int idx
= vc
->deint_queue_pos
>> 1;
297 if (idx
== 0) { // no future frame/pts available
298 vo
->next_pts
= bv
[0].pts
;
299 vo
->next_pts2
= MP_NOPTS_VALUE
;
300 } else if (!(vc
->deint
>= 2)) { // no field-splitting deinterlace
301 vo
->next_pts
= bv
[idx
].pts
;
302 vo
->next_pts2
= bv
[idx
- 1].pts
;
303 } else { // deinterlace with separate fields
304 double intermediate_pts
;
305 double diff
= bv
[idx
- 1].pts
- bv
[idx
].pts
;
306 if (diff
> 0 && diff
< 0.5)
307 intermediate_pts
= (bv
[idx
].pts
+ bv
[idx
- 1].pts
) / 2;
309 intermediate_pts
= bv
[idx
].pts
;
310 if (vc
->deint_queue_pos
& 1) { // first field
311 vo
->next_pts
= bv
[idx
].pts
;
312 vo
->next_pts2
= intermediate_pts
;
314 vo
->next_pts
= intermediate_pts
;
315 vo
->next_pts2
= bv
[idx
- 1].pts
;
319 video_to_output_surface(vo
);
322 static void add_new_video_surface(struct vo
*vo
, VdpVideoSurface surface
,
323 struct mp_image
*reserved_mpi
, double pts
)
325 struct vdpctx
*vc
= vo
->priv
;
326 struct buffered_video_surface
*bv
= vc
->buffered_video
;
329 reserved_mpi
->usage_count
++;
330 if (bv
[NUM_BUFFERED_VIDEO
- 1].mpi
)
331 bv
[NUM_BUFFERED_VIDEO
- 1].mpi
->usage_count
--;
333 for (int i
= NUM_BUFFERED_VIDEO
- 1; i
> 0; i
--)
335 bv
[0] = (struct buffered_video_surface
){
341 vc
->deint_queue_pos
+= 2;
342 get_buffered_frame(vo
, false);
345 static void forget_frames(struct vo
*vo
)
347 struct vdpctx
*vc
= vo
->priv
;
349 vc
->deint_queue_pos
= -1001;
350 vc
->dropped_frame
= false;
351 for (int i
= 0; i
< NUM_BUFFERED_VIDEO
; i
++) {
352 struct buffered_video_surface
*p
= vc
->buffered_video
+ i
;
354 p
->mpi
->usage_count
--;
355 *p
= (struct buffered_video_surface
){
356 .surface
= VDP_INVALID_HANDLE
,
361 static void resize(struct vo
*vo
)
363 struct vdpctx
*vc
= vo
->priv
;
364 struct vdp_functions
*vdp
= vc
->vdp
;
367 struct vo_rect src_rect
;
368 struct vo_rect dst_rect
;
369 struct vo_rect borders
;
370 calc_src_dst_rects(vo
, vc
->vid_width
, vc
->vid_height
, &src_rect
, &dst_rect
,
372 vc
->out_rect_vid
.x0
= dst_rect
.left
;
373 vc
->out_rect_vid
.x1
= dst_rect
.right
;
374 vc
->out_rect_vid
.y0
= dst_rect
.top
;
375 vc
->out_rect_vid
.y1
= dst_rect
.bottom
;
376 vc
->src_rect_vid
.x0
= src_rect
.left
;
377 vc
->src_rect_vid
.x1
= src_rect
.right
;
378 vc
->src_rect_vid
.y0
= vc
->flip
? src_rect
.bottom
: src_rect
.top
;
379 vc
->src_rect_vid
.y1
= vc
->flip
? src_rect
.top
: src_rect
.bottom
;
380 vc
->border_x
= borders
.left
;
381 vc
->border_y
= borders
.top
;
382 #ifdef CONFIG_FREETYPE
383 // adjust font size to display size
386 vo_osd_changed(OSDTYPE_OSD
);
387 int flip_offset_ms
= vo_fs
? vc
->flip_offset_fs
: vc
->flip_offset_window
;
388 vo
->flip_queue_offset
= flip_offset_ms
/ 1000.;
390 bool had_frames
= vc
->num_shown_frames
;
391 if (vc
->output_surface_width
< vo
->dwidth
392 || vc
->output_surface_height
< vo
->dheight
) {
393 if (vc
->output_surface_width
< vo
->dwidth
) {
394 vc
->output_surface_width
+= vc
->output_surface_width
>> 1;
395 vc
->output_surface_width
= FFMAX(vc
->output_surface_width
,
398 if (vc
->output_surface_height
< vo
->dheight
) {
399 vc
->output_surface_height
+= vc
->output_surface_height
>> 1;
400 vc
->output_surface_height
= FFMAX(vc
->output_surface_height
,
403 // Creation of output_surfaces
404 for (i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++) {
405 if (vc
->output_surfaces
[i
] != VDP_INVALID_HANDLE
)
406 vdp
->output_surface_destroy(vc
->output_surfaces
[i
]);
407 vdp_st
= vdp
->output_surface_create(vc
->vdp_device
,
408 VDP_RGBA_FORMAT_B8G8R8A8
,
409 vc
->output_surface_width
,
410 vc
->output_surface_height
,
411 &vc
->output_surfaces
[i
]);
412 CHECK_ST_WARNING("Error when calling vdp_output_surface_create");
413 mp_msg(MSGT_VO
, MSGL_DBG2
, "OUT CREATE: %u\n",
414 vc
->output_surfaces
[i
]);
416 vc
->num_shown_frames
= 0;
418 if (vc
->paused
&& had_frames
)
419 if (video_to_output_surface(vo
) >= 0)
420 flip_page_timed(vo
, 0, -1);
423 static void preemption_callback(VdpDevice device
, void *context
)
425 struct vdpctx
*vc
= context
;
426 vc
->is_preempted
= true;
427 vc
->preemption_acked
= false;
430 /* Initialize vdp_get_proc_address, called from preinit() */
431 static int win_x11_init_vdpau_procs(struct vo
*vo
)
433 struct vo_x11_state
*x11
= vo
->x11
;
434 struct vdpctx
*vc
= vo
->priv
;
435 talloc_free(vc
->vdp
); // In case this is reinitialization after preemption
436 struct vdp_functions
*vdp
= talloc_zero(vc
, struct vdp_functions
);
440 struct vdp_function
{
445 const struct vdp_function
*dsc
;
447 static const struct vdp_function vdp_func
[] = {
448 #define VDP_FUNCTION(_, macro_name, mp_name) {macro_name, offsetof(struct vdp_functions, mp_name)},
449 #include "vdpau_template.c"
454 vdp_st
= vdp_device_create_x11(x11
->display
, x11
->screen
,&vc
->vdp_device
,
455 &vc
->vdp_get_proc_address
);
456 if (vdp_st
!= VDP_STATUS_OK
) {
457 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling "
458 "vdp_device_create_x11: %i\n", vdp_st
);
462 vdp
->get_error_string
= NULL
;
463 for (dsc
= vdp_func
; dsc
->offset
>= 0; dsc
++) {
464 vdp_st
= vc
->vdp_get_proc_address(vc
->vdp_device
, dsc
->id
,
465 (void **)((char *)vdp
+ dsc
->offset
));
466 if (vdp_st
!= VDP_STATUS_OK
) {
467 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error when calling "
468 "vdp_get_proc_address(function id %d): %s\n", dsc
->id
,
469 vdp
->get_error_string
? vdp
->get_error_string(vdp_st
) : "?");
473 vdp_st
= vdp
->preemption_callback_register(vc
->vdp_device
,
474 preemption_callback
, vc
);
478 static int win_x11_init_vdpau_flip_queue(struct vo
*vo
)
480 struct vdpctx
*vc
= vo
->priv
;
481 struct vdp_functions
*vdp
= vc
->vdp
;
482 struct vo_x11_state
*x11
= vo
->x11
;
485 if (vc
->flip_target
== VDP_INVALID_HANDLE
) {
486 vdp_st
= vdp
->presentation_queue_target_create_x11(vc
->vdp_device
,
489 CHECK_ST_ERROR("Error when calling "
490 "vdp_presentation_queue_target_create_x11");
493 /* Emperically this seems to be the first call which fails when we
494 * try to reinit after preemption while the user is still switched
495 * from X to a virtual terminal (creating the vdp_device initially
496 * succeeds, as does creating the flip_target above). This is
497 * probably not guaranteed behavior, but we'll assume it as a simple
498 * way to reduce warnings while trying to recover from preemption.
500 if (vc
->flip_queue
== VDP_INVALID_HANDLE
) {
501 vdp_st
= vdp
->presentation_queue_create(vc
->vdp_device
, vc
->flip_target
,
503 if (vc
->is_preempted
&& vdp_st
!= VDP_STATUS_OK
) {
504 mp_msg(MSGT_VO
, MSGL_DBG2
, "[vdpau] Failed to create flip queue "
505 "while preempted: %s\n", vdp
->get_error_string(vdp_st
));
508 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create");
512 vdp_st
= vdp
->presentation_queue_get_time(vc
->flip_queue
, &vdp_time
);
513 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_get_time");
514 vc
->last_vdp_time
= vdp_time
;
515 vc
->last_sync_update
= GetTimer();
517 vc
->vsync_interval
= 1;
518 if (vc
->user_fps
> 0) {
519 vc
->vsync_interval
= 1e9
/ vc
->user_fps
;
520 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] Assuming user-specified display "
521 "refresh rate of %.3f Hz.\n", vc
->user_fps
);
522 } else if (vc
->user_fps
== 0) {
524 double fps
= vo_vm_get_fps(vo
);
526 mp_msg(MSGT_VO
, MSGL_WARN
, "[vdpau] Failed to get display FPS\n");
528 vc
->vsync_interval
= 1e9
/ fps
;
529 // This is verbose, but I'm not yet sure how common wrong values are
530 mp_msg(MSGT_VO
, MSGL_INFO
,
531 "[vdpau] Got display refresh rate %.3f Hz.\n"
532 "[vdpau] If that value looks wrong give the "
533 "-vo vdpau:fps=X suboption manually.\n", fps
);
536 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] This binary has been compiled "
537 "without XF86VidMode support.\n");
538 mp_msg(MSGT_VO
, MSGL_INFO
, "[vdpau] Can't use vsync-aware timing "
539 "without manually provided -vo vdpau:fps=X suboption.\n");
542 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] framedrop/timing logic disabled by "
548 static int set_video_attribute(struct vdpctx
*vc
, VdpVideoMixerAttribute attr
,
549 const void *value
, char *attr_name
)
551 struct vdp_functions
*vdp
= vc
->vdp
;
554 vdp_st
= vdp
->video_mixer_set_attribute_values(vc
->video_mixer
, 1, &attr
,
556 if (vdp_st
!= VDP_STATUS_OK
) {
557 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Error setting video mixer "
558 "attribute %s: %s\n", attr_name
, vdp
->get_error_string(vdp_st
));
564 static void update_csc_matrix(struct vo
*vo
)
566 struct vdpctx
*vc
= vo
->priv
;
567 struct vdp_functions
*vdp
= vc
->vdp
;
570 const VdpColorStandard vdp_colors
[] = {VDP_COLOR_STANDARD_ITUR_BT_601
,
571 VDP_COLOR_STANDARD_ITUR_BT_709
,
572 VDP_COLOR_STANDARD_SMPTE_240M
};
573 char * const vdp_names
[] = {"BT.601", "BT.709", "SMPTE-240M"};
574 int csp
= vc
->colorspace
;
575 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Updating CSC matrix for %s\n",
579 vdp_st
= vdp
->generate_csc_matrix(&vc
->procamp
, vdp_colors
[csp
], &matrix
);
580 CHECK_ST_WARNING("Error when generating CSC matrix");
582 set_video_attribute(vc
, VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX
,
583 &matrix
, "CSC matrix");
586 #define SET_VIDEO_ATTR(attr_name, attr_type, value) set_video_attribute(vc, \
587 VDP_VIDEO_MIXER_ATTRIBUTE_ ## attr_name, &(attr_type){value},\
589 static int create_vdp_mixer(struct vo
*vo
, VdpChromaType vdp_chroma_type
)
591 struct vdpctx
*vc
= vo
->priv
;
592 struct vdp_functions
*vdp
= vc
->vdp
;
593 #define VDP_NUM_MIXER_PARAMETER 3
594 #define MAX_NUM_FEATURES 6
598 if (vc
->video_mixer
!= VDP_INVALID_HANDLE
)
601 int feature_count
= 0;
602 VdpVideoMixerFeature features
[MAX_NUM_FEATURES
];
603 VdpBool feature_enables
[MAX_NUM_FEATURES
];
604 static const VdpVideoMixerParameter parameters
[VDP_NUM_MIXER_PARAMETER
] = {
605 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH
,
606 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT
,
607 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
,
609 const void *const parameter_values
[VDP_NUM_MIXER_PARAMETER
] = {
614 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
;
616 features
[feature_count
++] =
617 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
;
619 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE
;
621 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION
;
623 features
[feature_count
++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS
;
625 #ifndef VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
626 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] MPlayer was compiled with (old?) "
627 "libvdpau headers with no support for requested hqscaling.\n");
629 VdpVideoMixerFeature hqscaling_feature
=
630 VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1
+ vc
->hqscaling
-1;
631 VdpBool hqscaling_available
;
632 vdp_st
= vdp
->video_mixer_query_feature_support(vc
->vdp_device
,
634 &hqscaling_available
);
635 CHECK_ST_ERROR("Error when calling video_mixer_query_feature_support");
636 if (hqscaling_available
)
637 features
[feature_count
++] = hqscaling_feature
;
639 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] Your hardware or VDPAU "
640 "library does not support requested hqscaling.\n");
644 vdp_st
= vdp
->video_mixer_create(vc
->vdp_device
, feature_count
, features
,
645 VDP_NUM_MIXER_PARAMETER
,
646 parameters
, parameter_values
,
648 CHECK_ST_ERROR("Error when calling vdp_video_mixer_create");
650 for (i
= 0; i
< feature_count
; i
++)
651 feature_enables
[i
] = VDP_TRUE
;
653 feature_enables
[0] = VDP_FALSE
;
655 vdp_st
= vdp
->video_mixer_set_feature_enables(vc
->video_mixer
,
656 feature_count
, features
,
658 CHECK_ST_WARNING("Error calling vdp_video_mixer_set_feature_enables");
661 SET_VIDEO_ATTR(NOISE_REDUCTION_LEVEL
, float, vc
->denoise
);
663 SET_VIDEO_ATTR(SHARPNESS_LEVEL
, float, vc
->sharpen
);
664 if (!vc
->chroma_deint
)
665 SET_VIDEO_ATTR(SKIP_CHROMA_DEINTERLACE
, uint8_t, 1);
667 update_csc_matrix(vo
);
671 // Free everything specific to a certain video file
672 static void free_video_specific(struct vo
*vo
)
674 struct vdpctx
*vc
= vo
->priv
;
675 struct vdp_functions
*vdp
= vc
->vdp
;
679 if (vc
->decoder
!= VDP_INVALID_HANDLE
)
680 vdp
->decoder_destroy(vc
->decoder
);
681 vc
->decoder
= VDP_INVALID_HANDLE
;
682 vc
->decoder_max_refs
= -1;
686 for (i
= 0; i
< MAX_VIDEO_SURFACES
; i
++) {
687 if (vc
->surface_render
[i
].surface
!= VDP_INVALID_HANDLE
) {
688 vdp_st
= vdp
->video_surface_destroy(vc
->surface_render
[i
].surface
);
689 CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy");
691 vc
->surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
694 if (vc
->video_mixer
!= VDP_INVALID_HANDLE
) {
695 vdp_st
= vdp
->video_mixer_destroy(vc
->video_mixer
);
696 CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy");
698 vc
->video_mixer
= VDP_INVALID_HANDLE
;
701 static int create_vdp_decoder(struct vo
*vo
, int max_refs
)
703 struct vdpctx
*vc
= vo
->priv
;
704 struct vdp_functions
*vdp
= vc
->vdp
;
706 VdpDecoderProfile vdp_decoder_profile
;
707 if (vc
->decoder
!= VDP_INVALID_HANDLE
)
708 vdp
->decoder_destroy(vc
->decoder
);
709 switch (vc
->image_format
) {
710 case IMGFMT_VDPAU_MPEG1
:
711 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG1
;
713 case IMGFMT_VDPAU_MPEG2
:
714 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG2_MAIN
;
716 case IMGFMT_VDPAU_H264
:
717 vdp_decoder_profile
= VDP_DECODER_PROFILE_H264_HIGH
;
718 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Creating H264 hardware decoder "
719 "for %d reference frames.\n", max_refs
);
721 case IMGFMT_VDPAU_WMV3
:
722 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_MAIN
;
724 case IMGFMT_VDPAU_VC1
:
725 vdp_decoder_profile
= VDP_DECODER_PROFILE_VC1_ADVANCED
;
727 #ifdef VDP_DECODER_PROFILE_MPEG4_PART2_ASP
728 case IMGFMT_VDPAU_MPEG4
:
729 vdp_decoder_profile
= VDP_DECODER_PROFILE_MPEG4_PART2_ASP
;
733 vdp_st
= vdp
->decoder_create(vc
->vdp_device
, vdp_decoder_profile
,
734 vc
->vid_width
, vc
->vid_height
, max_refs
,
736 CHECK_ST_WARNING("Failed creating VDPAU decoder");
737 if (vdp_st
!= VDP_STATUS_OK
) {
738 vc
->decoder
= VDP_INVALID_HANDLE
;
739 vc
->decoder_max_refs
= 0;
742 vc
->decoder_max_refs
= max_refs
;
746 static int initialize_vdpau_objects(struct vo
*vo
)
748 struct vdpctx
*vc
= vo
->priv
;
749 struct vdp_functions
*vdp
= vc
->vdp
;
752 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_420
;
753 switch (vc
->image_format
) {
757 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_YV12
;
760 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_NV12
;
763 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_YUYV
;
764 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_422
;
767 vc
->vdp_pixel_format
= VDP_YCBCR_FORMAT_UYVY
;
768 vc
->vdp_chroma_type
= VDP_CHROMA_TYPE_422
;
770 if (win_x11_init_vdpau_flip_queue(vo
) < 0)
773 if (create_vdp_mixer(vo
, vc
->vdp_chroma_type
) < 0)
777 bitmap_surface_query_capabilities(vc
->vdp_device
,
780 &vc
->eosd_surface
.max_width
,
781 &vc
->eosd_surface
.max_height
);
782 CHECK_ST_WARNING("Query to get max EOSD surface size failed");
788 static void mark_vdpau_objects_uninitialized(struct vo
*vo
)
790 struct vdpctx
*vc
= vo
->priv
;
792 vc
->decoder
= VDP_INVALID_HANDLE
;
793 for (int i
= 0; i
< MAX_VIDEO_SURFACES
; i
++)
794 vc
->surface_render
[i
].surface
= VDP_INVALID_HANDLE
;
796 vc
->video_mixer
= VDP_INVALID_HANDLE
;
797 vc
->flip_queue
= VDP_INVALID_HANDLE
;
798 vc
->flip_target
= VDP_INVALID_HANDLE
;
799 for (int i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++)
800 vc
->output_surfaces
[i
] = VDP_INVALID_HANDLE
;
801 vc
->vdp_device
= VDP_INVALID_HANDLE
;
802 vc
->eosd_surface
= (struct eosd_bitmap_surface
){
803 .surface
= VDP_INVALID_HANDLE
,
805 vc
->output_surface_width
= vc
->output_surface_height
= -1;
806 vc
->eosd_render_count
= 0;
807 vc
->num_shown_frames
= 0;
810 static int handle_preemption(struct vo
*vo
)
812 struct vdpctx
*vc
= vo
->priv
;
814 if (!vc
->is_preempted
)
816 if (!vc
->preemption_acked
)
817 mark_vdpau_objects_uninitialized(vo
);
818 vc
->preemption_acked
= true;
819 if (!vc
->preemption_user_notified
) {
820 mp_tmsg(MSGT_VO
, MSGL_ERR
, "[vdpau] Got display preemption notice! "
821 "Will attempt to recover.\n");
822 vc
->preemption_user_notified
= true;
824 /* Trying to initialize seems to be quite slow, so only try once a
825 * second to avoid using 100% CPU. */
826 if (vc
->last_preemption_retry_fail
827 && GetTimerMS() - vc
->last_preemption_retry_fail
< 1000)
829 if (win_x11_init_vdpau_procs(vo
) < 0 || initialize_vdpau_objects(vo
) < 0) {
830 vc
->last_preemption_retry_fail
= GetTimerMS() | 1;
833 vc
->last_preemption_retry_fail
= 0;
834 vc
->is_preempted
= false;
835 vc
->preemption_user_notified
= false;
836 mp_tmsg(MSGT_VO
, MSGL_INFO
, "[vdpau] Recovered from display preemption.\n");
841 * connect to X server, create and map window, initialize all
842 * VDPAU objects, create different surfaces etc.
844 static int config(struct vo
*vo
, uint32_t width
, uint32_t height
,
845 uint32_t d_width
, uint32_t d_height
, uint32_t flags
,
846 char *title
, uint32_t format
)
848 struct vdpctx
*vc
= vo
->priv
;
849 struct vo_x11_state
*x11
= vo
->x11
;
851 XSetWindowAttributes xswa
;
852 XWindowAttributes attribs
;
853 unsigned long xswamask
;
857 int vm
= flags
& VOFLAG_MODESWITCHING
;
860 if (handle_preemption(vo
) < 0)
863 vc
->flip
= flags
& VOFLAG_FLIPPING
;
864 vc
->image_format
= format
;
865 vc
->vid_width
= width
;
866 vc
->vid_height
= height
;
867 if (vc
->user_colorspace
== 0)
868 vc
->colorspace
= width
>= 1280 || height
> 576 ? 1 : 0;
870 vc
->colorspace
= vc
->user_colorspace
- 1;
871 free_video_specific(vo
);
872 if (IMGFMT_IS_VDPAU(vc
->image_format
) && !create_vdp_decoder(vo
, 2))
878 vc
->mode_switched
= true;
881 XGetWindowAttributes(x11
->display
, DefaultRootWindow(x11
->display
),
883 depth
= attribs
.depth
;
884 if (depth
!= 15 && depth
!= 16 && depth
!= 24 && depth
!= 32)
886 XMatchVisualInfo(x11
->display
, x11
->screen
, depth
, TrueColor
, &vinfo
);
888 xswa
.background_pixel
= 0;
889 xswa
.border_pixel
= 0;
890 /* Do not use CWBackPixel: It leads to VDPAU errors after
891 * aspect ratio changes. */
892 xswamask
= CWBorderPixel
;
894 vo_x11_create_vo_window(vo
, &vinfo
, vo
->dx
, vo
->dy
, d_width
, d_height
,
895 flags
, CopyFromParent
, "vdpau", title
);
896 XChangeWindowAttributes(x11
->display
, x11
->window
, xswamask
, &xswa
);
900 /* Grab the mouse pointer in our window */
902 XGrabPointer(x11
->display
, x11
->window
, True
, 0,
903 GrabModeAsync
, GrabModeAsync
,
904 x11
->window
, None
, CurrentTime
);
905 XSetInputFocus(x11
->display
, x11
->window
, RevertToNone
, CurrentTime
);
909 if ((flags
& VOFLAG_FULLSCREEN
) && WinID
<= 0)
912 if (initialize_vdpau_objects(vo
) < 0)
918 static void check_events(struct vo
*vo
)
920 struct vdpctx
*vc
= vo
->priv
;
921 struct vdp_functions
*vdp
= vc
->vdp
;
923 if (handle_preemption(vo
) < 0)
926 int e
= vo_x11_check_events(vo
);
928 if (e
& VO_EVENT_RESIZE
)
930 else if (e
& VO_EVENT_EXPOSE
&& vc
->paused
) {
931 /* did we already draw a buffer */
932 if (vc
->num_shown_frames
) {
933 /* redraw the last visible buffer */
935 int last_surface
= (vc
->surface_num
+ NUM_OUTPUT_SURFACES
- 1)
936 % NUM_OUTPUT_SURFACES
;
937 vdp_st
= vdp
->presentation_queue_display(vc
->flip_queue
,
938 vc
->output_surfaces
[last_surface
],
939 vo
->dwidth
, vo
->dheight
, 0);
940 CHECK_ST_WARNING("Error when calling "
941 "vdp_presentation_queue_display");
946 static void draw_osd_I8A8(void *ctx
, int x0
, int y0
, int w
, int h
,
947 unsigned char *src
, unsigned char *srca
, int stride
)
950 struct vdpctx
*vc
= vo
->priv
;
951 struct vdp_functions
*vdp
= vc
->vdp
;
952 VdpOutputSurface output_surface
= vc
->output_surfaces
[vc
->surface_num
];
956 int index_data_size_required
;
957 VdpRect output_indexed_rect_vid
;
962 index_data_size_required
= 2*w
*h
;
963 if (vc
->index_data_size
< index_data_size_required
) {
964 vc
->index_data
= talloc_realloc_size(vc
, vc
->index_data
,
965 index_data_size_required
);
966 vc
->index_data_size
= index_data_size_required
;
969 // index_data creation, component order - I, A, I, A, .....
970 for (i
= 0; i
< h
; i
++)
971 for (int j
= 0; j
< w
; j
++) {
972 vc
->index_data
[i
*2*w
+ j
*2] = src
[i
*stride
+j
];
973 vc
->index_data
[i
*2*w
+ j
*2 + 1] = -srca
[i
*stride
+j
];
976 output_indexed_rect_vid
.x0
= x0
;
977 output_indexed_rect_vid
.y0
= y0
;
978 output_indexed_rect_vid
.x1
= x0
+ w
;
979 output_indexed_rect_vid
.y1
= y0
+ h
;
983 // write source_data to osd_surface.
985 output_surface_put_bits_indexed(osd_surface
, VDP_INDEXED_FORMAT_I8A8
,
986 (const void *const*)&vc
->index_data
,
987 &pitch
, &output_indexed_rect_vid
,
988 VDP_COLOR_TABLE_FORMAT_B8G8R8X8
,
989 (void *)vc
->palette
);
990 CHECK_ST_WARNING("Error when calling vdp_output_surface_put_bits_indexed");
992 VdpOutputSurfaceRenderBlendState blend_state
= {
993 .struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
,
994 .blend_factor_source_color
=
995 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
996 .blend_factor_source_alpha
=
997 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
998 .blend_factor_destination_color
=
999 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
1000 .blend_factor_destination_alpha
=
1001 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
1002 .blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1003 .blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1007 output_surface_render_output_surface(output_surface
,
1008 &output_indexed_rect_vid
,
1010 &output_indexed_rect_vid
,
1012 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
1013 CHECK_ST_WARNING("Error when calling "
1014 "vdp_output_surface_render_output_surface");
1017 static void draw_eosd(struct vo
*vo
)
1019 struct vdpctx
*vc
= vo
->priv
;
1020 struct vdp_functions
*vdp
= vc
->vdp
;
1022 VdpOutputSurface output_surface
= vc
->output_surfaces
[vc
->surface_num
];
1025 if (handle_preemption(vo
) < 0)
1028 VdpOutputSurfaceRenderBlendState blend_state
= {
1029 .struct_version
= VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION
,
1030 .blend_factor_source_color
=
1031 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
1032 .blend_factor_source_alpha
=
1033 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE
,
1034 .blend_factor_destination_color
=
1035 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA
,
1036 .blend_factor_destination_alpha
=
1037 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA
,
1038 .blend_equation_color
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1039 .blend_equation_alpha
= VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD
,
1042 for (i
= 0; i
< vc
->eosd_render_count
; i
++) {
1044 output_surface_render_bitmap_surface(output_surface
,
1045 &vc
->eosd_targets
[i
].dest
,
1046 vc
->eosd_surface
.surface
,
1047 &vc
->eosd_targets
[i
].source
,
1048 &vc
->eosd_targets
[i
].color
,
1050 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0
);
1051 CHECK_ST_WARNING("EOSD: Error when rendering");
1055 #define HEIGHT_SORT_BITS 4
1056 static int size_index(struct eosd_target
*r
)
1058 unsigned int h
= r
->source
.y1
;
1059 int n
= av_log2_16bit(h
);
1060 return (n
<< HEIGHT_SORT_BITS
)
1061 + (- 1 - (h
<< HEIGHT_SORT_BITS
>> n
) & (1 << HEIGHT_SORT_BITS
) - 1);
1064 /* Pack the given rectangles into an area of size w * h.
1065 * The size of each rectangle is read from .source.x1/.source.y1.
1066 * The height of each rectangle must be at least 1 and less than 65536.
1067 * The .source rectangle is then set corresponding to the packed position.
1068 * 'scratch' must point to work memory for num_rects+16 ints.
1069 * Return 0 on success, -1 if the rectangles did not fit in w*h.
1071 * The rectangles are placed in rows in order approximately sorted by
1072 * height (the approximate sorting is simpler than a full one would be,
1073 * and allows the algorithm to work in linear time). Additionally, to
1074 * reduce wasted space when there are a few tall rectangles, empty
1075 * lower-right parts of rows are filled recursively when the size of
1076 * rectangles in the row drops past a power-of-two threshold. So if a
1077 * row starts with rectangles of size 3x50, 10x40 and 5x20 then the
1078 * free rectangle with corners (13, 20)-(w, 50) is filled recursively.
1080 static int pack_rectangles(struct eosd_target
*rects
, int num_rects
,
1081 int w
, int h
, int *scratch
)
1083 int bins
[16 << HEIGHT_SORT_BITS
];
1084 int sizes
[16 << HEIGHT_SORT_BITS
] = {};
1085 for (int i
= 0; i
< num_rects
; i
++)
1086 sizes
[size_index(rects
+ i
)]++;
1088 for (int i
= 0; i
< 16 << HEIGHT_SORT_BITS
; i
+= 1 << HEIGHT_SORT_BITS
) {
1089 for (int j
= 0; j
< 1 << HEIGHT_SORT_BITS
; j
++) {
1091 idx
+= sizes
[i
+ j
];
1093 scratch
[idx
++] = -1;
1095 for (int i
= 0; i
< num_rects
; i
++)
1096 scratch
[bins
[size_index(rects
+ i
)]++] = i
;
1097 for (int i
= 0; i
< 16; i
++)
1098 bins
[i
] = bins
[i
<< HEIGHT_SORT_BITS
] - sizes
[i
<< HEIGHT_SORT_BITS
];
1100 int size
, x
, bottom
;
1101 } stack
[16] = {{15, 0, h
}}, s
= {};
1106 s
= stack
[--stackpos
];
1111 while ((obj
= scratch
[bins
[s
.size
]]) >= 0) {
1112 int bottom
= y
+ rects
[obj
].source
.y1
;
1113 if (bottom
> s
.bottom
)
1115 int right
= s
.x
+ rects
[obj
].source
.x1
;
1119 rects
[obj
].source
.x0
= s
.x
;
1120 rects
[obj
].source
.x1
+= s
.x
;
1121 rects
[obj
].source
.y0
= y
;
1122 rects
[obj
].source
.y1
+= y
;
1125 stack
[stackpos
++] = s
;
1127 maxy
= FFMAX(maxy
, bottom
);
1133 return num_rects
? -1 : 0;
1136 static void generate_eosd(struct vo
*vo
, mp_eosd_images_t
*imgs
)
1138 struct vdpctx
*vc
= vo
->priv
;
1139 struct vdp_functions
*vdp
= vc
->vdp
;
1142 ASS_Image
*img
= imgs
->imgs
;
1144 struct eosd_bitmap_surface
*sfc
= &vc
->eosd_surface
;
1145 bool need_upload
= false;
1147 if (imgs
->changed
== 0)
1148 return; // Nothing changed, no need to redraw
1150 vc
->eosd_render_count
= 0;
1153 return; // There's nothing to render!
1155 if (imgs
->changed
== 1)
1156 goto eosd_skip_upload
;
1159 bool reallocate
= false;
1161 for (p
= img
, i
= 0; p
; p
= p
->next
) {
1162 if (p
->w
<= 0 || p
->h
<= 0)
1164 // Allocate new space for surface/target arrays
1165 if (i
>= vc
->eosd_targets_size
) {
1166 vc
->eosd_targets_size
= FFMAX(vc
->eosd_targets_size
* 2, 512);
1168 talloc_realloc_size(vc
, vc
->eosd_targets
,
1169 vc
->eosd_targets_size
1170 * sizeof(*vc
->eosd_targets
));
1172 talloc_realloc_size(vc
, vc
->eosd_scratch
,
1173 (vc
->eosd_targets_size
+ 16)
1174 * sizeof(*vc
->eosd_scratch
));
1176 vc
->eosd_targets
[i
].source
.x1
= p
->w
;
1177 vc
->eosd_targets
[i
].source
.y1
= p
->h
;
1180 if (pack_rectangles(vc
->eosd_targets
, i
, sfc
->w
, sfc
->h
,
1181 vc
->eosd_scratch
) >= 0)
1183 int w
= FFMIN(FFMAX(sfc
->w
* 2, EOSD_SURFACE_INITIAL_SIZE
),
1185 int h
= FFMIN(FFMAX(sfc
->h
* 2, EOSD_SURFACE_INITIAL_SIZE
),
1187 if (w
== sfc
->w
&& h
== sfc
->h
) {
1188 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] EOSD bitmaps do not fit on "
1189 "a surface with the maximum supported size\n");
1198 if (sfc
->surface
!= VDP_INVALID_HANDLE
)
1199 vdp
->bitmap_surface_destroy(sfc
->surface
);
1200 mp_msg(MSGT_VO
, MSGL_V
, "[vdpau] Allocating a %dx%d surface for "
1201 "EOSD bitmaps.\n", sfc
->w
, sfc
->h
);
1202 vdp_st
= vdp
->bitmap_surface_create(vc
->vdp_device
, VDP_RGBA_FORMAT_A8
,
1203 sfc
->w
, sfc
->h
, true,
1205 if (vdp_st
!= VDP_STATUS_OK
)
1206 sfc
->surface
= VDP_INVALID_HANDLE
;
1207 CHECK_ST_WARNING("EOSD: error when creating surface");
1211 if (sfc
->surface
== VDP_INVALID_HANDLE
)
1213 for (p
= img
; p
; p
= p
->next
) {
1214 if (p
->w
<= 0 || p
->h
<= 0)
1216 struct eosd_target
*target
= &vc
->eosd_targets
[vc
->eosd_render_count
];
1219 bitmap_surface_put_bits_native(sfc
->surface
,
1220 (const void *) &p
->bitmap
,
1221 &p
->stride
, &target
->source
);
1222 CHECK_ST_WARNING("EOSD: putbits failed");
1224 // Render dest, color, etc.
1225 target
->color
.alpha
= 1.0 - ((p
->color
>> 0) & 0xff) / 255.0;
1226 target
->color
.blue
= ((p
->color
>> 8) & 0xff) / 255.0;
1227 target
->color
.green
= ((p
->color
>> 16) & 0xff) / 255.0;
1228 target
->color
.red
= ((p
->color
>> 24) & 0xff) / 255.0;
1229 target
->dest
.x0
= p
->dst_x
;
1230 target
->dest
.y0
= p
->dst_y
;
1231 target
->dest
.x1
= p
->w
+ p
->dst_x
;
1232 target
->dest
.y1
= p
->h
+ p
->dst_y
;
1233 vc
->eosd_render_count
++;
1237 static void draw_osd(struct vo
*vo
, struct osd_state
*osd
)
1239 struct vdpctx
*vc
= vo
->priv
;
1240 mp_msg(MSGT_VO
, MSGL_DBG2
, "DRAW_OSD\n");
1242 if (handle_preemption(vo
) < 0)
1245 osd_draw_text_ext(osd
, vo
->dwidth
, vo
->dheight
, vc
->border_x
, vc
->border_y
,
1246 vc
->border_x
, vc
->border_y
, vc
->vid_width
,
1247 vc
->vid_height
, draw_osd_I8A8
, vo
);
1250 static void wait_for_previous_frame(struct vo
*vo
)
1252 struct vdpctx
*vc
= vo
->priv
;
1253 struct vdp_functions
*vdp
= vc
->vdp
;
1256 if (vc
->num_shown_frames
< 2)
1260 VdpOutputSurface visible_s
, prev_s
;
1261 int base
= vc
->surface_num
+ NUM_OUTPUT_SURFACES
;
1262 visible_s
= vc
->output_surfaces
[(base
- 1) % NUM_OUTPUT_SURFACES
];
1263 prev_s
= vc
->output_surfaces
[(base
- 2) % NUM_OUTPUT_SURFACES
];
1264 vdp_st
= vdp
->presentation_queue_block_until_surface_idle(vc
->flip_queue
,
1266 CHECK_ST_WARNING("Error calling "
1267 "presentation_queue_block_until_surface_idle");
1268 VdpPresentationQueueStatus status
;
1269 vdp_st
= vdp
->presentation_queue_query_surface_status(vc
->flip_queue
,
1272 CHECK_ST_WARNING("Error calling presentation_queue_query_surface_status");
1273 vc
->recent_vsync_time
= vtime
;
1276 static inline uint64_t prev_vs2(struct vdpctx
*vc
, uint64_t ts
, int shift
)
1278 uint64_t offset
= ts
- vc
->recent_vsync_time
;
1279 // Fix negative values for 1<<shift vsyncs before vc->recent_vsync_time
1280 offset
+= (uint64_t)vc
->vsync_interval
<< shift
;
1281 offset
%= vc
->vsync_interval
;
1285 static void flip_page_timed(struct vo
*vo
, unsigned int pts_us
, int duration
)
1287 struct vdpctx
*vc
= vo
->priv
;
1288 struct vdp_functions
*vdp
= vc
->vdp
;
1290 uint32_t vsync_interval
= vc
->vsync_interval
;
1292 if (handle_preemption(vo
) < 0)
1295 if (duration
> INT_MAX
/ 1000)
1300 if (vc
->user_fps
< 0)
1301 duration
= -1; // Make sure drop logic is disabled
1303 uint64_t now
= sync_vdptime(vo
);
1304 uint64_t pts
= pts_us
? convert_to_vdptime(vo
, pts_us
) : now
;
1305 uint64_t ideal_pts
= pts
;
1306 uint64_t npts
= duration
>= 0 ? pts
+ duration
: UINT64_MAX
;
1308 #define PREV_VS2(ts, shift) prev_vs2(vc, ts, shift)
1309 // Only gives accurate results for ts >= vc->recent_vsync_time
1310 #define PREV_VSYNC(ts) PREV_VS2(ts, 0)
1312 /* We hope to be here at least one vsync before the frame should be shown.
1313 * If we are running late then don't drop the frame unless there is
1314 * already one queued for the next vsync; even if we _hope_ to show the
1315 * next frame soon enough to mean this one should be dropped we might
1316 * not make the target time in reality. Without this check we could drop
1317 * every frame, freezing the display completely if video lags behind.
1319 if (now
> PREV_VSYNC(FFMAX(pts
,
1320 vc
->last_queue_time
+ vsync_interval
)))
1323 /* Allow flipping a frame at a vsync if its presentation time is a
1324 * bit after that vsync and the change makes the flip time delta
1325 * from previous frame better match the target timestamp delta.
1326 * This avoids instability with frame timestamps falling near vsyncs.
1327 * For example if the frame timestamps were (with vsyncs at
1328 * integer values) 0.01, 1.99, 4.01, 5.99, 8.01, ... then
1329 * straightforward timing at next vsync would flip the frames at
1330 * 1, 2, 5, 6, 9; this changes it to 1, 2, 4, 6, 8 and so on with
1331 * regular 2-vsync intervals.
1333 * Also allow moving the frame forward if it looks like we dropped
1334 * the previous frame incorrectly (now that we know better after
1335 * having final exact timestamp information for this frame) and
1336 * there would unnecessarily be a vsync without a frame change.
1338 uint64_t vsync
= PREV_VSYNC(pts
);
1339 if (pts
< vsync
+ vsync_interval
/ 4
1340 && (vsync
- PREV_VS2(vc
->last_queue_time
, 16)
1341 > pts
- vc
->last_ideal_time
+ vsync_interval
/ 2
1342 || vc
->dropped_frame
&& vsync
> vc
->dropped_time
))
1343 pts
-= vsync_interval
/ 2;
1345 vc
->dropped_frame
= true; // changed at end if false
1346 vc
->dropped_time
= ideal_pts
;
1348 pts
= FFMAX(pts
, vc
->last_queue_time
+ vsync_interval
);
1349 pts
= FFMAX(pts
, now
);
1350 if (npts
< PREV_VSYNC(pts
) + vsync_interval
)
1353 /* At least on my NVIDIA 9500GT with driver versions 185.18.36 and 190.42
1354 * trying to queue two unshown frames simultaneously caused bad behavior
1355 * (high CPU use in _other_ VDPAU functions called later). Avoiding
1356 * longer queues also makes things simpler. So currently we always
1357 * try to keep exactly one frame queued for the future, queuing the
1358 * current frame immediately after the previous one is shown.
1360 wait_for_previous_frame(vo
);
1362 now
= sync_vdptime(vo
);
1363 pts
= FFMAX(pts
, now
);
1364 vsync
= PREV_VSYNC(pts
);
1365 if (npts
< vsync
+ vsync_interval
)
1367 pts
= vsync
+ (vsync_interval
>> 2);
1369 vdp
->presentation_queue_display(vc
->flip_queue
,
1370 vc
->output_surfaces
[vc
->surface_num
],
1371 vo
->dwidth
, vo
->dheight
, pts
);
1372 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display");
1374 vc
->last_queue_time
= pts
;
1375 vc
->last_ideal_time
= ideal_pts
;
1376 vc
->dropped_frame
= false;
1377 vc
->surface_num
= (vc
->surface_num
+ 1) % NUM_OUTPUT_SURFACES
;
1378 vc
->num_shown_frames
= FFMIN(vc
->num_shown_frames
+ 1, 1000);
1381 static int draw_slice(struct vo
*vo
, uint8_t *image
[], int stride
[], int w
,
1382 int h
, int x
, int y
)
1384 struct vdpctx
*vc
= vo
->priv
;
1385 struct vdp_functions
*vdp
= vc
->vdp
;
1388 if (handle_preemption(vo
) < 0)
1391 struct vdpau_render_state
*rndr
= (struct vdpau_render_state
*)image
[0];
1392 int max_refs
= vc
->image_format
== IMGFMT_VDPAU_H264
?
1393 rndr
->info
.h264
.num_ref_frames
: 2;
1394 if (!IMGFMT_IS_VDPAU(vc
->image_format
))
1396 if ((vc
->decoder
== VDP_INVALID_HANDLE
|| vc
->decoder_max_refs
< max_refs
)
1397 && !create_vdp_decoder(vo
, max_refs
))
1400 vdp_st
= vdp
->decoder_render(vc
->decoder
, rndr
->surface
,
1401 (void *)&rndr
->info
,
1402 rndr
->bitstream_buffers_used
,
1403 rndr
->bitstream_buffers
);
1404 CHECK_ST_WARNING("Failed VDPAU decoder rendering");
1409 static struct vdpau_render_state
*get_surface(struct vo
*vo
, int number
)
1411 struct vdpctx
*vc
= vo
->priv
;
1412 struct vdp_functions
*vdp
= vc
->vdp
;
1414 if (number
> MAX_VIDEO_SURFACES
)
1416 if (vc
->surface_render
[number
].surface
== VDP_INVALID_HANDLE
1417 && !vc
->is_preempted
) {
1419 vdp_st
= vdp
->video_surface_create(vc
->vdp_device
, vc
->vdp_chroma_type
,
1420 vc
->vid_width
, vc
->vid_height
,
1421 &vc
->surface_render
[number
].surface
);
1422 CHECK_ST_WARNING("Error when calling vdp_video_surface_create");
1424 mp_msg(MSGT_VO
, MSGL_DBG2
, "VID CREATE: %u\n",
1425 vc
->surface_render
[number
].surface
);
1426 return &vc
->surface_render
[number
];
1429 static void draw_image(struct vo
*vo
, mp_image_t
*mpi
, double pts
)
1431 struct vdpctx
*vc
= vo
->priv
;
1432 struct vdp_functions
*vdp
= vc
->vdp
;
1433 struct mp_image
*reserved_mpi
= NULL
;
1434 struct vdpau_render_state
*rndr
;
1436 if (vc
->is_preempted
) {
1437 vo
->frame_loaded
= true;
1441 if (IMGFMT_IS_VDPAU(vc
->image_format
)) {
1444 } else if (!(mpi
->flags
& MP_IMGFLAG_DRAW_CALLBACK
)) {
1446 void *destdata
[3] = {mpi
->planes
[0], mpi
->planes
[2], mpi
->planes
[1]};
1447 rndr
= get_surface(vo
, vc
->deint_counter
);
1448 vc
->deint_counter
= (vc
->deint_counter
+ 1) % NUM_BUFFERED_VIDEO
;
1449 if (vc
->image_format
== IMGFMT_NV12
)
1450 destdata
[1] = destdata
[2];
1452 vdp
->video_surface_put_bits_y_cb_cr(rndr
->surface
,
1453 vc
->vdp_pixel_format
,
1454 (const void *const*)destdata
,
1455 mpi
->stride
); // pitch
1456 CHECK_ST_WARNING("Error when calling "
1457 "vdp_video_surface_put_bits_y_cb_cr");
1459 // We don't support slice callbacks so this shouldn't occur -
1460 // I think the flags test above in pointless, but I'm adding
1461 // this instead of removing it just in case.
1463 if (mpi
->fields
& MP_IMGFIELD_ORDERED
)
1464 vc
->top_field_first
= !!(mpi
->fields
& MP_IMGFIELD_TOP_FIRST
);
1466 vc
->top_field_first
= 1;
1468 add_new_video_surface(vo
, rndr
->surface
, mpi
, pts
);
1473 static uint32_t get_image(struct vo
*vo
, mp_image_t
*mpi
)
1475 struct vdpctx
*vc
= vo
->priv
;
1476 struct vdpau_render_state
*rndr
;
1478 // no dr for non-decoding for now
1479 if (!IMGFMT_IS_VDPAU(vc
->image_format
))
1481 if (mpi
->type
!= MP_IMGTYPE_NUMBERED
)
1484 rndr
= get_surface(vo
, mpi
->number
);
1486 mp_msg(MSGT_VO
, MSGL_ERR
, "[vdpau] no surfaces available in "
1488 // TODO: this probably breaks things forever, provide a dummy buffer?
1491 mpi
->flags
|= MP_IMGFLAG_DIRECT
;
1492 mpi
->stride
[0] = mpi
->stride
[1] = mpi
->stride
[2] = 0;
1493 mpi
->planes
[0] = mpi
->planes
[1] = mpi
->planes
[2] = NULL
;
1494 // hack to get around a check and to avoid a special-case in vd_ffmpeg.c
1495 mpi
->planes
[0] = (void *)rndr
;
1496 mpi
->num_planes
= 1;
1501 static int query_format(uint32_t format
)
1503 int default_flags
= VFCAP_CSP_SUPPORTED
| VFCAP_CSP_SUPPORTED_BY_HW
1504 | VFCAP_HWSCALE_UP
| VFCAP_HWSCALE_DOWN
| VFCAP_OSD
| VFCAP_EOSD
1505 | VFCAP_EOSD_UNSCALED
| VFCAP_FLIP
;
1513 return default_flags
| VOCAP_NOSLICES
;
1514 case IMGFMT_VDPAU_MPEG1
:
1515 case IMGFMT_VDPAU_MPEG2
:
1516 case IMGFMT_VDPAU_H264
:
1517 case IMGFMT_VDPAU_WMV3
:
1518 case IMGFMT_VDPAU_VC1
:
1519 case IMGFMT_VDPAU_MPEG4
:
1520 return default_flags
;
1525 static void destroy_vdpau_objects(struct vo
*vo
)
1527 struct vdpctx
*vc
= vo
->priv
;
1528 struct vdp_functions
*vdp
= vc
->vdp
;
1533 free_video_specific(vo
);
1535 if (vc
->flip_queue
!= VDP_INVALID_HANDLE
) {
1536 vdp_st
= vdp
->presentation_queue_destroy(vc
->flip_queue
);
1537 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy");
1540 if (vc
->flip_target
!= VDP_INVALID_HANDLE
) {
1541 vdp_st
= vdp
->presentation_queue_target_destroy(vc
->flip_target
);
1542 CHECK_ST_WARNING("Error when calling "
1543 "vdp_presentation_queue_target_destroy");
1546 for (i
= 0; i
<= NUM_OUTPUT_SURFACES
; i
++) {
1547 if (vc
->output_surfaces
[i
] == VDP_INVALID_HANDLE
)
1549 vdp_st
= vdp
->output_surface_destroy(vc
->output_surfaces
[i
]);
1550 CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
1553 if (vc
->eosd_surface
.surface
!= VDP_INVALID_HANDLE
) {
1554 vdp_st
= vdp
->bitmap_surface_destroy(vc
->eosd_surface
.surface
);
1555 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
1558 vdp_st
= vdp
->device_destroy(vc
->vdp_device
);
1559 CHECK_ST_WARNING("Error when calling vdp_device_destroy");
1562 static void uninit(struct vo
*vo
)
1564 struct vdpctx
*vc
= vo
->priv
;
1566 /* Destroy all vdpau objects */
1567 destroy_vdpau_objects(vo
);
1569 #ifdef CONFIG_XF86VM
1570 if (vc
->mode_switched
)
1575 // Free bitstream buffers allocated by FFmpeg
1576 for (int i
= 0; i
< MAX_VIDEO_SURFACES
; i
++)
1577 av_freep(&vc
->surface_render
[i
].bitstream_buffers
);
1580 static int preinit(struct vo
*vo
, const char *arg
)
1584 struct vdpctx
*vc
= talloc_zero(vo
, struct vdpctx
);
1587 // Mark everything as invalid first so uninit() can tell what has been
1589 mark_vdpau_objects_uninitialized(vo
);
1592 vc
->chroma_deint
= 1;
1593 vc
->user_colorspace
= 1;
1594 vc
->flip_offset_window
= 50;
1595 vc
->flip_offset_fs
= 50;
1596 const opt_t subopts
[] = {
1597 {"deint", OPT_ARG_INT
, &vc
->deint
, (opt_test_f
)int_non_neg
},
1598 {"chroma-deint", OPT_ARG_BOOL
, &vc
->chroma_deint
, NULL
},
1599 {"pullup", OPT_ARG_BOOL
, &vc
->pullup
, NULL
},
1600 {"denoise", OPT_ARG_FLOAT
, &vc
->denoise
, NULL
},
1601 {"sharpen", OPT_ARG_FLOAT
, &vc
->sharpen
, NULL
},
1602 {"colorspace", OPT_ARG_INT
, &vc
->user_colorspace
, NULL
},
1603 {"hqscaling", OPT_ARG_INT
, &vc
->hqscaling
, NULL
},
1604 {"fps", OPT_ARG_FLOAT
, &vc
->user_fps
, NULL
},
1605 {"queuetime_windowed", OPT_ARG_INT
, &vc
->flip_offset_window
, NULL
},
1606 {"queuetime_fs", OPT_ARG_INT
, &vc
->flip_offset_fs
, NULL
},
1609 if (subopt_parse(arg
, subopts
) != 0) {
1610 mp_msg(MSGT_VO
, MSGL_FATAL
, "[vdpau] Could not parse suboptions.\n");
1613 if (vc
->hqscaling
< 0 || vc
->hqscaling
> 9) {
1614 mp_msg(MSGT_VO
, MSGL_FATAL
, "[vdpau] Invalid value for suboption "
1619 vc
->deint_type
= vc
->deint
;
1624 // After this calling uninit() should work to free resources
1626 if (win_x11_init_vdpau_procs(vo
) < 0) {
1627 if (vc
->vdp
->device_destroy
)
1628 vc
->vdp
->device_destroy(vc
->vdp_device
);
1633 // full grayscale palette.
1634 for (i
= 0; i
< PALETTE_SIZE
; ++i
)
1635 vc
->palette
[i
] = (i
<< 16) | (i
<< 8) | i
;
1637 vc
->procamp
.struct_version
= VDP_PROCAMP_VERSION
;
1638 vc
->procamp
.brightness
= 0.0;
1639 vc
->procamp
.contrast
= 1.0;
1640 vc
->procamp
.saturation
= 1.0;
1641 vc
->procamp
.hue
= 0.0;
1646 static int get_equalizer(struct vo
*vo
, const char *name
, int *value
)
1648 struct vdpctx
*vc
= vo
->priv
;
1650 if (!strcasecmp(name
, "brightness"))
1651 *value
= vc
->procamp
.brightness
* 100;
1652 else if (!strcasecmp(name
, "contrast"))
1653 *value
= (vc
->procamp
.contrast
- 1.0) * 100;
1654 else if (!strcasecmp(name
, "saturation"))
1655 *value
= (vc
->procamp
.saturation
- 1.0) * 100;
1656 else if (!strcasecmp(name
, "hue"))
1657 *value
= vc
->procamp
.hue
* 100 / M_PI
;
1663 static int set_equalizer(struct vo
*vo
, const char *name
, int value
)
1665 struct vdpctx
*vc
= vo
->priv
;
1667 if (!strcasecmp(name
, "brightness"))
1668 vc
->procamp
.brightness
= value
/ 100.0;
1669 else if (!strcasecmp(name
, "contrast"))
1670 vc
->procamp
.contrast
= value
/ 100.0 + 1.0;
1671 else if (!strcasecmp(name
, "saturation"))
1672 vc
->procamp
.saturation
= value
/ 100.0 + 1.0;
1673 else if (!strcasecmp(name
, "hue"))
1674 vc
->procamp
.hue
= value
/ 100.0 * M_PI
;
1678 update_csc_matrix(vo
);
1682 static int control(struct vo
*vo
, uint32_t request
, void *data
)
1684 struct vdpctx
*vc
= vo
->priv
;
1685 struct vdp_functions
*vdp
= vc
->vdp
;
1687 handle_preemption(vo
);
1690 case VOCTRL_GET_DEINTERLACE
:
1691 *(int*)data
= vc
->deint
;
1693 case VOCTRL_SET_DEINTERLACE
:
1694 vc
->deint
= *(int*)data
;
1696 vc
->deint
= vc
->deint_type
;
1697 if (vc
->deint_type
> 2) {
1699 VdpVideoMixerFeature features
[1] =
1700 {vc
->deint_type
== 3 ?
1701 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL
:
1702 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL
};
1703 VdpBool feature_enables
[1] = {vc
->deint
? VDP_TRUE
: VDP_FALSE
};
1704 vdp_st
= vdp
->video_mixer_set_feature_enables(vc
->video_mixer
,
1707 CHECK_ST_WARNING("Error changing deinterlacing settings");
1711 if (vc
->dropped_frame
)
1712 flip_page_timed(vo
, 0, -1);
1713 return (vc
->paused
= true);
1715 return (vc
->paused
= false);
1716 case VOCTRL_QUERY_FORMAT
:
1717 return query_format(*(uint32_t *)data
);
1718 case VOCTRL_GET_IMAGE
:
1719 return get_image(vo
, data
);
1720 case VOCTRL_DRAW_IMAGE
:
1721 abort(); // draw_image() should get called directly
1726 case VOCTRL_FULLSCREEN
:
1727 vo_x11_fullscreen(vo
);
1730 case VOCTRL_GET_PANSCAN
:
1732 case VOCTRL_SET_PANSCAN
:
1735 case VOCTRL_SET_EQUALIZER
: {
1736 struct voctrl_set_equalizer_args
*args
= data
;
1737 return set_equalizer(vo
, args
->name
, args
->value
);
1739 case VOCTRL_GET_EQUALIZER
: {
1740 struct voctrl_get_equalizer_args
*args
= data
;
1741 return get_equalizer(vo
, args
->name
, args
->valueptr
);
1743 case VOCTRL_SET_YUV_COLORSPACE
:
1744 vc
->colorspace
= *(int *)data
% 3;
1745 update_csc_matrix(vo
);
1747 case VOCTRL_GET_YUV_COLORSPACE
:
1748 *(int *)data
= vc
->colorspace
;
1753 case VOCTRL_UPDATE_SCREENINFO
:
1754 update_xinerama_info(vo
);
1756 case VOCTRL_DRAW_EOSD
:
1759 generate_eosd(vo
, data
);
1762 case VOCTRL_GET_EOSD_RES
: {
1763 mp_eosd_res_t
*r
= data
;
1766 r
->ml
= r
->mr
= vc
->border_x
;
1767 r
->mt
= r
->mb
= vc
->border_y
;
1770 case VOCTRL_REDRAW_OSD
:
1771 video_to_output_surface(vo
);
1774 flip_page_timed(vo
, 0, -1);
1783 const struct vo_driver video_out_vdpau
= {
1785 .buffer_frames
= true,
1786 .info
= &(const struct vo_info_s
){
1789 "Rajib Mahapatra <rmahapatra@nvidia.com> and others",
1795 .draw_image
= draw_image
,
1796 .get_buffered_frame
= get_buffered_frame
,
1797 .draw_slice
= draw_slice
,
1798 .draw_osd
= draw_osd
,
1799 .flip_page_timed
= flip_page_timed
,
1800 .check_events
= check_events
,