vo_vdpau: Allocate one large surface for EOSD content
[mplayer/glamo.git] / libvo / vo_vdpau.c
blob7778c093d0d5deca202bd81bb45f2a39d174374c
1 /*
2 * VDPAU video output driver
4 * Copyright (C) 2008 NVIDIA
6 * This file is part of MPlayer.
8 * MPlayer is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * MPlayer is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License along
19 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24 * Actual decoding and presentation are implemented here.
25 * All necessary frame information is collected through
26 * the "vdpau_render_state" structure after parsing all headers
27 * etc. in libavcodec for different codecs.
30 #include <stdio.h>
31 #include <dlfcn.h>
32 #include <stdint.h>
33 #include <stdbool.h>
35 #include "config.h"
36 #include "mp_msg.h"
37 #include "options.h"
38 #include "talloc.h"
39 #include "video_out.h"
40 #include "x11_common.h"
41 #include "aspect.h"
42 #include "sub.h"
43 #include "subopt-helper.h"
44 #include "libmpcodecs/vfcap.h"
45 #include "libmpcodecs/mp_image.h"
47 #include "libavcodec/vdpau.h"
49 #include "font_load.h"
51 #include "libavutil/common.h"
52 #include "libavutil/mathematics.h"
54 #include "ass_mp.h"
56 #define CHECK_ST_ERROR(message) \
57 do { \
58 if (vdp_st != VDP_STATUS_OK) { \
59 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \
60 message, vdp->get_error_string(vdp_st)); \
61 return -1; \
62 } \
63 } while (0)
65 #define CHECK_ST_WARNING(message) \
66 do { \
67 if (vdp_st != VDP_STATUS_OK) \
68 mp_msg(MSGT_VO, MSGL_WARN, "[ vdpau] %s: %s\n", \
69 message, vdp->get_error_string(vdp_st)); \
70 } while (0)
72 /* number of video and output surfaces */
73 #define NUM_OUTPUT_SURFACES 2
74 #define MAX_VIDEO_SURFACES 50
76 /* number of palette entries */
77 #define PALETTE_SIZE 256
79 /* Initial size of EOSD surface in pixels (x*x) */
80 #define EOSD_SURFACE_INITIAL_SIZE 256
83 * Global variable declaration - VDPAU specific
86 struct vdp_functions {
87 #define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name;
88 #include "vdpau_template.c"
89 #undef VDP_FUNCTION
92 struct vdpctx {
93 struct vdp_functions *vdp;
95 VdpDevice vdp_device;
96 VdpDeviceCreateX11 *vdp_device_create;
97 VdpGetProcAddress *vdp_get_proc_address;
99 VdpPresentationQueueTarget flip_target;
100 VdpPresentationQueue flip_queue;
102 void *vdpau_lib_handle;
104 /* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */
105 #define osd_surface vc->output_surfaces[NUM_OUTPUT_SURFACES]
106 VdpOutputSurface output_surfaces[NUM_OUTPUT_SURFACES + 1];
107 VdpVideoSurface deint_surfaces[3];
108 mp_image_t *deint_mpi[2];
109 int output_surface_width, output_surface_height;
111 VdpVideoMixer video_mixer;
112 int deint;
113 int deint_type;
114 int deint_counter;
115 int deint_buffer_past_frames;
116 int pullup;
117 float denoise;
118 float sharpen;
119 int chroma_deint;
120 int top_field_first;
122 VdpDecoder decoder;
123 int decoder_max_refs;
125 VdpRect src_rect_vid;
126 VdpRect out_rect_vid;
127 int border_x, border_y;
129 struct vdpau_render_state surface_render[MAX_VIDEO_SURFACES];
130 int surface_num;
131 int vid_surface_num;
132 uint32_t vid_width, vid_height;
133 uint32_t image_format;
134 VdpChromaType vdp_chroma_type;
135 VdpYCbCrFormat vdp_pixel_format;
137 /* draw_osd */
138 unsigned char *index_data;
139 int index_data_size;
140 uint32_t palette[PALETTE_SIZE];
142 // EOSD
143 // Pool of surfaces
144 struct eosd_bitmap_surface {
145 VdpBitmapSurface surface;
146 int w;
147 int h;
148 uint32_t max_width;
149 uint32_t max_height;
150 } eosd_surface;
152 // List of surfaces to be rendered
153 struct eosd_target {
154 VdpRect source;
155 VdpRect dest;
156 VdpColor color;
157 } *eosd_targets;
158 int eosd_targets_size;
159 int *eosd_scratch;
161 int eosd_render_count;
163 // Video equalizer
164 VdpProcamp procamp;
166 bool visible_buf;
167 bool paused;
169 // These tell what's been initialized and uninit() should free/uninitialize
170 bool mode_switched;
174 static void push_deint_surface(struct vo *vo, VdpVideoSurface surface)
176 struct vdpctx *vc = vo->priv;
177 vc->deint_surfaces[2] = vc->deint_surfaces[1];
178 vc->deint_surfaces[1] = vc->deint_surfaces[0];
179 vc->deint_surfaces[0] = surface;
182 static void flip_page(struct vo *vo);
183 static void video_to_output_surface(struct vo *vo)
185 struct vdpctx *vc = vo->priv;
186 struct vdp_functions *vdp = vc->vdp;
187 VdpTime dummy;
188 VdpStatus vdp_st;
189 int i;
190 if (vc->vid_surface_num < 0)
191 return;
193 if (vc->deint < 2 || vc->deint_surfaces[0] == VDP_INVALID_HANDLE)
194 push_deint_surface(vo, vc->surface_render[vc->vid_surface_num].surface);
196 for (i = 0; i <= (vc->deint > 1); i++) {
197 int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
198 VdpOutputSurface output_surface;
199 if (i) {
200 // draw_eosd()
201 // draw_osd()
202 flip_page(vo);
204 if (vc->deint)
205 field = (vc->top_field_first == i) ^ (vc->deint > 1) ?
206 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:
207 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
208 output_surface = vc->output_surfaces[vc->surface_num];
209 vdp_st = vdp->
210 presentation_queue_block_until_surface_idle(vc->flip_queue,
211 output_surface,
212 &dummy);
213 CHECK_ST_WARNING("Error when calling "
214 "vdp_presentation_queue_block_until_surface_idle");
216 vdp_st = vdp->video_mixer_render(vc->video_mixer, VDP_INVALID_HANDLE,
217 0, field, 2, vc->deint_surfaces + 1,
218 vc->deint_surfaces[0], 1,
219 &vc->surface_render[vc->vid_surface_num].surface,
220 &vc->src_rect_vid, output_surface,
221 NULL, &vc->out_rect_vid, 0, NULL);
222 CHECK_ST_WARNING("Error when calling vdp_video_mixer_render");
223 push_deint_surface(vo, vc->surface_render[vc->vid_surface_num].surface);
227 static void resize(struct vo *vo)
229 struct vdpctx *vc = vo->priv;
230 struct vdp_functions *vdp = vc->vdp;
231 VdpStatus vdp_st;
232 int i;
233 struct vo_rect src_rect;
234 struct vo_rect dst_rect;
235 struct vo_rect borders;
236 calc_src_dst_rects(vo, vc->vid_width, vc->vid_height, &src_rect, &dst_rect,
237 &borders, NULL);
238 vc->out_rect_vid.x0 = dst_rect.left;
239 vc->out_rect_vid.x1 = dst_rect.right;
240 vc->out_rect_vid.y0 = dst_rect.top;
241 vc->out_rect_vid.y1 = dst_rect.bottom;
242 vc->src_rect_vid.x0 = src_rect.left;
243 vc->src_rect_vid.x1 = src_rect.right;
244 vc->src_rect_vid.y0 = src_rect.top;
245 vc->src_rect_vid.y1 = src_rect.bottom;
246 vc->border_x = borders.left;
247 vc->border_y = borders.top;
248 #ifdef CONFIG_FREETYPE
249 // adjust font size to display size
250 force_load_font = 1;
251 #endif
252 vo_osd_changed(OSDTYPE_OSD);
254 if (vc->output_surface_width < vo->dwidth
255 || vc->output_surface_height < vo->dheight) {
256 if (vc->output_surface_width < vo->dwidth) {
257 vc->output_surface_width += vc->output_surface_width >> 1;
258 vc->output_surface_width = FFMAX(vc->output_surface_width,
259 vo->dwidth);
261 if (vc->output_surface_height < vo->dheight) {
262 vc->output_surface_height += vc->output_surface_height >> 1;
263 vc->output_surface_height = FFMAX(vc->output_surface_height,
264 vo->dheight);
266 // Creation of output_surfaces
267 for (i = 0; i <= NUM_OUTPUT_SURFACES; i++) {
268 if (vc->output_surfaces[i] != VDP_INVALID_HANDLE)
269 vdp->output_surface_destroy(vc->output_surfaces[i]);
270 vdp_st = vdp->output_surface_create(vc->vdp_device,
271 VDP_RGBA_FORMAT_B8G8R8A8,
272 vc->output_surface_width,
273 vc->output_surface_height,
274 &vc->output_surfaces[i]);
275 CHECK_ST_WARNING("Error when calling vdp_output_surface_create");
276 mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE: %u\n",
277 vc->output_surfaces[i]);
280 video_to_output_surface(vo);
281 if (vc->visible_buf)
282 flip_page(vo);
285 /* Initialize vdp_get_proc_address, called from preinit() */
286 static int win_x11_init_vdpau_procs(struct vo *vo)
288 struct vo_x11_state *x11 = vo->x11;
289 struct vdpctx *vc = vo->priv;
290 struct vdp_functions *vdp = talloc_zero(vc, struct vdp_functions);
291 vc->vdp = vdp;
292 VdpStatus vdp_st;
294 struct vdp_function {
295 const int id;
296 int offset;
299 const struct vdp_function *dsc;
301 static const struct vdp_function vdp_func[] = {
302 #define VDP_FUNCTION(_, macro_name, mp_name) {macro_name, offsetof(struct vdp_functions, mp_name)},
303 #include "vdpau_template.c"
304 #undef VDP_FUNCTION
305 {0, -1}
308 vdp_st = vc->vdp_device_create(x11->display, x11->screen,&vc->vdp_device,
309 &vc->vdp_get_proc_address);
310 if (vdp_st != VDP_STATUS_OK) {
311 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling "
312 "vdp_device_create_x11: %i\n", vdp_st);
313 return -1;
316 vdp->get_error_string = NULL;
317 for (dsc = vdp_func; dsc->offset >= 0; dsc++) {
318 vdp_st = vc->vdp_get_proc_address(vc->vdp_device, dsc->id,
319 (void **)((char *)vdp + dsc->offset));
320 if (vdp_st != VDP_STATUS_OK) {
321 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling "
322 "vdp_get_proc_address(function id %d): %s\n", dsc->id,
323 vdp->get_error_string ? vdp->get_error_string(vdp_st) : "?");
324 return -1;
327 return 0;
330 static int win_x11_init_vdpau_flip_queue(struct vo *vo)
332 struct vdpctx *vc = vo->priv;
333 struct vdp_functions *vdp = vc->vdp;
334 struct vo_x11_state *x11 = vo->x11;
335 VdpStatus vdp_st;
337 vdp_st = vdp->presentation_queue_target_create_x11(vc->vdp_device,
338 x11->window,
339 &vc->flip_target);
340 CHECK_ST_ERROR("Error when calling "
341 "vdp_presentation_queue_target_create_x11");
343 vdp_st = vdp->presentation_queue_create(vc->vdp_device, vc->flip_target,
344 &vc->flip_queue);
345 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create");
347 return 0;
350 static int create_vdp_mixer(struct vo *vo, VdpChromaType vdp_chroma_type)
352 struct vdpctx *vc = vo->priv;
353 struct vdp_functions *vdp = vc->vdp;
354 #define VDP_NUM_MIXER_PARAMETER 3
355 #define MAX_NUM_FEATURES 5
356 int i;
357 VdpStatus vdp_st;
358 int feature_count = 0;
359 VdpVideoMixerFeature features[MAX_NUM_FEATURES];
360 VdpBool feature_enables[MAX_NUM_FEATURES];
361 static const VdpVideoMixerAttribute denoise_attrib[] =
362 {VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL};
363 const void * const denoise_value[] = {&vc->denoise};
364 static const VdpVideoMixerAttribute sharpen_attrib[] =
365 {VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL};
366 const void * const sharpen_value[] = {&vc->sharpen};
367 static const VdpVideoMixerAttribute skip_chroma_attrib[] =
368 {VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
369 const uint8_t skip_chroma_value = 1;
370 const void * const skip_chroma_value_ptr[] = {&skip_chroma_value};
371 static const VdpVideoMixerParameter parameters[VDP_NUM_MIXER_PARAMETER] = {
372 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
373 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
374 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE,
376 const void *const parameter_values[VDP_NUM_MIXER_PARAMETER] = {
377 &vc->vid_width,
378 &vc->vid_height,
379 &vdp_chroma_type,
381 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL;
382 if (vc->deint == 4)
383 features[feature_count++] =
384 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL;
385 if (vc->pullup)
386 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE;
387 if (vc->denoise)
388 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION;
389 if (vc->sharpen)
390 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS;
392 vdp_st = vdp->video_mixer_create(vc->vdp_device, feature_count, features,
393 VDP_NUM_MIXER_PARAMETER,
394 parameters, parameter_values,
395 &vc->video_mixer);
396 CHECK_ST_ERROR("Error when calling vdp_video_mixer_create");
398 for (i = 0; i < feature_count; i++)
399 feature_enables[i] = VDP_TRUE;
400 if (vc->deint < 3)
401 feature_enables[0] = VDP_FALSE;
402 if (feature_count)
403 vdp->video_mixer_set_feature_enables(vc->video_mixer, feature_count,
404 features, feature_enables);
405 if (vc->denoise)
406 vdp->video_mixer_set_attribute_values(vc->video_mixer, 1,
407 denoise_attrib, denoise_value);
408 if (vc->sharpen)
409 vdp->video_mixer_set_attribute_values(vc->video_mixer, 1,
410 sharpen_attrib, sharpen_value);
411 if (!vc->chroma_deint)
412 vdp->video_mixer_set_attribute_values(vc->video_mixer, 1,
413 skip_chroma_attrib,
414 skip_chroma_value_ptr);
416 return 0;
419 // Free everything specific to a certain video file
420 static void free_video_specific(struct vo *vo)
422 struct vdpctx *vc = vo->priv;
423 struct vdp_functions *vdp = vc->vdp;
424 int i;
425 VdpStatus vdp_st;
427 if (vc->decoder != VDP_INVALID_HANDLE)
428 vdp->decoder_destroy(vc->decoder);
429 vc->decoder = VDP_INVALID_HANDLE;
430 vc->decoder_max_refs = -1;
432 for (i = 0; i < 3; i++)
433 vc->deint_surfaces[i] = VDP_INVALID_HANDLE;
435 for (i = 0; i < 2; i++)
436 if (vc->deint_mpi[i]) {
437 vc->deint_mpi[i]->usage_count--;
438 vc->deint_mpi[i] = NULL;
441 for (i = 0; i < MAX_VIDEO_SURFACES; i++) {
442 if (vc->surface_render[i].surface != VDP_INVALID_HANDLE) {
443 vdp_st = vdp->video_surface_destroy(vc->surface_render[i].surface);
444 CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy");
446 vc->surface_render[i].surface = VDP_INVALID_HANDLE;
449 if (vc->video_mixer != VDP_INVALID_HANDLE) {
450 vdp_st = vdp->video_mixer_destroy(vc->video_mixer);
451 CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy");
453 vc->video_mixer = VDP_INVALID_HANDLE;
456 static int create_vdp_decoder(struct vo *vo, int max_refs)
458 struct vdpctx *vc = vo->priv;
459 struct vdp_functions *vdp = vc->vdp;
460 VdpStatus vdp_st;
461 VdpDecoderProfile vdp_decoder_profile;
462 if (vc->decoder != VDP_INVALID_HANDLE)
463 vdp->decoder_destroy(vc->decoder);
464 switch (vc->image_format) {
465 case IMGFMT_VDPAU_MPEG1:
466 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
467 break;
468 case IMGFMT_VDPAU_MPEG2:
469 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
470 break;
471 case IMGFMT_VDPAU_H264:
472 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
473 mp_msg(MSGT_VO, MSGL_V, "[vdpau] Creating H264 hardware decoder "
474 "for %d reference frames.\n", max_refs);
475 break;
476 case IMGFMT_VDPAU_WMV3:
477 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
478 break;
479 case IMGFMT_VDPAU_VC1:
480 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
481 break;
483 vdp_st = vdp->decoder_create(vc->vdp_device, vdp_decoder_profile,
484 vc->vid_width, vc->vid_height, max_refs,
485 &vc->decoder);
486 CHECK_ST_WARNING("Failed creating VDPAU decoder");
487 if (vdp_st != VDP_STATUS_OK) {
488 vc->decoder = VDP_INVALID_HANDLE;
489 vc->decoder_max_refs = 0;
490 return 0;
492 vc->decoder_max_refs = max_refs;
493 return 1;
497 * connect to X server, create and map window, initialize all
498 * VDPAU objects, create different surfaces etc.
500 static int config(struct vo *vo, uint32_t width, uint32_t height,
501 uint32_t d_width, uint32_t d_height, uint32_t flags,
502 char *title, uint32_t format)
504 struct vdpctx *vc = vo->priv;
505 struct vo_x11_state *x11 = vo->x11;
506 XVisualInfo vinfo;
507 XSetWindowAttributes xswa;
508 XWindowAttributes attribs;
509 unsigned long xswamask;
510 int depth;
512 #ifdef CONFIG_XF86VM
513 int vm = flags & VOFLAG_MODESWITCHING;
514 #endif
516 vc->image_format = format;
517 vc->vid_width = width;
518 vc->vid_height = height;
519 free_video_specific(vo);
520 if (IMGFMT_IS_VDPAU(vc->image_format) && !create_vdp_decoder(vo, 2))
521 return -1;
523 vc->visible_buf = false;
525 #ifdef CONFIG_XF86VM
526 if (vm) {
527 vo_vm_switch(vo);
528 vc->mode_switched = true;
530 #endif
531 XGetWindowAttributes(x11->display, DefaultRootWindow(x11->display),
532 &attribs);
533 depth = attribs.depth;
534 if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
535 depth = 24;
536 XMatchVisualInfo(x11->display, x11->screen, depth, TrueColor, &vinfo);
538 xswa.background_pixel = 0;
539 xswa.border_pixel = 0;
540 /* Do not use CWBackPixel: It leads to VDPAU errors after
541 * aspect ratio changes. */
542 xswamask = CWBorderPixel;
544 vo_x11_create_vo_window(vo, &vinfo, vo->dx, vo->dy, d_width, d_height,
545 flags, CopyFromParent, "vdpau", title);
546 XChangeWindowAttributes(x11->display, x11->window, xswamask, &xswa);
548 #ifdef CONFIG_XF86VM
549 if (vm) {
550 /* Grab the mouse pointer in our window */
551 if (vo_grabpointer)
552 XGrabPointer(x11->display, x11->window, True, 0,
553 GrabModeAsync, GrabModeAsync,
554 x11->window, None, CurrentTime);
555 XSetInputFocus(x11->display, x11->window, RevertToNone, CurrentTime);
557 #endif
559 if ((flags & VOFLAG_FULLSCREEN) && WinID <= 0)
560 vo_fs = 1;
562 /* -----VDPAU related code here -------- */
563 if (vc->flip_queue == VDP_INVALID_HANDLE
564 && win_x11_init_vdpau_flip_queue(vo))
565 return -1;
567 vc->vdp_chroma_type = VDP_CHROMA_TYPE_420;
568 switch (vc->image_format) {
569 case IMGFMT_YV12:
570 case IMGFMT_I420:
571 case IMGFMT_IYUV:
572 vc->vdp_pixel_format = VDP_YCBCR_FORMAT_YV12;
573 break;
574 case IMGFMT_NV12:
575 vc->vdp_pixel_format = VDP_YCBCR_FORMAT_NV12;
576 break;
577 case IMGFMT_YUY2:
578 vc->vdp_pixel_format = VDP_YCBCR_FORMAT_YUYV;
579 vc->vdp_chroma_type = VDP_CHROMA_TYPE_422;
580 break;
581 case IMGFMT_UYVY:
582 vc->vdp_pixel_format = VDP_YCBCR_FORMAT_UYVY;
583 vc->vdp_chroma_type = VDP_CHROMA_TYPE_422;
585 if (create_vdp_mixer(vo, vc->vdp_chroma_type))
586 return -1;
588 vc->vdp->bitmap_surface_query_capabilities(vc->vdp_device,
589 VDP_RGBA_FORMAT_A8,
590 &(VdpBool){0},
591 &vc->eosd_surface.max_width,
592 &vc->eosd_surface.max_height);
593 vc->surface_num = 0;
594 vc->vid_surface_num = -1;
595 resize(vo);
597 return 0;
600 static void check_events(struct vo *vo)
602 struct vdpctx *vc = vo->priv;
603 struct vdp_functions *vdp = vc->vdp;
605 int e = vo_x11_check_events(vo);
607 if (e & VO_EVENT_RESIZE)
608 resize(vo);
610 if ((e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) && vc->paused) {
611 /* did we already draw a buffer */
612 if (vc->visible_buf) {
613 /* redraw the last visible buffer */
614 VdpStatus vdp_st;
615 vdp_st = vdp->presentation_queue_display(vc->flip_queue,
616 vc->output_surfaces[vc->surface_num],
617 vo->dwidth, vo->dheight, 0);
618 CHECK_ST_WARNING("Error when calling "
619 "vdp_presentation_queue_display");
624 static void draw_osd_I8A8(void *ctx, int x0, int y0, int w, int h,
625 unsigned char *src, unsigned char *srca, int stride)
627 struct vo *vo = ctx;
628 struct vdpctx *vc = vo->priv;
629 struct vdp_functions *vdp = vc->vdp;
630 VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num];
631 VdpStatus vdp_st;
632 int i;
633 int pitch;
634 int index_data_size_required;
635 VdpRect output_indexed_rect_vid;
637 if (!w || !h)
638 return;
640 index_data_size_required = 2*w*h;
641 if (vc->index_data_size < index_data_size_required) {
642 vc->index_data = talloc_realloc_size(vc, vc->index_data,
643 index_data_size_required);
644 vc->index_data_size = index_data_size_required;
647 // index_data creation, component order - I, A, I, A, .....
648 for (i = 0; i < h; i++)
649 for (int j = 0; j < w; j++) {
650 vc->index_data[i*2*w + j*2] = src [i*stride+j];
651 vc->index_data[i*2*w + j*2 + 1] = -srca[i*stride+j];
654 output_indexed_rect_vid.x0 = x0;
655 output_indexed_rect_vid.y0 = y0;
656 output_indexed_rect_vid.x1 = x0 + w;
657 output_indexed_rect_vid.y1 = y0 + h;
659 pitch = w*2;
661 // write source_data to osd_surface.
662 vdp_st = vdp->
663 output_surface_put_bits_indexed(osd_surface, VDP_INDEXED_FORMAT_I8A8,
664 (const void *const*)&vc->index_data,
665 &pitch, &output_indexed_rect_vid,
666 VDP_COLOR_TABLE_FORMAT_B8G8R8X8,
667 (void *)vc->palette);
668 CHECK_ST_WARNING("Error when calling vdp_output_surface_put_bits_indexed");
670 VdpOutputSurfaceRenderBlendState blend_state = {
671 .struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION,
672 .blend_factor_source_color =
673 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE,
674 .blend_factor_source_alpha =
675 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE,
676 .blend_factor_destination_color =
677 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
678 .blend_factor_destination_alpha =
679 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
680 .blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
681 .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
684 vdp_st = vdp->
685 output_surface_render_output_surface(output_surface,
686 &output_indexed_rect_vid,
687 osd_surface,
688 &output_indexed_rect_vid,
689 NULL, &blend_state,
690 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
691 CHECK_ST_WARNING("Error when calling "
692 "vdp_output_surface_render_output_surface");
695 static void draw_eosd(struct vo *vo)
697 struct vdpctx *vc = vo->priv;
698 struct vdp_functions *vdp = vc->vdp;
699 VdpStatus vdp_st;
700 VdpOutputSurface output_surface = vc->output_surfaces[vc->surface_num];
701 int i;
703 VdpOutputSurfaceRenderBlendState blend_state = {
704 .struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION,
705 .blend_factor_source_color =
706 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA,
707 .blend_factor_source_alpha =
708 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE,
709 .blend_factor_destination_color =
710 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
711 .blend_factor_destination_alpha =
712 VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA,
713 .blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
714 .blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD,
717 for (i = 0; i < vc->eosd_render_count; i++) {
718 vdp_st = vdp->
719 output_surface_render_bitmap_surface(output_surface,
720 &vc->eosd_targets[i].dest,
721 vc->eosd_surface.surface,
722 &vc->eosd_targets[i].source,
723 &vc->eosd_targets[i].color,
724 &blend_state,
725 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
726 CHECK_ST_WARNING("EOSD: Error when rendering");
730 #define HEIGHT_SORT_BITS 4
731 static int size_index(struct eosd_target *r)
733 unsigned int h = r->source.y1;
734 int n = av_log2_16bit(h);
735 return (n << HEIGHT_SORT_BITS)
736 + (- 1 - (h << HEIGHT_SORT_BITS >> n) & (1 << HEIGHT_SORT_BITS) - 1);
739 /* Pack the given rectangles into an area of size w * h.
740 * The size of each rectangle is read from .source.x1/.source.y1.
741 * The height of each rectangle must be at least 1 and less than 65536.
742 * The .source rectangle is then set corresponding to the packed position.
743 * 'scratch' must point to work memory for num_rects+16 ints.
744 * Return 0 on success, -1 if the rectangles did not fit in w*h.
746 * The rectangles are placed in rows in order approximately sorted by
747 * height (the approximate sorting is simpler than a full one would be,
748 * and allows the algorithm to work in linear time). Additionally, to
749 * reduce wasted space when there are a few tall rectangles, empty
750 * lower-right parts of rows are filled recursively when the size of
751 * rectangles in the row drops past a power-of-two threshold. So if a
752 * row starts with rectangles of size 3x50, 10x40 and 5x20 then the
753 * free rectangle with corners (13, 20)-(w, 50) is filled recursively.
755 static int pack_rectangles(struct eosd_target *rects, int num_rects,
756 int w, int h, int *scratch)
758 int bins[16 << HEIGHT_SORT_BITS];
759 int sizes[16 << HEIGHT_SORT_BITS] = {};
760 for (int i = 0; i < num_rects; i++)
761 sizes[size_index(rects + i)]++;
762 int idx = 0;
763 for (int i = 0; i < 16 << HEIGHT_SORT_BITS; i += 1 << HEIGHT_SORT_BITS) {
764 for (int j = 0; j < 1 << HEIGHT_SORT_BITS; j++) {
765 bins[i + j] = idx;
766 idx += sizes[i + j];
768 scratch[idx++] = -1;
770 for (int i = 0; i < num_rects; i++)
771 scratch[bins[size_index(rects + i)]++] = i;
772 for (int i = 0; i < 16; i++)
773 bins[i] = bins[i << HEIGHT_SORT_BITS] - sizes[i << HEIGHT_SORT_BITS];
774 struct {
775 int size, x, bottom;
776 } stack[16] = {{15, 0, h}}, s = {};
777 int stackpos = 1;
778 int y;
779 while (stackpos) {
780 y = s.bottom;
781 s = stack[--stackpos];
782 s.size++;
783 while (s.size--) {
784 int maxy = -1;
785 int obj;
786 while ((obj = scratch[bins[s.size]]) >= 0) {
787 int bottom = y + rects[obj].source.y1;
788 if (bottom > s.bottom)
789 break;
790 int right = s.x + rects[obj].source.x1;
791 if (right > w)
792 break;
793 bins[s.size]++;
794 rects[obj].source.x0 = s.x;
795 rects[obj].source.x1 += s.x;
796 rects[obj].source.y0 = y;
797 rects[obj].source.y1 += y;
798 num_rects--;
799 if (maxy <= 0)
800 stack[stackpos++] = s;
801 s.x = right;
802 maxy = FFMAX(maxy, bottom);
804 if (maxy > 0)
805 s.bottom = maxy;
808 return num_rects ? -1 : 0;
811 static void generate_eosd(struct vo *vo, mp_eosd_images_t *imgs)
813 struct vdpctx *vc = vo->priv;
814 struct vdp_functions *vdp = vc->vdp;
815 VdpStatus vdp_st;
816 int i;
817 ASS_Image *img = imgs->imgs;
818 ASS_Image *p;
819 struct eosd_bitmap_surface *sfc = &vc->eosd_surface;
820 bool need_upload = false;
822 if (imgs->changed == 0)
823 return; // Nothing changed, no need to redraw
825 vc->eosd_render_count = 0;
827 if (!img)
828 return; // There's nothing to render!
830 if (imgs->changed == 1)
831 goto eosd_skip_upload;
833 need_upload = true;
834 bool reallocate = false;
835 while (1) {
836 for (p = img, i = 0; p; p = p->next) {
837 if (p->w <= 0 || p->h <= 0)
838 continue;
839 // Allocate new space for surface/target arrays
840 if (i >= vc->eosd_targets_size) {
841 vc->eosd_targets_size = FFMAX(vc->eosd_targets_size * 2, 512);
842 vc->eosd_targets =
843 talloc_realloc_size(vc, vc->eosd_targets,
844 vc->eosd_targets_size
845 * sizeof(*vc->eosd_targets));
846 vc->eosd_scratch =
847 talloc_realloc_size(vc, vc->eosd_scratch,
848 (vc->eosd_targets_size + 16)
849 * sizeof(*vc->eosd_scratch));
851 vc->eosd_targets[i].source.x1 = p->w;
852 vc->eosd_targets[i].source.y1 = p->h;
853 i++;
855 if (pack_rectangles(vc->eosd_targets, i, sfc->w, sfc->h,
856 vc->eosd_scratch) >= 0)
857 break;
858 int w = FFMIN(FFMAX(sfc->w * 2, EOSD_SURFACE_INITIAL_SIZE),
859 sfc->max_width);
860 int h = FFMIN(FFMAX(sfc->h * 2, EOSD_SURFACE_INITIAL_SIZE),
861 sfc->max_height);
862 if (w == sfc->w && h == sfc->h) {
863 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] EOSD bitmaps do not fit on "
864 "a surface with the maximum supported size\n");
865 return;
866 } else {
867 sfc->w = w;
868 sfc->h = h;
870 reallocate = true;
872 if (reallocate) {
873 if (sfc->surface != VDP_INVALID_HANDLE)
874 vdp->bitmap_surface_destroy(sfc->surface);
875 mp_msg(MSGT_VO, MSGL_V, "[vdpau] Allocating a %dx%d surface for "
876 "EOSD bitmaps.\n", sfc->w, sfc->h);
877 vdp_st = vdp->bitmap_surface_create(vc->vdp_device, VDP_RGBA_FORMAT_A8,
878 sfc->w, sfc->h, true,
879 &sfc->surface);
880 if (vdp_st != VDP_STATUS_OK)
881 sfc->surface = VDP_INVALID_HANDLE;
882 CHECK_ST_WARNING("EOSD: error when creating surface");
885 eosd_skip_upload:
886 if (sfc->surface == VDP_INVALID_HANDLE)
887 return;
888 for (p = img; p; p = p->next) {
889 if (p->w <= 0 || p->h <= 0)
890 continue;
891 struct eosd_target *target = &vc->eosd_targets[vc->eosd_render_count];
892 if (need_upload) {
893 vdp_st = vdp->
894 bitmap_surface_put_bits_native(sfc->surface,
895 (const void *) &p->bitmap,
896 &p->stride, &target->source);
897 CHECK_ST_WARNING("EOSD: putbits failed");
899 // Render dest, color, etc.
900 target->color.alpha = 1.0 - ((p->color >> 0) & 0xff) / 255.0;
901 target->color.blue = ((p->color >> 8) & 0xff) / 255.0;
902 target->color.green = ((p->color >> 16) & 0xff) / 255.0;
903 target->color.red = ((p->color >> 24) & 0xff) / 255.0;
904 target->dest.x0 = p->dst_x;
905 target->dest.y0 = p->dst_y;
906 target->dest.x1 = p->w + p->dst_x;
907 target->dest.y1 = p->h + p->dst_y;
908 vc->eosd_render_count++;
912 static void draw_osd(struct vo *vo, struct osd_state *osd)
914 struct vdpctx *vc = vo->priv;
915 mp_msg(MSGT_VO, MSGL_DBG2, "DRAW_OSD\n");
917 osd_draw_text_ext(osd, vo->dwidth, vo->dheight, vc->border_x, vc->border_y,
918 vc->border_x, vc->border_y, vc->vid_width,
919 vc->vid_height, draw_osd_I8A8, vo);
922 static void flip_page(struct vo *vo)
924 struct vdpctx *vc = vo->priv;
925 struct vdp_functions *vdp = vc->vdp;
926 VdpStatus vdp_st;
928 mp_msg(MSGT_VO, MSGL_DBG2, "\nFLIP_PAGE VID:%u -> OUT:%u\n",
929 vc->surface_render[vc->vid_surface_num].surface,
930 vc->output_surfaces[vc->surface_num]);
932 vdp_st =
933 vdp->presentation_queue_display(vc->flip_queue,
934 vc->output_surfaces[vc->surface_num],
935 vo->dwidth, vo->dheight, 0);
936 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display");
938 vc->surface_num = (vc->surface_num + 1) % NUM_OUTPUT_SURFACES;
939 vc->visible_buf = true;
942 static int draw_slice(struct vo *vo, uint8_t *image[], int stride[], int w,
943 int h, int x, int y)
945 struct vdpctx *vc = vo->priv;
946 struct vdp_functions *vdp = vc->vdp;
947 VdpStatus vdp_st;
948 struct vdpau_render_state *rndr = (struct vdpau_render_state *)image[0];
949 int max_refs = vc->image_format == IMGFMT_VDPAU_H264 ?
950 rndr->info.h264.num_ref_frames : 2;
951 if (!IMGFMT_IS_VDPAU(vc->image_format))
952 return VO_FALSE;
953 if ((vc->decoder == VDP_INVALID_HANDLE || vc->decoder_max_refs < max_refs)
954 && !create_vdp_decoder(vo, max_refs))
955 return VO_FALSE;
957 vdp_st = vdp->decoder_render(vc->decoder, rndr->surface,
958 (void *)&rndr->info,
959 rndr->bitstream_buffers_used,
960 rndr->bitstream_buffers);
961 CHECK_ST_WARNING("Failed VDPAU decoder rendering");
962 return VO_TRUE;
966 static int draw_frame(struct vo *vo, uint8_t *src[])
968 return VO_ERROR;
971 static struct vdpau_render_state *get_surface(struct vo *vo, int number)
973 struct vdpctx *vc = vo->priv;
974 struct vdp_functions *vdp = vc->vdp;
976 if (number > MAX_VIDEO_SURFACES)
977 return NULL;
978 if (vc->surface_render[number].surface == VDP_INVALID_HANDLE) {
979 VdpStatus vdp_st;
980 vdp_st = vdp->video_surface_create(vc->vdp_device, vc->vdp_chroma_type,
981 vc->vid_width, vc->vid_height,
982 &vc->surface_render[number].surface);
983 CHECK_ST_WARNING("Error when calling vdp_video_surface_create");
984 if (vdp_st != VDP_STATUS_OK)
985 return NULL;
987 mp_msg(MSGT_VO, MSGL_DBG2, "VID CREATE: %u\n",
988 vc->surface_render[number].surface);
989 return &vc->surface_render[number];
992 static uint32_t draw_image(struct vo *vo, mp_image_t *mpi)
994 struct vdpctx *vc = vo->priv;
995 struct vdp_functions *vdp = vc->vdp;
997 if (IMGFMT_IS_VDPAU(vc->image_format)) {
998 struct vdpau_render_state *rndr = mpi->priv;
999 vc->vid_surface_num = rndr - vc->surface_render;
1000 if (vc->deint_buffer_past_frames) {
1001 mpi->usage_count++;
1002 if (vc->deint_mpi[1])
1003 vc->deint_mpi[1]->usage_count--;
1004 vc->deint_mpi[1] = vc->deint_mpi[0];
1005 vc->deint_mpi[0] = mpi;
1007 } else if (!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) {
1008 VdpStatus vdp_st;
1009 void *destdata[3] = {mpi->planes[0], mpi->planes[2], mpi->planes[1]};
1010 struct vdpau_render_state *rndr = get_surface(vo, vc->deint_counter);
1011 vc->deint_counter = (vc->deint_counter + 1) % 3;
1012 vc->vid_surface_num = rndr - vc->surface_render;
1013 if (vc->image_format == IMGFMT_NV12)
1014 destdata[1] = destdata[2];
1015 vdp_st =
1016 vdp->video_surface_put_bits_y_cb_cr(rndr->surface,
1017 vc->vdp_pixel_format,
1018 (const void *const*)destdata,
1019 mpi->stride); // pitch
1020 CHECK_ST_ERROR("Error when calling "
1021 "vdp_video_surface_put_bits_y_cb_cr");
1023 if (mpi->fields & MP_IMGFIELD_ORDERED)
1024 vc->top_field_first = !!(mpi->fields & MP_IMGFIELD_TOP_FIRST);
1025 else
1026 vc->top_field_first = 1;
1028 video_to_output_surface(vo);
1029 return VO_TRUE;
1032 static uint32_t get_image(struct vo *vo, mp_image_t *mpi)
1034 struct vdpctx *vc = vo->priv;
1035 struct vdpau_render_state *rndr;
1037 // no dr for non-decoding for now
1038 if (!IMGFMT_IS_VDPAU(vc->image_format))
1039 return VO_FALSE;
1040 if (mpi->type != MP_IMGTYPE_NUMBERED)
1041 return VO_FALSE;
1043 rndr = get_surface(vo, mpi->number);
1044 if (!rndr) {
1045 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] no surfaces available in "
1046 "get_image\n");
1047 // TODO: this probably breaks things forever, provide a dummy buffer?
1048 return VO_FALSE;
1050 mpi->flags |= MP_IMGFLAG_DIRECT;
1051 mpi->stride[0] = mpi->stride[1] = mpi->stride[2] = 0;
1052 mpi->planes[0] = mpi->planes[1] = mpi->planes[2] = NULL;
1053 // hack to get around a check and to avoid a special-case in vd_ffmpeg.c
1054 mpi->planes[0] = (void *)rndr;
1055 mpi->num_planes = 1;
1056 mpi->priv = rndr;
1057 return VO_TRUE;
1060 static int query_format(uint32_t format)
1062 int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW
1063 | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD
1064 | VFCAP_EOSD_UNSCALED;
1065 switch (format) {
1066 case IMGFMT_YV12:
1067 case IMGFMT_I420:
1068 case IMGFMT_IYUV:
1069 case IMGFMT_NV12:
1070 case IMGFMT_YUY2:
1071 case IMGFMT_UYVY:
1072 return default_flags | VOCAP_NOSLICES;
1073 case IMGFMT_VDPAU_MPEG1:
1074 case IMGFMT_VDPAU_MPEG2:
1075 case IMGFMT_VDPAU_H264:
1076 case IMGFMT_VDPAU_WMV3:
1077 case IMGFMT_VDPAU_VC1:
1078 return default_flags;
1080 return 0;
1083 static void destroy_vdpau_objects(struct vo *vo)
1085 struct vdpctx *vc = vo->priv;
1086 struct vdp_functions *vdp = vc->vdp;
1088 int i;
1089 VdpStatus vdp_st;
1091 free_video_specific(vo);
1093 if (vc->flip_queue != VDP_INVALID_HANDLE) {
1094 vdp_st = vdp->presentation_queue_destroy(vc->flip_queue);
1095 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy");
1098 if (vc->flip_target != VDP_INVALID_HANDLE) {
1099 vdp_st = vdp->presentation_queue_target_destroy(vc->flip_target);
1100 CHECK_ST_WARNING("Error when calling "
1101 "vdp_presentation_queue_target_destroy");
1104 for (i = 0; i <= NUM_OUTPUT_SURFACES; i++) {
1105 if (vc->output_surfaces[i] == VDP_INVALID_HANDLE)
1106 continue;
1107 vdp_st = vdp->output_surface_destroy(vc->output_surfaces[i]);
1108 CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy");
1111 if (vc->eosd_surface.surface != VDP_INVALID_HANDLE) {
1112 vdp_st = vdp->bitmap_surface_destroy(vc->eosd_surface.surface);
1113 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy");
1116 vdp_st = vdp->device_destroy(vc->vdp_device);
1117 CHECK_ST_WARNING("Error when calling vdp_device_destroy");
1120 static void uninit(struct vo *vo)
1122 struct vdpctx *vc = vo->priv;
1124 /* Destroy all vdpau objects */
1125 destroy_vdpau_objects(vo);
1127 #ifdef CONFIG_XF86VM
1128 if (vc->mode_switched)
1129 vo_vm_close(vo);
1130 #endif
1131 vo_x11_uninit(vo);
1133 dlclose(vc->vdpau_lib_handle);
1136 static const char help_msg[] =
1137 "\n-vo vdpau command line help:\n"
1138 "Example: mplayer -vo vdpau:deint=2\n"
1139 "\nOptions:\n"
1140 " deint (all modes > 0 respect -field-dominance)\n"
1141 " 0: no deinterlacing\n"
1142 " 1: only show first field\n"
1143 " 2: bob deinterlacing\n"
1144 " 3: temporal deinterlacing (resource-hungry)\n"
1145 " 4: temporal-spatial deinterlacing (very resource-hungry)\n"
1146 " chroma-deint\n"
1147 " Operate on luma and chroma when using temporal deinterlacing (default)\n"
1148 " Use nochroma-deint to speed up temporal deinterlacing\n"
1149 " pullup\n"
1150 " Try to apply inverse-telecine (needs temporal deinterlacing)\n"
1151 " denoise\n"
1152 " Apply denoising, argument is strength from 0.0 to 1.0\n"
1153 " sharpen\n"
1154 " Apply sharpening or softening, argument is strength from -1.0 to 1.0\n"
1157 static int preinit(struct vo *vo, const char *arg)
1159 int i;
1161 struct vdpctx *vc = talloc_zero(vo, struct vdpctx);
1162 vo->priv = vc;
1164 // Mark everything as invalid first so uninit() can tell what has been
1165 // allocated
1166 vc->decoder = VDP_INVALID_HANDLE;
1167 for (i = 0; i < MAX_VIDEO_SURFACES; i++)
1168 vc->surface_render[i].surface = VDP_INVALID_HANDLE;
1169 vc->video_mixer = VDP_INVALID_HANDLE;
1170 vc->flip_queue = VDP_INVALID_HANDLE;
1171 vc->flip_target = VDP_INVALID_HANDLE;
1172 for (i = 0; i <= NUM_OUTPUT_SURFACES; i++)
1173 vc->output_surfaces[i] = VDP_INVALID_HANDLE;
1174 vc->vdp_device = VDP_INVALID_HANDLE;
1175 vc->eosd_surface.surface = VDP_INVALID_HANDLE;
1177 vc->deint_type = 3;
1178 vc->chroma_deint = 1;
1179 const opt_t subopts[] = {
1180 {"deint", OPT_ARG_INT, &vc->deint, (opt_test_f)int_non_neg},
1181 {"chroma-deint", OPT_ARG_BOOL, &vc->chroma_deint, NULL},
1182 {"pullup", OPT_ARG_BOOL, &vc->pullup, NULL},
1183 {"denoise", OPT_ARG_FLOAT, &vc->denoise, NULL},
1184 {"sharpen", OPT_ARG_FLOAT, &vc->sharpen, NULL},
1185 {NULL}
1187 if (subopt_parse(arg, subopts) != 0) {
1188 mp_msg(MSGT_VO, MSGL_FATAL, help_msg);
1189 return -1;
1191 if (vc->deint)
1192 vc->deint_type = vc->deint;
1193 if (vc->deint > 1)
1194 vc->deint_buffer_past_frames = 1;
1196 char *vdpaulibrary = "libvdpau.so.1";
1197 char *vdpau_device_create = "vdp_device_create_x11";
1198 vc->vdpau_lib_handle = dlopen(vdpaulibrary, RTLD_LAZY);
1199 if (!vc->vdpau_lib_handle) {
1200 mp_msg(MSGT_VO, MSGL_ERR,
1201 "[vdpau] Could not open dynamic library %s\n", vdpaulibrary);
1202 return -1;
1204 vc->vdp_device_create = dlsym(vc->vdpau_lib_handle, vdpau_device_create);
1205 if (!vc->vdp_device_create) {
1206 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Could not find function %s in %s\n",
1207 vdpau_device_create, vdpaulibrary);
1208 dlclose(vc->vdpau_lib_handle);
1209 return -1;
1211 if (!vo_init(vo)) {
1212 dlclose(vc->vdpau_lib_handle);
1213 return -1;
1216 // After this calling uninit() should work to free resources
1218 if (win_x11_init_vdpau_procs(vo) < 0) {
1219 if (vc->vdp->device_destroy)
1220 vc->vdp->device_destroy(vc->vdp_device);
1221 vo_x11_uninit(vo);
1222 dlclose(vc->vdpau_lib_handle);
1223 return -1;
1226 vc->output_surface_width = vc->output_surface_height = -1;
1228 // full grayscale palette.
1229 for (i = 0; i < PALETTE_SIZE; ++i)
1230 vc->palette[i] = (i << 16) | (i << 8) | i;
1232 vc->procamp.struct_version = VDP_PROCAMP_VERSION;
1233 vc->procamp.brightness = 0.0;
1234 vc->procamp.contrast = 1.0;
1235 vc->procamp.saturation = 1.0;
1236 vc->procamp.hue = 0.0;
1238 return 0;
1241 static int get_equalizer(struct vo *vo, const char *name, int *value)
1243 struct vdpctx *vc = vo->priv;
1245 if (!strcasecmp(name, "brightness"))
1246 *value = vc->procamp.brightness * 100;
1247 else if (!strcasecmp(name, "contrast"))
1248 *value = (vc->procamp.contrast - 1.0) * 100;
1249 else if (!strcasecmp(name, "saturation"))
1250 *value = (vc->procamp.saturation - 1.0) * 100;
1251 else if (!strcasecmp(name, "hue"))
1252 *value = vc->procamp.hue * 100 / M_PI;
1253 else
1254 return VO_NOTIMPL;
1255 return VO_TRUE;
1258 static int set_equalizer(struct vo *vo, const char *name, int value)
1260 struct vdpctx *vc = vo->priv;
1261 struct vdp_functions *vdp = vc->vdp;
1262 VdpStatus vdp_st;
1263 VdpCSCMatrix matrix;
1264 static const VdpVideoMixerAttribute attributes[] =
1265 {VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX};
1266 const void *attribute_values[] = {&matrix};
1268 if (!strcasecmp(name, "brightness"))
1269 vc->procamp.brightness = value / 100.0;
1270 else if (!strcasecmp(name, "contrast"))
1271 vc->procamp.contrast = value / 100.0 + 1.0;
1272 else if (!strcasecmp(name, "saturation"))
1273 vc->procamp.saturation = value / 100.0 + 1.0;
1274 else if (!strcasecmp(name, "hue"))
1275 vc->procamp.hue = value / 100.0 * M_PI;
1276 else
1277 return VO_NOTIMPL;
1279 vdp_st = vdp->generate_csc_matrix(&vc->procamp,
1280 VDP_COLOR_STANDARD_ITUR_BT_601,
1281 &matrix);
1282 CHECK_ST_WARNING("Error when generating CSC matrix");
1283 vdp_st = vdp->video_mixer_set_attribute_values(vc->video_mixer, 1,
1284 attributes,
1285 attribute_values);
1286 CHECK_ST_WARNING("Error when setting CSC matrix");
1287 return VO_TRUE;
1290 static int control(struct vo *vo, uint32_t request, void *data)
1292 struct vdpctx *vc = vo->priv;
1293 struct vdp_functions *vdp = vc->vdp;
1295 switch (request) {
1296 case VOCTRL_GET_DEINTERLACE:
1297 *(int*)data = vc->deint;
1298 return VO_TRUE;
1299 case VOCTRL_SET_DEINTERLACE:
1300 vc->deint = *(int*)data;
1301 if (vc->deint)
1302 vc->deint = vc->deint_type;
1303 if (vc->deint_type > 2) {
1304 VdpStatus vdp_st;
1305 VdpVideoMixerFeature features[1] =
1306 {vc->deint_type == 3 ?
1307 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL :
1308 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL};
1309 VdpBool feature_enables[1] = {vc->deint ? VDP_TRUE : VDP_FALSE};
1310 vdp_st = vdp->video_mixer_set_feature_enables(vc->video_mixer,
1311 1, features,
1312 feature_enables);
1313 CHECK_ST_WARNING("Error changing deinterlacing settings");
1314 vc->deint_buffer_past_frames = 1;
1316 return VO_TRUE;
1317 case VOCTRL_PAUSE:
1318 return (vc->paused = true);
1319 case VOCTRL_RESUME:
1320 return (vc->paused = false);
1321 case VOCTRL_QUERY_FORMAT:
1322 return query_format(*(uint32_t *)data);
1323 case VOCTRL_GET_IMAGE:
1324 return get_image(vo, data);
1325 case VOCTRL_DRAW_IMAGE:
1326 return draw_image(vo, data);
1327 case VOCTRL_BORDER:
1328 vo_x11_border(vo);
1329 resize(vo);
1330 return VO_TRUE;
1331 case VOCTRL_FULLSCREEN:
1332 vo_x11_fullscreen(vo);
1333 resize(vo);
1334 return VO_TRUE;
1335 case VOCTRL_GET_PANSCAN:
1336 return VO_TRUE;
1337 case VOCTRL_SET_PANSCAN:
1338 resize(vo);
1339 return VO_TRUE;
1340 case VOCTRL_SET_EQUALIZER: {
1341 struct voctrl_set_equalizer_args *args = data;
1342 return set_equalizer(vo, args->name, args->value);
1344 case VOCTRL_GET_EQUALIZER:
1346 struct voctrl_get_equalizer_args *args = data;
1347 return get_equalizer(vo, args->name, args->valueptr);
1349 case VOCTRL_ONTOP:
1350 vo_x11_ontop(vo);
1351 return VO_TRUE;
1352 case VOCTRL_UPDATE_SCREENINFO:
1353 update_xinerama_info(vo);
1354 return VO_TRUE;
1355 case VOCTRL_DRAW_EOSD:
1356 if (!data)
1357 return VO_FALSE;
1358 generate_eosd(vo, data);
1359 draw_eosd(vo);
1360 return VO_TRUE;
1361 case VOCTRL_GET_EOSD_RES: {
1362 mp_eosd_res_t *r = data;
1363 r->mt = r->mb = r->ml = r->mr = 0;
1364 if (vo_fs) {
1365 r->w = vo->opts->vo_screenwidth;
1366 r->h = vo->opts->vo_screenheight;
1367 r->ml = r->mr = vc->border_x;
1368 r->mt = r->mb = vc->border_y;
1369 } else {
1370 r->w = vo->dwidth;
1371 r->h = vo->dheight;
1373 return VO_TRUE;
1376 return VO_NOTIMPL;
1379 const struct vo_driver video_out_vdpau = {
1380 .is_new = 1,
1381 .info = &(const struct vo_info_s){
1382 "VDPAU with X11",
1383 "vdpau",
1384 "Rajib Mahapatra <rmahapatra@nvidia.com> and others",
1387 .preinit = preinit,
1388 .config = config,
1389 .control = control,
1390 .draw_frame = draw_frame,
1391 .draw_slice = draw_slice,
1392 .draw_osd = draw_osd,
1393 .flip_page = flip_page,
1394 .check_events = check_events,
1395 .uninit = uninit,