Do not dynamically load libvdpau.so.1, but link at compile time.
[mplayer/glamo.git] / libvo / vo_vdpau.c
blob97242d9abfd72788858d48f61e7d45525b323554
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.
23 /**
24 * \defgroup VDPAU_Presentation VDPAU Presentation
25 * \ingroup Decoder
27 * Actual decoding and presentation are implemented here.
28 * All necessary frame information is collected through
29 * the "vdpau_render_state" structure after parsing all headers
30 * etc. in libavcodec for different codecs.
32 * @{
35 #include <stdio.h>
37 #include "config.h"
38 #include "mp_msg.h"
39 #include "video_out.h"
40 #include "video_out_internal.h"
41 #include "x11_common.h"
42 #include "aspect.h"
43 #include "sub.h"
44 #include "subopt-helper.h"
46 #include "libavcodec/vdpau.h"
48 #include "gui/interface.h"
50 #include "libavutil/common.h"
51 #include "libavutil/mathematics.h"
53 #include "libass/ass.h"
54 #include "libass/ass_mp.h"
56 static vo_info_t info = {
57 "VDPAU with X11",
58 "vdpau",
59 "Rajib Mahapatra <rmahapatra@nvidia.com> and others",
63 LIBVO_EXTERN(vdpau)
65 #define CHECK_ST_ERROR(message) \
66 if (vdp_st != VDP_STATUS_OK) { \
67 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] %s: %s\n", \
68 message, vdp_get_error_string(vdp_st)); \
69 return -1; \
72 #define CHECK_ST_WARNING(message) \
73 if (vdp_st != VDP_STATUS_OK) \
74 mp_msg(MSGT_VO, MSGL_WARN, "[vdpau] %s: %s\n", \
75 message, vdp_get_error_string(vdp_st));
77 /* number of video and output surfaces */
78 #define NUM_OUTPUT_SURFACES 2
79 #define MAX_VIDEO_SURFACES 50
81 /* number of palette entries */
82 #define PALETTE_SIZE 256
84 /* Initial maximum number of EOSD surfaces */
85 #define EOSD_SURFACES_INITIAL 512
88 * Global variable declaration - VDPAU specific
91 /* Declaration for all variables of win_x11_init_vdpau_procs() and
92 * win_x11_init_vdpau_flip_queue() functions
94 static VdpDevice vdp_device;
95 static VdpGetProcAddress *vdp_get_proc_address;
97 static VdpPresentationQueueTarget vdp_flip_target;
98 static VdpPresentationQueue vdp_flip_queue;
100 static VdpDeviceDestroy *vdp_device_destroy;
101 static VdpVideoSurfaceCreate *vdp_video_surface_create;
102 static VdpVideoSurfaceDestroy *vdp_video_surface_destroy;
104 static VdpGetErrorString *vdp_get_error_string;
106 /* May be used in software filtering/postprocessing options
107 * in MPlayer (./mplayer -vf ..) if we copy video_surface data to
108 * system memory.
110 static VdpVideoSurfacePutBitsYCbCr *vdp_video_surface_put_bits_y_cb_cr;
111 static VdpOutputSurfacePutBitsNative *vdp_output_surface_put_bits_native;
113 static VdpOutputSurfaceCreate *vdp_output_surface_create;
114 static VdpOutputSurfaceDestroy *vdp_output_surface_destroy;
116 /* VideoMixer puts video_surface data on displayable output_surface. */
117 static VdpVideoMixerCreate *vdp_video_mixer_create;
118 static VdpVideoMixerDestroy *vdp_video_mixer_destroy;
119 static VdpVideoMixerRender *vdp_video_mixer_render;
120 static VdpVideoMixerSetFeatureEnables *vdp_video_mixer_set_feature_enables;
121 static VdpVideoMixerSetAttributeValues *vdp_video_mixer_set_attribute_values;
123 static VdpPresentationQueueTargetDestroy *vdp_presentation_queue_target_destroy;
124 static VdpPresentationQueueCreate *vdp_presentation_queue_create;
125 static VdpPresentationQueueDestroy *vdp_presentation_queue_destroy;
126 static VdpPresentationQueueDisplay *vdp_presentation_queue_display;
127 static VdpPresentationQueueBlockUntilSurfaceIdle *vdp_presentation_queue_block_until_surface_idle;
128 static VdpPresentationQueueTargetCreateX11 *vdp_presentation_queue_target_create_x11;
130 static VdpOutputSurfaceRenderOutputSurface *vdp_output_surface_render_output_surface;
131 static VdpOutputSurfacePutBitsIndexed *vdp_output_surface_put_bits_indexed;
132 static VdpOutputSurfaceRenderBitmapSurface *vdp_output_surface_render_bitmap_surface;
134 static VdpBitmapSurfaceCreate *vdp_bitmap_surface_create;
135 static VdpBitmapSurfaceDestroy *vdp_bitmap_surface_destroy;
136 static VdpBitmapSurfacePutBitsNative *vdp_bitmap_surface_putbits_native;
138 static VdpDecoderCreate *vdp_decoder_create;
139 static VdpDecoderDestroy *vdp_decoder_destroy;
140 static VdpDecoderRender *vdp_decoder_render;
142 static VdpGenerateCSCMatrix *vdp_generate_csc_matrix;
143 static VdpPreemptionCallbackRegister *vdp_preemption_callback_register;
145 /* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */
146 #define osd_surface output_surfaces[NUM_OUTPUT_SURFACES]
147 static VdpOutputSurface output_surfaces[NUM_OUTPUT_SURFACES + 1];
148 static VdpVideoSurface deint_surfaces[3];
149 static mp_image_t *deint_mpi[2];
150 static int output_surface_width, output_surface_height;
152 static VdpVideoMixer video_mixer;
153 static int deint;
154 static int deint_type;
155 static int deint_counter;
156 static int deint_buffer_past_frames;
157 static int pullup;
158 static float denoise;
159 static float sharpen;
160 static int colorspace;
161 static int chroma_deint;
162 static int force_mixer;
163 static int top_field_first;
164 static int flip;
165 static int hqscaling;
167 static VdpDecoder decoder;
168 static int decoder_max_refs;
170 static VdpRect src_rect_vid;
171 static VdpRect out_rect_vid;
172 static int border_x, border_y;
174 static struct vdpau_render_state surface_render[MAX_VIDEO_SURFACES];
175 static int surface_num;
176 static int vid_surface_num;
177 static uint32_t vid_width, vid_height;
178 static uint32_t image_format;
179 static VdpChromaType vdp_chroma_type;
180 static VdpYCbCrFormat vdp_pixel_format;
182 static volatile int is_preempted;
184 /* draw_osd */
185 static unsigned char *index_data;
186 static int index_data_size;
187 static uint32_t palette[PALETTE_SIZE];
189 // EOSD
190 // Pool of surfaces
191 struct {
192 VdpBitmapSurface surface;
193 int w;
194 int h;
195 char in_use;
196 } *eosd_surfaces;
198 // List of surfaces to be rendered
199 struct {
200 VdpBitmapSurface surface;
201 VdpRect source;
202 VdpRect dest;
203 VdpColor color;
204 } *eosd_targets;
206 static int eosd_render_count;
207 static int eosd_surface_count;
209 // Video equalizer
210 static VdpProcamp procamp;
213 * X11 specific
215 static int visible_buf;
216 static int int_pause;
218 static void draw_eosd(void);
220 static void push_deint_surface(VdpVideoSurface surface)
222 deint_surfaces[2] = deint_surfaces[1];
223 deint_surfaces[1] = deint_surfaces[0];
224 deint_surfaces[0] = surface;
227 static void video_to_output_surface(void)
229 VdpTime dummy;
230 VdpStatus vdp_st;
231 int i;
232 if (vid_surface_num < 0)
233 return;
235 if (deint < 2 || deint_surfaces[0] == VDP_INVALID_HANDLE)
236 push_deint_surface(surface_render[vid_surface_num].surface);
238 for (i = 0; i <= !!(deint > 1); i++) {
239 int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME;
240 VdpOutputSurface output_surface;
241 if (i) {
242 draw_eosd();
243 draw_osd();
244 flip_page();
246 if (deint)
247 field = (top_field_first == i) ^ (deint > 1) ?
248 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD:
249 VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD;
250 output_surface = output_surfaces[surface_num];
251 vdp_st = vdp_presentation_queue_block_until_surface_idle(vdp_flip_queue,
252 output_surface,
253 &dummy);
254 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_block_until_surface_idle")
256 vdp_st = vdp_video_mixer_render(video_mixer, VDP_INVALID_HANDLE, 0,
257 field, 2, deint_surfaces + 1,
258 deint_surfaces[0],
259 1, &surface_render[vid_surface_num].surface,
260 &src_rect_vid,
261 output_surface,
262 NULL, &out_rect_vid, 0, NULL);
263 CHECK_ST_WARNING("Error when calling vdp_video_mixer_render")
264 push_deint_surface(surface_render[vid_surface_num].surface);
268 static void resize(void)
270 VdpStatus vdp_st;
271 int i;
272 struct vo_rect src_rect;
273 struct vo_rect dst_rect;
274 struct vo_rect borders;
275 calc_src_dst_rects(vid_width, vid_height, &src_rect, &dst_rect, &borders, NULL);
276 out_rect_vid.x0 = dst_rect.left;
277 out_rect_vid.x1 = dst_rect.right;
278 out_rect_vid.y0 = dst_rect.top;
279 out_rect_vid.y1 = dst_rect.bottom;
280 src_rect_vid.x0 = src_rect.left;
281 src_rect_vid.x1 = src_rect.right;
282 src_rect_vid.y0 = flip ? src_rect.bottom : src_rect.top;
283 src_rect_vid.y1 = flip ? src_rect.top : src_rect.bottom;
284 border_x = borders.left;
285 border_y = borders.top;
286 #ifdef CONFIG_FREETYPE
287 // adjust font size to display size
288 force_load_font = 1;
289 #endif
290 vo_osd_changed(OSDTYPE_OSD);
292 if (output_surface_width < vo_dwidth || output_surface_height < vo_dheight) {
293 if (output_surface_width < vo_dwidth) {
294 output_surface_width += output_surface_width >> 1;
295 output_surface_width = FFMAX(output_surface_width, vo_dwidth);
297 if (output_surface_height < vo_dheight) {
298 output_surface_height += output_surface_height >> 1;
299 output_surface_height = FFMAX(output_surface_height, vo_dheight);
301 // Creation of output_surfaces
302 for (i = 0; i <= NUM_OUTPUT_SURFACES; i++) {
303 if (output_surfaces[i] != VDP_INVALID_HANDLE)
304 vdp_output_surface_destroy(output_surfaces[i]);
305 vdp_st = vdp_output_surface_create(vdp_device, VDP_RGBA_FORMAT_B8G8R8A8,
306 output_surface_width, output_surface_height,
307 &output_surfaces[i]);
308 CHECK_ST_WARNING("Error when calling vdp_output_surface_create")
309 mp_msg(MSGT_VO, MSGL_DBG2, "OUT CREATE: %u\n", output_surfaces[i]);
312 if (image_format == IMGFMT_BGRA) {
313 vdp_st = vdp_output_surface_render_output_surface(output_surfaces[surface_num],
314 NULL, VDP_INVALID_HANDLE,
315 NULL, NULL, NULL,
316 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
317 CHECK_ST_WARNING("Error when calling vdp_output_surface_render_output_surface")
318 vdp_st = vdp_output_surface_render_output_surface(output_surfaces[1 - surface_num],
319 NULL, VDP_INVALID_HANDLE,
320 NULL, NULL, NULL,
321 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
322 CHECK_ST_WARNING("Error when calling vdp_output_surface_render_output_surface")
323 } else
324 video_to_output_surface();
325 if (visible_buf)
326 flip_page();
329 static void preemption_callback(VdpDevice device, void *context)
331 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Display preemption detected\n");
332 is_preempted = 1;
335 /* Initialize vdp_get_proc_address, called from preinit() */
336 static int win_x11_init_vdpau_procs(void)
338 VdpStatus vdp_st;
340 struct vdp_function {
341 const int id;
342 void *pointer;
345 const struct vdp_function *dsc;
347 static const struct vdp_function vdp_func[] = {
348 {VDP_FUNC_ID_GET_ERROR_STRING, &vdp_get_error_string},
349 {VDP_FUNC_ID_DEVICE_DESTROY, &vdp_device_destroy},
350 {VDP_FUNC_ID_VIDEO_SURFACE_CREATE, &vdp_video_surface_create},
351 {VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, &vdp_video_surface_destroy},
352 {VDP_FUNC_ID_VIDEO_SURFACE_PUT_BITS_Y_CB_CR,
353 &vdp_video_surface_put_bits_y_cb_cr},
354 {VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_NATIVE,
355 &vdp_output_surface_put_bits_native},
356 {VDP_FUNC_ID_OUTPUT_SURFACE_CREATE, &vdp_output_surface_create},
357 {VDP_FUNC_ID_OUTPUT_SURFACE_DESTROY, &vdp_output_surface_destroy},
358 {VDP_FUNC_ID_VIDEO_MIXER_CREATE, &vdp_video_mixer_create},
359 {VDP_FUNC_ID_VIDEO_MIXER_DESTROY, &vdp_video_mixer_destroy},
360 {VDP_FUNC_ID_VIDEO_MIXER_RENDER, &vdp_video_mixer_render},
361 {VDP_FUNC_ID_VIDEO_MIXER_SET_FEATURE_ENABLES,
362 &vdp_video_mixer_set_feature_enables},
363 {VDP_FUNC_ID_VIDEO_MIXER_SET_ATTRIBUTE_VALUES,
364 &vdp_video_mixer_set_attribute_values},
365 {VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_DESTROY,
366 &vdp_presentation_queue_target_destroy},
367 {VDP_FUNC_ID_PRESENTATION_QUEUE_CREATE, &vdp_presentation_queue_create},
368 {VDP_FUNC_ID_PRESENTATION_QUEUE_DESTROY,
369 &vdp_presentation_queue_destroy},
370 {VDP_FUNC_ID_PRESENTATION_QUEUE_DISPLAY,
371 &vdp_presentation_queue_display},
372 {VDP_FUNC_ID_PRESENTATION_QUEUE_BLOCK_UNTIL_SURFACE_IDLE,
373 &vdp_presentation_queue_block_until_surface_idle},
374 {VDP_FUNC_ID_PRESENTATION_QUEUE_TARGET_CREATE_X11,
375 &vdp_presentation_queue_target_create_x11},
376 {VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_OUTPUT_SURFACE,
377 &vdp_output_surface_render_output_surface},
378 {VDP_FUNC_ID_OUTPUT_SURFACE_PUT_BITS_INDEXED,
379 &vdp_output_surface_put_bits_indexed},
380 {VDP_FUNC_ID_DECODER_CREATE, &vdp_decoder_create},
381 {VDP_FUNC_ID_DECODER_RENDER, &vdp_decoder_render},
382 {VDP_FUNC_ID_DECODER_DESTROY, &vdp_decoder_destroy},
383 {VDP_FUNC_ID_BITMAP_SURFACE_CREATE, &vdp_bitmap_surface_create},
384 {VDP_FUNC_ID_BITMAP_SURFACE_DESTROY, &vdp_bitmap_surface_destroy},
385 {VDP_FUNC_ID_BITMAP_SURFACE_PUT_BITS_NATIVE,
386 &vdp_bitmap_surface_putbits_native},
387 {VDP_FUNC_ID_OUTPUT_SURFACE_RENDER_BITMAP_SURFACE,
388 &vdp_output_surface_render_bitmap_surface},
389 {VDP_FUNC_ID_GENERATE_CSC_MATRIX, &vdp_generate_csc_matrix},
390 {VDP_FUNC_ID_PREEMPTION_CALLBACK_REGISTER,
391 &vdp_preemption_callback_register},
392 {0, NULL}
395 vdp_st = vdp_device_create_x11(mDisplay, mScreen,
396 &vdp_device, &vdp_get_proc_address);
397 if (vdp_st != VDP_STATUS_OK) {
398 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling vdp_device_create_x11: %i\n", vdp_st);
399 return -1;
402 vdp_get_error_string = NULL;
403 for (dsc = vdp_func; dsc->pointer; dsc++) {
404 vdp_st = vdp_get_proc_address(vdp_device, dsc->id, dsc->pointer);
405 if (vdp_st != VDP_STATUS_OK) {
406 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Error when calling vdp_get_proc_address(function id %d): %s\n",
407 dsc->id, vdp_get_error_string ? vdp_get_error_string(vdp_st) : "?");
408 return -1;
411 vdp_st = vdp_preemption_callback_register(vdp_device,
412 preemption_callback, NULL);
413 CHECK_ST_ERROR("Error when calling vdp_preemption_callback_register")
415 return 0;
418 /* Initialize vdpau_flip_queue, called from config() */
419 static int win_x11_init_vdpau_flip_queue(void)
421 VdpStatus vdp_st;
423 vdp_st = vdp_presentation_queue_target_create_x11(vdp_device, vo_window,
424 &vdp_flip_target);
425 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_target_create_x11")
427 vdp_st = vdp_presentation_queue_create(vdp_device, vdp_flip_target,
428 &vdp_flip_queue);
429 CHECK_ST_ERROR("Error when calling vdp_presentation_queue_create")
431 return 0;
434 static int update_csc_matrix(void)
436 VdpStatus vdp_st;
437 VdpCSCMatrix matrix;
438 static const VdpVideoMixerAttribute attributes[] = {VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX};
439 const void *attribute_values[] = {&matrix};
440 static const VdpColorStandard vdp_colors[] = {0, VDP_COLOR_STANDARD_ITUR_BT_601, VDP_COLOR_STANDARD_ITUR_BT_709, VDP_COLOR_STANDARD_SMPTE_240M};
441 static const char * const vdp_names[] = {NULL, "BT.601", "BT.709", "SMPTE-240M"};
442 int csp = colorspace;
444 if (!csp)
445 csp = vid_width >= 1280 || vid_height > 576 ? 2 : 1;
447 mp_msg(MSGT_VO, MSGL_V, "[vdpau] Updating CSC matrix for %s\n",
448 vdp_names[csp]);
450 vdp_st = vdp_generate_csc_matrix(&procamp, vdp_colors[csp], &matrix);
451 CHECK_ST_WARNING("Error when generating CSC matrix")
453 vdp_st = vdp_video_mixer_set_attribute_values(video_mixer, 1, attributes,
454 attribute_values);
455 CHECK_ST_WARNING("Error when setting CSC matrix")
456 return VO_TRUE;
459 static int create_vdp_mixer(VdpChromaType vdp_chroma_type)
461 #define VDP_NUM_MIXER_PARAMETER 3
462 #define MAX_NUM_FEATURES 6
463 int i;
464 VdpStatus vdp_st;
465 int feature_count = 0;
466 VdpVideoMixerFeature features[MAX_NUM_FEATURES];
467 VdpBool feature_enables[MAX_NUM_FEATURES];
468 static const VdpVideoMixerAttribute denoise_attrib[] = {VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL};
469 const void * const denoise_value[] = {&denoise};
470 static const VdpVideoMixerAttribute sharpen_attrib[] = {VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL};
471 const void * const sharpen_value[] = {&sharpen};
472 static const VdpVideoMixerAttribute skip_chroma_attrib[] = {VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE};
473 const uint8_t skip_chroma_value = 1;
474 const void * const skip_chroma_value_ptr[] = {&skip_chroma_value};
475 static const VdpVideoMixerParameter parameters[VDP_NUM_MIXER_PARAMETER] = {
476 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH,
477 VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT,
478 VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
480 const void *const parameter_values[VDP_NUM_MIXER_PARAMETER] = {
481 &vid_width,
482 &vid_height,
483 &vdp_chroma_type
485 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL;
486 if (deint == 4)
487 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL;
488 if (pullup)
489 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE;
490 if (denoise)
491 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION;
492 if (sharpen)
493 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS;
494 if (hqscaling)
495 features[feature_count++] = VDP_VIDEO_MIXER_FEATURE_HIGH_QUALITY_SCALING_L1 + (hqscaling - 1);
497 vdp_st = vdp_video_mixer_create(vdp_device, feature_count, features,
498 VDP_NUM_MIXER_PARAMETER,
499 parameters, parameter_values,
500 &video_mixer);
501 CHECK_ST_ERROR("Error when calling vdp_video_mixer_create")
503 for (i = 0; i < feature_count; i++)
504 feature_enables[i] = VDP_TRUE;
505 if (deint < 3)
506 feature_enables[0] = VDP_FALSE;
507 if (feature_count)
508 vdp_video_mixer_set_feature_enables(video_mixer, feature_count, features, feature_enables);
509 if (denoise)
510 vdp_video_mixer_set_attribute_values(video_mixer, 1, denoise_attrib, denoise_value);
511 if (sharpen)
512 vdp_video_mixer_set_attribute_values(video_mixer, 1, sharpen_attrib, sharpen_value);
513 if (!chroma_deint)
514 vdp_video_mixer_set_attribute_values(video_mixer, 1, skip_chroma_attrib, skip_chroma_value_ptr);
516 update_csc_matrix();
517 return 0;
520 // Free everything specific to a certain video file
521 static void free_video_specific(void)
523 int i;
524 VdpStatus vdp_st;
526 if (decoder != VDP_INVALID_HANDLE)
527 vdp_decoder_destroy(decoder);
528 decoder = VDP_INVALID_HANDLE;
529 decoder_max_refs = -1;
531 for (i = 0; i < 3; i++)
532 deint_surfaces[i] = VDP_INVALID_HANDLE;
534 for (i = 0; i < 2; i++)
535 if (deint_mpi[i]) {
536 deint_mpi[i]->usage_count--;
537 deint_mpi[i] = NULL;
540 for (i = 0; i < MAX_VIDEO_SURFACES; i++) {
541 if (surface_render[i].surface != VDP_INVALID_HANDLE) {
542 vdp_st = vdp_video_surface_destroy(surface_render[i].surface);
543 CHECK_ST_WARNING("Error when calling vdp_video_surface_destroy")
545 surface_render[i].surface = VDP_INVALID_HANDLE;
548 if (video_mixer != VDP_INVALID_HANDLE) {
549 vdp_st = vdp_video_mixer_destroy(video_mixer);
550 CHECK_ST_WARNING("Error when calling vdp_video_mixer_destroy")
552 video_mixer = VDP_INVALID_HANDLE;
555 static int create_vdp_decoder(uint32_t format, uint32_t width, uint32_t height,
556 int max_refs)
558 VdpStatus vdp_st;
559 VdpDecoderProfile vdp_decoder_profile;
560 if (decoder != VDP_INVALID_HANDLE)
561 vdp_decoder_destroy(decoder);
562 switch (format) {
563 case IMGFMT_VDPAU_MPEG1:
564 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1;
565 break;
566 case IMGFMT_VDPAU_MPEG2:
567 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN;
568 break;
569 case IMGFMT_VDPAU_H264:
570 vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH;
571 mp_msg(MSGT_VO, MSGL_V, "[vdpau] Creating H264 hardware decoder for %d reference frames.\n", max_refs);
572 break;
573 case IMGFMT_VDPAU_WMV3:
574 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN;
575 break;
576 case IMGFMT_VDPAU_VC1:
577 vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED;
578 break;
579 case IMGFMT_VDPAU_MPEG4:
580 vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG4_PART2_ASP;
581 break;
582 default:
583 goto err_out;
585 vdp_st = vdp_decoder_create(vdp_device, vdp_decoder_profile,
586 width, height, max_refs, &decoder);
587 CHECK_ST_WARNING("Failed creating VDPAU decoder");
588 if (vdp_st != VDP_STATUS_OK) {
589 err_out:
590 decoder = VDP_INVALID_HANDLE;
591 decoder_max_refs = 0;
592 return 0;
594 decoder_max_refs = max_refs;
595 return 1;
598 static void mark_vdpau_objects_uninitialized(void)
600 int i;
602 decoder = VDP_INVALID_HANDLE;
603 for (i = 0; i < MAX_VIDEO_SURFACES; i++)
604 surface_render[i].surface = VDP_INVALID_HANDLE;
605 for (i = 0; i < 3; i++) {
606 deint_surfaces[i] = VDP_INVALID_HANDLE;
607 if (i < 2 && deint_mpi[i])
608 deint_mpi[i]->usage_count--;
609 deint_mpi[i] = NULL;
611 video_mixer = VDP_INVALID_HANDLE;
612 vdp_flip_queue = VDP_INVALID_HANDLE;
613 vdp_flip_target = VDP_INVALID_HANDLE;
614 for (i = 0; i <= NUM_OUTPUT_SURFACES; i++)
615 output_surfaces[i] = VDP_INVALID_HANDLE;
616 vdp_device = VDP_INVALID_HANDLE;
617 for (i = 0; i < eosd_surface_count; i++)
618 eosd_surfaces[i].surface = VDP_INVALID_HANDLE;
619 output_surface_width = output_surface_height = -1;
620 eosd_render_count = 0;
621 visible_buf = 0;
624 static int handle_preemption(void)
626 if (!is_preempted)
627 return 0;
628 is_preempted = 0;
629 mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] Attempting to recover from preemption.\n");
630 mark_vdpau_objects_uninitialized();
631 if (win_x11_init_vdpau_procs() < 0 ||
632 win_x11_init_vdpau_flip_queue() < 0 ||
633 create_vdp_mixer(vdp_chroma_type) < 0) {
634 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] Recovering from preemption failed\n");
635 is_preempted = 1;
636 return -1;
638 resize();
639 mp_msg(MSGT_VO, MSGL_INFO, "[vdpau] Recovered from display preemption.\n");
640 return 1;
644 * connect to X server, create and map window, initialize all
645 * VDPAU objects, create different surfaces etc.
647 static int config(uint32_t width, uint32_t height, uint32_t d_width,
648 uint32_t d_height, uint32_t flags, char *title,
649 uint32_t format)
651 XVisualInfo vinfo;
652 XSetWindowAttributes xswa;
653 XWindowAttributes attribs;
654 unsigned long xswamask;
655 int depth;
657 #ifdef CONFIG_XF86VM
658 int vm = flags & VOFLAG_MODESWITCHING;
659 #endif
660 flip = flags & VOFLAG_FLIPPING;
662 image_format = format;
663 vid_width = width;
664 vid_height = height;
665 free_video_specific();
666 if (IMGFMT_IS_VDPAU(image_format)
667 && !create_vdp_decoder(image_format, vid_width, vid_height, 2))
668 return -1;
670 int_pause = 0;
671 visible_buf = 0;
673 #ifdef CONFIG_GUI
674 if (use_gui)
675 guiGetEvent(guiSetShVideo, 0); // the GUI will set up / resize our window
676 else
677 #endif
679 #ifdef CONFIG_XF86VM
680 if (vm)
681 vo_vm_switch();
682 else
683 #endif
684 XGetWindowAttributes(mDisplay, DefaultRootWindow(mDisplay), &attribs);
685 depth = attribs.depth;
686 if (depth != 15 && depth != 16 && depth != 24 && depth != 32)
687 depth = 24;
688 XMatchVisualInfo(mDisplay, mScreen, depth, TrueColor, &vinfo);
690 xswa.background_pixel = 0;
691 xswa.border_pixel = 0;
692 /* Do not use CWBackPixel: It leads to VDPAU errors after
693 aspect ratio changes. */
694 xswamask = CWBorderPixel;
696 vo_x11_create_vo_window(&vinfo, vo_dx, vo_dy, d_width, d_height,
697 flags, CopyFromParent, "vdpau", title);
698 XChangeWindowAttributes(mDisplay, vo_window, xswamask, &xswa);
700 #ifdef CONFIG_XF86VM
701 if (vm) {
702 /* Grab the mouse pointer in our window */
703 if (vo_grabpointer)
704 XGrabPointer(mDisplay, vo_window, True, 0,
705 GrabModeAsync, GrabModeAsync,
706 vo_window, None, CurrentTime);
707 XSetInputFocus(mDisplay, vo_window, RevertToNone, CurrentTime);
709 #endif
712 if ((flags & VOFLAG_FULLSCREEN) && WinID <= 0)
713 vo_fs = 1;
715 /* -----VDPAU related code here -------- */
716 if (vdp_flip_queue == VDP_INVALID_HANDLE && win_x11_init_vdpau_flip_queue())
717 return -1;
719 vdp_chroma_type = VDP_CHROMA_TYPE_420;
720 switch (image_format) {
721 case IMGFMT_YV12:
722 case IMGFMT_I420:
723 case IMGFMT_IYUV:
724 vdp_pixel_format = VDP_YCBCR_FORMAT_YV12;
725 break;
726 case IMGFMT_NV12:
727 vdp_pixel_format = VDP_YCBCR_FORMAT_NV12;
728 break;
729 case IMGFMT_YUY2:
730 vdp_pixel_format = VDP_YCBCR_FORMAT_YUYV;
731 vdp_chroma_type = VDP_CHROMA_TYPE_422;
732 break;
733 case IMGFMT_UYVY:
734 vdp_pixel_format = VDP_YCBCR_FORMAT_UYVY;
735 vdp_chroma_type = VDP_CHROMA_TYPE_422;
737 if (create_vdp_mixer(vdp_chroma_type))
738 return -1;
740 surface_num = 0;
741 vid_surface_num = -1;
742 resize();
744 return 0;
747 static void check_events(void)
749 int e = vo_x11_check_events(mDisplay);
751 if (handle_preemption() < 0)
752 return;
754 if (e & VO_EVENT_RESIZE)
755 resize();
757 if ((e & VO_EVENT_EXPOSE || e & VO_EVENT_RESIZE) && int_pause) {
758 /* did we already draw a buffer */
759 if (visible_buf) {
760 /* redraw the last visible buffer */
761 VdpStatus vdp_st;
762 vdp_st = vdp_presentation_queue_display(vdp_flip_queue,
763 output_surfaces[surface_num],
764 vo_dwidth, vo_dheight,
766 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
771 static void draw_osd_I8A8(int x0,int y0, int w,int h, unsigned char *src,
772 unsigned char *srca, int stride)
774 VdpOutputSurface output_surface = output_surfaces[surface_num];
775 VdpStatus vdp_st;
776 int i, j;
777 int pitch;
778 int index_data_size_required;
779 VdpRect output_indexed_rect_vid;
780 VdpOutputSurfaceRenderBlendState blend_state;
782 if (!w || !h)
783 return;
785 index_data_size_required = 2*w*h;
786 if (index_data_size < index_data_size_required) {
787 index_data = realloc(index_data, index_data_size_required);
788 index_data_size = index_data_size_required;
791 // index_data creation, component order - I, A, I, A, .....
792 for (i = 0; i < h; i++)
793 for (j = 0; j < w; j++) {
794 index_data[i*2*w + j*2] = src [i*stride + j];
795 index_data[i*2*w + j*2 + 1] = -srca[i*stride + j];
798 output_indexed_rect_vid.x0 = x0;
799 output_indexed_rect_vid.y0 = y0;
800 output_indexed_rect_vid.x1 = x0 + w;
801 output_indexed_rect_vid.y1 = y0 + h;
803 pitch = w*2;
805 // write source_data to osd_surface.
806 vdp_st = vdp_output_surface_put_bits_indexed(osd_surface,
807 VDP_INDEXED_FORMAT_I8A8,
808 (const void *const*)&index_data,
809 &pitch,
810 &output_indexed_rect_vid,
811 VDP_COLOR_TABLE_FORMAT_B8G8R8X8,
812 (void *)palette);
813 CHECK_ST_WARNING("Error when calling vdp_output_surface_put_bits_indexed")
815 blend_state.struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION;
816 blend_state.blend_factor_source_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE;
817 blend_state.blend_factor_source_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE;
818 blend_state.blend_factor_destination_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
819 blend_state.blend_factor_destination_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
820 blend_state.blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD;
821 blend_state.blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD;
823 vdp_st = vdp_output_surface_render_output_surface(output_surface,
824 &output_indexed_rect_vid,
825 osd_surface,
826 &output_indexed_rect_vid,
827 NULL,
828 &blend_state,
829 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
830 CHECK_ST_WARNING("Error when calling vdp_output_surface_render_output_surface")
833 static void draw_eosd(void)
835 VdpStatus vdp_st;
836 VdpOutputSurface output_surface = output_surfaces[surface_num];
837 VdpOutputSurfaceRenderBlendState blend_state;
838 int i;
840 blend_state.struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION;
841 blend_state.blend_factor_source_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA;
842 blend_state.blend_factor_source_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE;
843 blend_state.blend_factor_destination_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
844 blend_state.blend_factor_destination_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA;
845 blend_state.blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD;
846 blend_state.blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD;
848 for (i = 0; i < eosd_render_count; i++) {
849 vdp_st = vdp_output_surface_render_bitmap_surface(
850 output_surface, &eosd_targets[i].dest,
851 eosd_targets[i].surface, &eosd_targets[i].source,
852 &eosd_targets[i].color, &blend_state,
853 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
854 CHECK_ST_WARNING("EOSD: Error when rendering")
858 static void generate_eosd(mp_eosd_images_t *imgs)
860 VdpStatus vdp_st;
861 VdpRect destRect;
862 int j, found;
863 ass_image_t *img = imgs->imgs;
864 ass_image_t *i;
866 // Nothing changed, no need to redraw
867 if (imgs->changed == 0)
868 return;
869 eosd_render_count = 0;
870 // There's nothing to render!
871 if (!img)
872 return;
874 if (imgs->changed == 1)
875 goto eosd_skip_upload;
877 for (j = 0; j < eosd_surface_count; j++)
878 eosd_surfaces[j].in_use = 0;
880 for (i = img; i; i = i->next) {
881 // Try to reuse a suitable surface
882 found = -1;
883 for (j = 0; j < eosd_surface_count; j++) {
884 if (eosd_surfaces[j].surface != VDP_INVALID_HANDLE && !eosd_surfaces[j].in_use &&
885 eosd_surfaces[j].w >= i->w && eosd_surfaces[j].h >= i->h) {
886 found = j;
887 break;
890 // None found, allocate a new surface
891 if (found < 0) {
892 for (j = 0; j < eosd_surface_count; j++) {
893 if (!eosd_surfaces[j].in_use) {
894 if (eosd_surfaces[j].surface != VDP_INVALID_HANDLE)
895 vdp_bitmap_surface_destroy(eosd_surfaces[j].surface);
896 found = j;
897 break;
900 // Allocate new space for surface/target arrays
901 if (found < 0) {
902 j = found = eosd_surface_count;
903 eosd_surface_count = eosd_surface_count ? eosd_surface_count*2 : EOSD_SURFACES_INITIAL;
904 eosd_surfaces = realloc(eosd_surfaces, eosd_surface_count * sizeof(*eosd_surfaces));
905 eosd_targets = realloc(eosd_targets, eosd_surface_count * sizeof(*eosd_targets));
906 for (j = found; j < eosd_surface_count; j++) {
907 eosd_surfaces[j].surface = VDP_INVALID_HANDLE;
908 eosd_surfaces[j].in_use = 0;
911 vdp_st = vdp_bitmap_surface_create(vdp_device, VDP_RGBA_FORMAT_A8,
912 i->w, i->h, VDP_TRUE, &eosd_surfaces[found].surface);
913 CHECK_ST_WARNING("EOSD: error when creating surface")
914 eosd_surfaces[found].w = i->w;
915 eosd_surfaces[found].h = i->h;
917 eosd_surfaces[found].in_use = 1;
918 eosd_targets[eosd_render_count].surface = eosd_surfaces[found].surface;
919 destRect.x0 = 0;
920 destRect.y0 = 0;
921 destRect.x1 = i->w;
922 destRect.y1 = i->h;
923 vdp_st = vdp_bitmap_surface_putbits_native(eosd_targets[eosd_render_count].surface,
924 (const void *) &i->bitmap, &i->stride, &destRect);
925 CHECK_ST_WARNING("EOSD: putbits failed")
926 eosd_render_count++;
929 eosd_skip_upload:
930 eosd_render_count = 0;
931 for (i = img; i; i = i->next) {
932 // Render dest, color, etc.
933 eosd_targets[eosd_render_count].color.alpha = 1.0 - ((i->color >> 0) & 0xff) / 255.0;
934 eosd_targets[eosd_render_count].color.blue = ((i->color >> 8) & 0xff) / 255.0;
935 eosd_targets[eosd_render_count].color.green = ((i->color >> 16) & 0xff) / 255.0;
936 eosd_targets[eosd_render_count].color.red = ((i->color >> 24) & 0xff) / 255.0;
937 eosd_targets[eosd_render_count].dest.x0 = i->dst_x;
938 eosd_targets[eosd_render_count].dest.y0 = i->dst_y;
939 eosd_targets[eosd_render_count].dest.x1 = i->w + i->dst_x;
940 eosd_targets[eosd_render_count].dest.y1 = i->h + i->dst_y;
941 eosd_targets[eosd_render_count].source.x0 = 0;
942 eosd_targets[eosd_render_count].source.y0 = 0;
943 eosd_targets[eosd_render_count].source.x1 = i->w;
944 eosd_targets[eosd_render_count].source.y1 = i->h;
945 eosd_render_count++;
949 static void draw_osd(void)
951 mp_msg(MSGT_VO, MSGL_DBG2, "DRAW_OSD\n");
953 if (handle_preemption() < 0)
954 return;
956 vo_draw_text_ext(vo_dwidth, vo_dheight, border_x, border_y, border_x, border_y,
957 vid_width, vid_height, draw_osd_I8A8);
960 static void flip_page(void)
962 VdpStatus vdp_st;
963 mp_msg(MSGT_VO, MSGL_DBG2, "\nFLIP_PAGE VID:%u -> OUT:%u\n",
964 surface_render[vid_surface_num].surface, output_surfaces[surface_num]);
966 if (handle_preemption() < 0)
967 return;
969 vdp_st = vdp_presentation_queue_display(vdp_flip_queue, output_surfaces[surface_num],
970 vo_dwidth, vo_dheight,
972 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_display")
974 surface_num = (surface_num + 1) % NUM_OUTPUT_SURFACES;
975 visible_buf = 1;
978 static int draw_slice(uint8_t *image[], int stride[], int w, int h,
979 int x, int y)
981 VdpStatus vdp_st;
982 struct vdpau_render_state *rndr = (struct vdpau_render_state *)image[0];
983 int max_refs = image_format == IMGFMT_VDPAU_H264 ? rndr->info.h264.num_ref_frames : 2;
985 if (handle_preemption() < 0)
986 return VO_TRUE;
988 if (!IMGFMT_IS_VDPAU(image_format))
989 return VO_FALSE;
990 if ((decoder == VDP_INVALID_HANDLE || decoder_max_refs < max_refs)
991 && !create_vdp_decoder(image_format, vid_width, vid_height, max_refs))
992 return VO_FALSE;
994 vdp_st = vdp_decoder_render(decoder, rndr->surface, (void *)&rndr->info, rndr->bitstream_buffers_used, rndr->bitstream_buffers);
995 CHECK_ST_WARNING("Failed VDPAU decoder rendering");
996 return VO_TRUE;
1000 static int draw_frame(uint8_t *src[])
1002 return VO_ERROR;
1005 static struct vdpau_render_state *get_surface(int number)
1007 if (number > MAX_VIDEO_SURFACES)
1008 return NULL;
1009 if (surface_render[number].surface == VDP_INVALID_HANDLE) {
1010 VdpStatus vdp_st;
1011 vdp_st = vdp_video_surface_create(vdp_device, vdp_chroma_type,
1012 vid_width, vid_height,
1013 &surface_render[number].surface);
1014 CHECK_ST_WARNING("Error when calling vdp_video_surface_create")
1015 if (vdp_st != VDP_STATUS_OK)
1016 return NULL;
1018 mp_msg(MSGT_VO, MSGL_DBG2, "VID CREATE: %u\n", surface_render[number].surface);
1019 return &surface_render[number];
1022 static uint32_t draw_image(mp_image_t *mpi)
1024 if (IMGFMT_IS_VDPAU(image_format)) {
1025 struct vdpau_render_state *rndr = mpi->priv;
1026 vid_surface_num = rndr - surface_render;
1027 if (deint_buffer_past_frames) {
1028 mpi->usage_count++;
1029 if (deint_mpi[1])
1030 deint_mpi[1]->usage_count--;
1031 deint_mpi[1] = deint_mpi[0];
1032 deint_mpi[0] = mpi;
1034 } else if (image_format == IMGFMT_BGRA) {
1035 VdpStatus vdp_st;
1036 VdpRect r = {0, 0, vid_width, vid_height};
1037 vdp_st = vdp_output_surface_put_bits_native(output_surfaces[2],
1038 (void const*const*)mpi->planes,
1039 mpi->stride, &r);
1040 CHECK_ST_ERROR("Error when calling vdp_output_surface_put_bits_native")
1041 vdp_st = vdp_output_surface_render_output_surface(output_surfaces[surface_num],
1042 &out_rect_vid,
1043 output_surfaces[2],
1044 &src_rect_vid, NULL, NULL,
1045 VDP_OUTPUT_SURFACE_RENDER_ROTATE_0);
1046 CHECK_ST_ERROR("Error when calling vdp_output_surface_render_output_surface")
1047 } else if (!(mpi->flags & MP_IMGFLAG_DRAW_CALLBACK)) {
1048 VdpStatus vdp_st;
1049 void *destdata[3] = {mpi->planes[0], mpi->planes[2], mpi->planes[1]};
1050 struct vdpau_render_state *rndr = get_surface(deint_counter);
1051 deint_counter = (deint_counter + 1) % 3;
1052 vid_surface_num = rndr - surface_render;
1053 if (image_format == IMGFMT_NV12)
1054 destdata[1] = destdata[2];
1055 vdp_st = vdp_video_surface_put_bits_y_cb_cr(rndr->surface,
1056 vdp_pixel_format,
1057 (const void *const*)destdata,
1058 mpi->stride); // pitch
1059 CHECK_ST_ERROR("Error when calling vdp_video_surface_put_bits_y_cb_cr")
1061 if (mpi->fields & MP_IMGFIELD_ORDERED)
1062 top_field_first = !!(mpi->fields & MP_IMGFIELD_TOP_FIRST);
1063 else
1064 top_field_first = 1;
1066 video_to_output_surface();
1067 return VO_TRUE;
1070 static uint32_t get_image(mp_image_t *mpi)
1072 struct vdpau_render_state *rndr;
1074 // no dr for non-decoding for now
1075 if (!IMGFMT_IS_VDPAU(image_format))
1076 return VO_FALSE;
1077 if (mpi->type != MP_IMGTYPE_NUMBERED)
1078 return VO_FALSE;
1080 rndr = get_surface(mpi->number);
1081 if (!rndr) {
1082 mp_msg(MSGT_VO, MSGL_ERR, "[vdpau] no surfaces available in get_image\n");
1083 // TODO: this probably breaks things forever, provide a dummy buffer?
1084 return VO_FALSE;
1086 mpi->flags |= MP_IMGFLAG_DIRECT;
1087 mpi->stride[0] = mpi->stride[1] = mpi->stride[2] = 0;
1088 mpi->planes[0] = mpi->planes[1] = mpi->planes[2] = NULL;
1089 // hack to get around a check and to avoid a special-case in vd_ffmpeg.c
1090 mpi->planes[0] = (void *)rndr;
1091 mpi->num_planes = 1;
1092 mpi->priv = rndr;
1093 return VO_TRUE;
1096 static int query_format(uint32_t format)
1098 int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED | VFCAP_FLIP;
1099 switch (format) {
1100 case IMGFMT_BGRA:
1101 if (force_mixer)
1102 return 0;
1103 case IMGFMT_YV12:
1104 case IMGFMT_I420:
1105 case IMGFMT_IYUV:
1106 case IMGFMT_NV12:
1107 case IMGFMT_YUY2:
1108 case IMGFMT_UYVY:
1109 return default_flags | VOCAP_NOSLICES;
1110 case IMGFMT_VDPAU_MPEG1:
1111 case IMGFMT_VDPAU_MPEG2:
1112 case IMGFMT_VDPAU_H264:
1113 case IMGFMT_VDPAU_WMV3:
1114 case IMGFMT_VDPAU_VC1:
1115 case IMGFMT_VDPAU_MPEG4:
1116 if (create_vdp_decoder(format, 48, 48, 2))
1117 return default_flags;
1119 return 0;
1122 static void DestroyVdpauObjects(void)
1124 int i;
1125 VdpStatus vdp_st;
1127 free_video_specific();
1129 vdp_st = vdp_presentation_queue_destroy(vdp_flip_queue);
1130 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_destroy")
1132 vdp_st = vdp_presentation_queue_target_destroy(vdp_flip_target);
1133 CHECK_ST_WARNING("Error when calling vdp_presentation_queue_target_destroy")
1135 for (i = 0; i <= NUM_OUTPUT_SURFACES; i++) {
1136 vdp_st = vdp_output_surface_destroy(output_surfaces[i]);
1137 output_surfaces[i] = VDP_INVALID_HANDLE;
1138 CHECK_ST_WARNING("Error when calling vdp_output_surface_destroy")
1141 for (i = 0; i<eosd_surface_count; i++) {
1142 if (eosd_surfaces[i].surface != VDP_INVALID_HANDLE) {
1143 vdp_st = vdp_bitmap_surface_destroy(eosd_surfaces[i].surface);
1144 CHECK_ST_WARNING("Error when calling vdp_bitmap_surface_destroy")
1146 eosd_surfaces[i].surface = VDP_INVALID_HANDLE;
1149 vdp_st = vdp_device_destroy(vdp_device);
1150 CHECK_ST_WARNING("Error when calling vdp_device_destroy")
1153 static void uninit(void)
1155 int i;
1157 if (!vo_config_count)
1158 return;
1159 visible_buf = 0;
1161 for (i = 0; i < MAX_VIDEO_SURFACES; i++) {
1162 // Allocated in ff_vdpau_add_data_chunk()
1163 av_freep(&surface_render[i].bitstream_buffers);
1164 surface_render[i].bitstream_buffers_allocated = 0;
1167 /* Destroy all vdpau objects */
1168 DestroyVdpauObjects();
1170 free(index_data);
1171 index_data = NULL;
1173 free(eosd_surfaces);
1174 eosd_surfaces = NULL;
1175 free(eosd_targets);
1176 eosd_targets = NULL;
1178 #ifdef CONFIG_XF86VM
1179 vo_vm_close();
1180 #endif
1181 vo_x11_uninit();
1184 static const opt_t subopts[] = {
1185 {"deint", OPT_ARG_INT, &deint, (opt_test_f)int_non_neg},
1186 {"chroma-deint", OPT_ARG_BOOL, &chroma_deint, NULL},
1187 {"pullup", OPT_ARG_BOOL, &pullup, NULL},
1188 {"denoise", OPT_ARG_FLOAT, &denoise, NULL},
1189 {"sharpen", OPT_ARG_FLOAT, &sharpen, NULL},
1190 {"colorspace", OPT_ARG_INT, &colorspace, NULL},
1191 {"force-mixer", OPT_ARG_BOOL, &force_mixer, NULL},
1192 {"hqscaling", OPT_ARG_INT, &hqscaling, (opt_test_f)int_non_neg},
1193 {NULL}
1196 static const char help_msg[] =
1197 "\n-vo vdpau command line help:\n"
1198 "Example: mplayer -vo vdpau:deint=2\n"
1199 "\nOptions:\n"
1200 " deint (all modes > 0 respect -field-dominance)\n"
1201 " 0: no deinterlacing\n"
1202 " 1: only show first field\n"
1203 " 2: bob deinterlacing\n"
1204 " 3: temporal deinterlacing (resource-hungry)\n"
1205 " 4: temporal-spatial deinterlacing (very resource-hungry)\n"
1206 " chroma-deint\n"
1207 " Operate on luma and chroma when using temporal deinterlacing (default)\n"
1208 " Use nochroma-deint to speed up temporal deinterlacing\n"
1209 " pullup\n"
1210 " Try to apply inverse-telecine (needs temporal deinterlacing)\n"
1211 " denoise\n"
1212 " Apply denoising, argument is strength from 0.0 to 1.0\n"
1213 " sharpen\n"
1214 " Apply sharpening or softening, argument is strength from -1.0 to 1.0\n"
1215 " colorspace\n"
1216 " 0: guess based on video resolution\n"
1217 " 1: ITU-R BT.601 (default)\n"
1218 " 2: ITU-R BT.709\n"
1219 " 3: SMPTE-240M\n"
1220 " hqscaling\n"
1221 " 0: default VDPAU scaler\n"
1222 " 1-9: high quality VDPAU scaler (needs capable hardware)\n"
1223 " force-mixer\n"
1224 " Use the VDPAU mixer (default)\n"
1225 " Use noforce-mixer to allow BGRA output (disables all above options)\n"
1228 static int preinit(const char *arg)
1230 int i;
1232 deint = 0;
1233 deint_type = 3;
1234 deint_counter = 0;
1235 deint_buffer_past_frames = 0;
1236 deint_mpi[0] = deint_mpi[1] = NULL;
1237 chroma_deint = 1;
1238 pullup = 0;
1239 denoise = 0;
1240 sharpen = 0;
1241 colorspace = 1;
1242 force_mixer = 1;
1243 hqscaling = 0;
1244 if (subopt_parse(arg, subopts) != 0) {
1245 mp_msg(MSGT_VO, MSGL_FATAL, help_msg);
1246 return -1;
1248 if (deint)
1249 deint_type = deint;
1250 if (deint > 1)
1251 deint_buffer_past_frames = 1;
1252 if (colorspace < 0 || colorspace > 3) {
1253 mp_msg(MSGT_VO, MSGL_WARN, "[vdpau] Invalid color space specified, "
1254 "using BT.601\n");
1255 colorspace = 1;
1258 if (!vo_init() || win_x11_init_vdpau_procs())
1259 return -1;
1261 decoder = VDP_INVALID_HANDLE;
1262 for (i = 0; i < MAX_VIDEO_SURFACES; i++)
1263 surface_render[i].surface = VDP_INVALID_HANDLE;
1264 video_mixer = VDP_INVALID_HANDLE;
1265 for (i = 0; i <= NUM_OUTPUT_SURFACES; i++)
1266 output_surfaces[i] = VDP_INVALID_HANDLE;
1267 vdp_flip_queue = VDP_INVALID_HANDLE;
1268 output_surface_width = output_surface_height = -1;
1270 // full grayscale palette.
1271 for (i = 0; i < PALETTE_SIZE; ++i)
1272 palette[i] = (i << 16) | (i << 8) | i;
1273 index_data = NULL;
1274 index_data_size = 0;
1276 eosd_surface_count = eosd_render_count = 0;
1277 eosd_surfaces = NULL;
1278 eosd_targets = NULL;
1280 procamp.struct_version = VDP_PROCAMP_VERSION;
1281 procamp.brightness = 0.0;
1282 procamp.contrast = 1.0;
1283 procamp.saturation = 1.0;
1284 procamp.hue = 0.0;
1286 return 0;
1289 static int get_equalizer(char *name, int *value)
1291 if (!strcasecmp(name, "brightness"))
1292 *value = procamp.brightness * 100;
1293 else if (!strcasecmp(name, "contrast"))
1294 *value = (procamp.contrast-1.0) * 100;
1295 else if (!strcasecmp(name, "saturation"))
1296 *value = (procamp.saturation-1.0) * 100;
1297 else if (!strcasecmp(name, "hue"))
1298 *value = procamp.hue * 100 / M_PI;
1299 else
1300 return VO_NOTIMPL;
1301 return VO_TRUE;
1304 static int set_equalizer(char *name, int value)
1306 if (!strcasecmp(name, "brightness"))
1307 procamp.brightness = value / 100.0;
1308 else if (!strcasecmp(name, "contrast"))
1309 procamp.contrast = value / 100.0 + 1.0;
1310 else if (!strcasecmp(name, "saturation"))
1311 procamp.saturation = value / 100.0 + 1.0;
1312 else if (!strcasecmp(name, "hue"))
1313 procamp.hue = value / 100.0 * M_PI;
1314 else
1315 return VO_NOTIMPL;
1317 return update_csc_matrix();
1320 static int control(uint32_t request, void *data, ...)
1322 if (handle_preemption() < 0)
1323 return VO_FALSE;
1325 switch (request) {
1326 case VOCTRL_GET_DEINTERLACE:
1327 *(int*)data = deint;
1328 return VO_TRUE;
1329 case VOCTRL_SET_DEINTERLACE:
1330 if (image_format == IMGFMT_BGRA)
1331 return VO_NOTIMPL;
1332 deint = *(int*)data;
1333 if (deint)
1334 deint = deint_type;
1335 if (deint_type > 2) {
1336 VdpStatus vdp_st;
1337 VdpVideoMixerFeature features[1] =
1338 {deint_type == 3 ?
1339 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL :
1340 VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL};
1341 VdpBool feature_enables[1] = {deint ? VDP_TRUE : VDP_FALSE};
1342 vdp_st = vdp_video_mixer_set_feature_enables(video_mixer, 1,
1343 features,
1344 feature_enables);
1345 CHECK_ST_WARNING("Error changing deinterlacing settings")
1346 deint_buffer_past_frames = 1;
1348 return VO_TRUE;
1349 case VOCTRL_PAUSE:
1350 return int_pause = 1;
1351 case VOCTRL_RESUME:
1352 return int_pause = 0;
1353 case VOCTRL_QUERY_FORMAT:
1354 return query_format(*(uint32_t *)data);
1355 case VOCTRL_GET_IMAGE:
1356 return get_image(data);
1357 case VOCTRL_DRAW_IMAGE:
1358 return draw_image(data);
1359 case VOCTRL_GUISUPPORT:
1360 return VO_TRUE;
1361 case VOCTRL_BORDER:
1362 vo_x11_border();
1363 resize();
1364 return VO_TRUE;
1365 case VOCTRL_FULLSCREEN:
1366 vo_x11_fullscreen();
1367 resize();
1368 return VO_TRUE;
1369 case VOCTRL_GET_PANSCAN:
1370 return VO_TRUE;
1371 case VOCTRL_SET_PANSCAN:
1372 resize();
1373 return VO_TRUE;
1374 case VOCTRL_SET_EQUALIZER: {
1375 va_list ap;
1376 int value;
1377 if (image_format == IMGFMT_BGRA)
1378 return VO_NOTIMPL;
1380 va_start(ap, data);
1381 value = va_arg(ap, int);
1383 va_end(ap);
1384 return set_equalizer(data, value);
1386 case VOCTRL_GET_EQUALIZER: {
1387 va_list ap;
1388 int *value;
1390 va_start(ap, data);
1391 value = va_arg(ap, int *);
1393 va_end(ap);
1394 return get_equalizer(data, value);
1396 case VOCTRL_ONTOP:
1397 vo_x11_ontop();
1398 return VO_TRUE;
1399 case VOCTRL_UPDATE_SCREENINFO:
1400 update_xinerama_info();
1401 return VO_TRUE;
1402 case VOCTRL_DRAW_EOSD:
1403 if (!data)
1404 return VO_FALSE;
1405 generate_eosd(data);
1406 draw_eosd();
1407 return VO_TRUE;
1408 case VOCTRL_GET_EOSD_RES: {
1409 mp_eosd_res_t *r = data;
1410 r->mt = r->mb = r->ml = r->mr = 0;
1411 if (vo_fs) {
1412 r->w = vo_screenwidth;
1413 r->h = vo_screenheight;
1414 r->ml = r->mr = border_x;
1415 r->mt = r->mb = border_y;
1416 } else {
1417 r->w = vo_dwidth;
1418 r->h = vo_dheight;
1420 return VO_TRUE;
1423 return VO_NOTIMPL;
1426 /* @} */