2009-02-16 21:58:13 +01:00
/*
* VDPAU video output driver
*
* Copyright ( C ) 2008 NVIDIA
*
* This file is part of MPlayer .
*
* MPlayer is free software ; you can redistribute it and / or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation ; either version 2 of the License , or
* ( at your option ) any later version .
*
* MPlayer is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License along
* with MPlayer ; if not , write to the Free Software Foundation , Inc . ,
* 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA .
*/
/**
* \ defgroup VDPAU_Presentation VDPAU Presentation
* \ ingroup Decoder
*
* Actual decoding and presentation are implemented here .
* All necessary frame information is collected through
* the " vdpau_render_state " structure after parsing all headers
* etc . in libavcodec for different codecs .
*
* @ {
*/
# include <stdio.h>
# include <dlfcn.h>
# include "config.h"
# include "mp_msg.h"
2009-05-04 02:09:50 +02:00
# include "options.h"
2009-05-06 20:04:37 +02:00
# include "talloc.h"
2009-02-16 21:58:13 +01:00
# include "video_out.h"
# include "x11_common.h"
# include "aspect.h"
# include "sub.h"
2009-02-20 10:45:48 +01:00
# include "subopt-helper.h"
2009-05-04 02:09:50 +02:00
# include "libmpcodecs/vfcap.h"
# include "libmpcodecs/mp_image.h"
2009-02-16 21:58:13 +01:00
# include "libavcodec/vdpau.h"
2009-05-04 02:01:51 +02:00
# include "font_load.h"
2009-02-16 21:58:13 +01:00
# include "libavutil/common.h"
2009-02-28 16:45:24 +01:00
# include "libavutil/mathematics.h"
2009-02-16 21:58:13 +01:00
2009-02-23 10:21:57 +01:00
# include "libass/ass.h"
# include "libass/ass_mp.h"
2009-02-16 21:58:13 +01:00
# define CHECK_ST_ERROR(message) \
if ( vdp_st ! = VDP_STATUS_OK ) { \
mp_msg ( MSGT_VO , MSGL_ERR , " [vdpau] %s: %s \n " , \
2009-05-06 20:04:37 +02:00
message , vdp - > get_error_string ( vdp_st ) ) ; \
2009-02-16 21:58:13 +01:00
return - 1 ; \
}
# define CHECK_ST_WARNING(message) \
if ( vdp_st ! = VDP_STATUS_OK ) \
mp_msg ( MSGT_VO , MSGL_WARN , " [vdpau] %s: %s \n " , \
2009-05-06 20:04:37 +02:00
message , vdp - > get_error_string ( vdp_st ) ) ;
2009-02-16 21:58:13 +01:00
/* number of video and output surfaces */
2009-02-25 13:01:00 +01:00
# define NUM_OUTPUT_SURFACES 2
2009-02-16 21:58:13 +01:00
# define MAX_VIDEO_SURFACES 50
/* number of palette entries */
# define PALETTE_SIZE 256
2009-02-23 10:21:57 +01:00
/* Initial maximum number of EOSD surfaces */
# define EOSD_SURFACES_INITIAL 512
2009-02-16 21:58:13 +01:00
/*
* Global variable declaration - VDPAU specific
*/
2009-05-06 20:04:37 +02:00
struct vdp_functions {
# define VDP_FUNCTION(vdp_type, _, mp_name) vdp_type *mp_name;
# include "vdpau_template.c"
# undef VDP_FUNCTION
} ;
struct vdpctx {
struct vdp_functions * vdp ;
} ;
2009-02-16 21:58:13 +01:00
/* Declaration for all variables of win_x11_init_vdpau_procs() and
* win_x11_init_vdpau_flip_queue ( ) functions
*/
static VdpDevice vdp_device ;
static VdpDeviceCreateX11 * vdp_device_create ;
static VdpGetProcAddress * vdp_get_proc_address ;
static VdpPresentationQueueTarget vdp_flip_target ;
static VdpPresentationQueue vdp_flip_queue ;
static void * vdpau_lib_handle ;
2009-02-25 13:01:00 +01:00
/* output_surfaces[NUM_OUTPUT_SURFACES] is misused for OSD. */
# define osd_surface output_surfaces[NUM_OUTPUT_SURFACES]
static VdpOutputSurface output_surfaces [ NUM_OUTPUT_SURFACES + 1 ] ;
2009-03-15 22:20:06 +01:00
static VdpVideoSurface deint_surfaces [ 3 ] ;
2009-03-24 22:47:56 +01:00
static mp_image_t * deint_mpi [ 2 ] ;
2009-02-16 21:58:13 +01:00
static int output_surface_width , output_surface_height ;
static VdpVideoMixer video_mixer ;
2009-02-20 10:45:48 +01:00
static int deint ;
2009-02-27 22:55:28 +01:00
static int deint_type ;
2009-03-15 22:20:06 +01:00
static int deint_counter ;
2009-03-18 18:02:29 +01:00
static int deint_buffer_past_frames ;
2009-02-20 10:45:48 +01:00
static int pullup ;
static float denoise ;
static float sharpen ;
2009-03-17 00:03:18 +01:00
static int chroma_deint ;
2009-02-24 22:46:25 +01:00
static int top_field_first ;
2009-02-16 21:58:13 +01:00
static VdpDecoder decoder ;
static int decoder_max_refs ;
static VdpRect src_rect_vid ;
static VdpRect out_rect_vid ;
2009-02-17 12:59:49 +01:00
static int border_x , border_y ;
2009-02-16 21:58:13 +01:00
static struct vdpau_render_state surface_render [ MAX_VIDEO_SURFACES ] ;
static int surface_num ;
static int vid_surface_num ;
static uint32_t vid_width , vid_height ;
static uint32_t image_format ;
2009-03-29 21:43:52 +02:00
static VdpChromaType vdp_chroma_type ;
static VdpYCbCrFormat vdp_pixel_format ;
2009-02-16 21:58:13 +01:00
/* draw_osd */
static unsigned char * index_data ;
static int index_data_size ;
static uint32_t palette [ PALETTE_SIZE ] ;
2009-02-23 10:21:57 +01:00
// EOSD
// Pool of surfaces
struct {
VdpBitmapSurface surface ;
int w ;
int h ;
char in_use ;
} * eosd_surfaces ;
// List of surfaces to be rendered
struct {
VdpBitmapSurface surface ;
VdpRect source ;
VdpRect dest ;
VdpColor color ;
} * eosd_targets ;
static int eosd_render_count ;
static int eosd_surface_count ;
2009-02-28 14:20:01 +01:00
// Video equalizer
static VdpProcamp procamp ;
2009-02-16 21:58:13 +01:00
/*
* X11 specific
*/
static int visible_buf ;
static int int_pause ;
2009-03-24 22:45:39 +01:00
static void push_deint_surface ( VdpVideoSurface surface )
{
deint_surfaces [ 2 ] = deint_surfaces [ 1 ] ;
deint_surfaces [ 1 ] = deint_surfaces [ 0 ] ;
deint_surfaces [ 0 ] = surface ;
}
2009-05-04 02:09:50 +02:00
static void flip_page ( struct vo * vo ) ;
static void video_to_output_surface ( struct vo * vo )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
VdpTime dummy ;
VdpStatus vdp_st ;
2009-02-24 22:46:25 +01:00
int i ;
2009-02-16 21:58:13 +01:00
if ( vid_surface_num < 0 )
return ;
2009-03-26 00:32:27 +01:00
if ( deint < 2 | | deint_surfaces [ 0 ] = = VDP_INVALID_HANDLE )
push_deint_surface ( surface_render [ vid_surface_num ] . surface ) ;
2009-02-27 22:52:59 +01:00
for ( i = 0 ; i < = ! ! ( deint > 1 ) ; i + + ) {
2009-02-24 22:46:25 +01:00
int field = VDP_VIDEO_MIXER_PICTURE_STRUCTURE_FRAME ;
VdpOutputSurface output_surface ;
2009-02-28 14:02:52 +01:00
if ( i ) {
2009-05-06 20:04:37 +02:00
// draw_eosd(vo);
2009-05-04 02:09:50 +02:00
//draw_osd(vo, NULL);
flip_page ( vo ) ;
2009-02-28 14:02:52 +01:00
}
2009-02-24 22:46:25 +01:00
if ( deint )
2009-03-26 00:32:27 +01:00
field = ( top_field_first = = i ) ^ ( deint > 1 ) ?
2009-02-24 22:46:25 +01:00
VDP_VIDEO_MIXER_PICTURE_STRUCTURE_BOTTOM_FIELD :
VDP_VIDEO_MIXER_PICTURE_STRUCTURE_TOP_FIELD ;
output_surface = output_surfaces [ surface_num ] ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > presentation_queue_block_until_surface_idle ( vdp_flip_queue ,
2009-02-24 22:46:25 +01:00
output_surface ,
& dummy ) ;
2009-05-06 20:04:37 +02:00
CHECK_ST_WARNING ( " Error when calling vdp->presentation_queue_block_until_surface_idle " )
2009-02-16 21:58:13 +01:00
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > video_mixer_render ( video_mixer , VDP_INVALID_HANDLE , 0 ,
2009-03-15 22:20:06 +01:00
field , 2 , deint_surfaces + 1 ,
deint_surfaces [ 0 ] ,
1 , & surface_render [ vid_surface_num ] . surface ,
& src_rect_vid ,
2009-02-24 23:45:29 +01:00
output_surface ,
NULL , & out_rect_vid , 0 , NULL ) ;
CHECK_ST_WARNING ( " Error when calling vdp_video_mixer_render " )
2009-03-26 00:32:27 +01:00
push_deint_surface ( surface_render [ vid_surface_num ] . surface ) ;
2009-02-24 22:46:25 +01:00
}
2009-02-16 21:58:13 +01:00
}
2009-05-04 02:09:50 +02:00
static void resize ( struct vo * vo )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
VdpStatus vdp_st ;
int i ;
struct vo_rect src_rect ;
struct vo_rect dst_rect ;
2009-02-17 12:59:49 +01:00
struct vo_rect borders ;
2009-05-04 02:09:50 +02:00
calc_src_dst_rects ( vo , vid_width , vid_height , & src_rect , & dst_rect ,
& borders , NULL ) ;
2009-02-16 21:58:13 +01:00
out_rect_vid . x0 = dst_rect . left ;
out_rect_vid . x1 = dst_rect . right ;
out_rect_vid . y0 = dst_rect . top ;
out_rect_vid . y1 = dst_rect . bottom ;
src_rect_vid . x0 = src_rect . left ;
src_rect_vid . x1 = src_rect . right ;
src_rect_vid . y0 = src_rect . top ;
src_rect_vid . y1 = src_rect . bottom ;
2009-02-17 12:59:49 +01:00
border_x = borders . left ;
border_y = borders . top ;
2009-02-16 21:58:13 +01:00
# ifdef CONFIG_FREETYPE
// adjust font size to display size
force_load_font = 1 ;
# endif
vo_osd_changed ( OSDTYPE_OSD ) ;
2009-05-04 02:09:50 +02:00
if ( output_surface_width < vo - > dwidth | | output_surface_height < vo - > dheight ) {
if ( output_surface_width < vo - > dwidth ) {
2009-02-16 21:58:13 +01:00
output_surface_width + = output_surface_width > > 1 ;
2009-05-04 02:09:50 +02:00
output_surface_width = FFMAX ( output_surface_width , vo - > dwidth ) ;
2009-02-16 21:58:13 +01:00
}
2009-05-04 02:09:50 +02:00
if ( output_surface_height < vo - > dheight ) {
2009-02-16 21:58:13 +01:00
output_surface_height + = output_surface_height > > 1 ;
2009-05-04 02:09:50 +02:00
output_surface_height = FFMAX ( output_surface_height , vo - > dheight ) ;
2009-02-16 21:58:13 +01:00
}
// Creation of output_surfaces
2009-02-25 13:01:00 +01:00
for ( i = 0 ; i < = NUM_OUTPUT_SURFACES ; i + + ) {
2009-02-16 21:58:13 +01:00
if ( output_surfaces [ i ] ! = VDP_INVALID_HANDLE )
2009-05-06 20:04:37 +02:00
vdp - > output_surface_destroy ( output_surfaces [ i ] ) ;
vdp_st = vdp - > output_surface_create ( vdp_device , VDP_RGBA_FORMAT_B8G8R8A8 ,
2009-02-16 21:58:13 +01:00
output_surface_width , output_surface_height ,
& output_surfaces [ i ] ) ;
2009-05-06 20:04:37 +02:00
CHECK_ST_WARNING ( " Error when calling vdp->output_surface_create " )
2009-02-16 21:58:13 +01:00
mp_msg ( MSGT_VO , MSGL_DBG2 , " OUT CREATE: %u \n " , output_surfaces [ i ] ) ;
}
}
2009-05-04 02:09:50 +02:00
video_to_output_surface ( vo ) ;
2009-02-16 21:58:13 +01:00
if ( visible_buf )
2009-05-04 02:09:50 +02:00
flip_page ( vo ) ;
2009-02-16 21:58:13 +01:00
}
/* Initialize vdp_get_proc_address, called from preinit() */
2009-05-04 02:09:50 +02:00
static int win_x11_init_vdpau_procs ( struct vo * vo )
2009-02-16 21:58:13 +01:00
{
2009-05-04 02:09:50 +02:00
struct vo_x11_state * x11 = vo - > x11 ;
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = talloc_zero ( vc , struct vdp_functions ) ;
vc - > vdp = vdp ;
2009-02-16 21:58:13 +01:00
VdpStatus vdp_st ;
struct vdp_function {
const int id ;
2009-05-06 20:04:37 +02:00
int offset ;
2009-02-16 21:58:13 +01:00
} ;
const struct vdp_function * dsc ;
static const struct vdp_function vdp_func [ ] = {
2009-05-06 20:04:37 +02:00
# define VDP_FUNCTION(_, macro_name, mp_name) {macro_name, offsetof(struct vdp_functions, mp_name)},
2009-05-05 23:17:21 +02:00
# include "vdpau_template.c"
# undef VDP_FUNCTION
2009-05-06 20:04:37 +02:00
{ 0 , - 1 }
2009-02-16 21:58:13 +01:00
} ;
2009-05-04 02:09:50 +02:00
vdp_st = vdp_device_create ( x11 - > display , x11 - > screen ,
2009-02-16 21:58:13 +01:00
& vdp_device , & vdp_get_proc_address ) ;
if ( vdp_st ! = VDP_STATUS_OK ) {
mp_msg ( MSGT_VO , MSGL_ERR , " [vdpau] Error when calling vdp_device_create_x11: %i \n " , vdp_st ) ;
return - 1 ;
}
2009-05-06 20:04:37 +02:00
vdp - > get_error_string = NULL ;
for ( dsc = vdp_func ; dsc - > offset > = 0 ; dsc + + ) {
vdp_st = vdp_get_proc_address ( vdp_device , dsc - > id ,
( void * * ) ( ( char * ) vdp + dsc - > offset ) ) ;
2009-02-16 21:58:13 +01:00
if ( vdp_st ! = VDP_STATUS_OK ) {
2009-05-06 20:04:37 +02:00
mp_msg ( MSGT_VO , MSGL_ERR , " [vdpau] Error when calling vdp_get_proc_address(function id %d): %s \n " , dsc - > id , vdp - > get_error_string ? vdp - > get_error_string ( vdp_st ) : " ? " ) ;
2009-02-16 21:58:13 +01:00
return - 1 ;
}
}
return 0 ;
}
/* Initialize vdpau_flip_queue, called from config() */
2009-05-04 02:09:50 +02:00
static int win_x11_init_vdpau_flip_queue ( struct vo * vo )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-05-04 02:09:50 +02:00
struct vo_x11_state * x11 = vo - > x11 ;
2009-02-16 21:58:13 +01:00
VdpStatus vdp_st ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > presentation_queue_target_create_x11 ( vdp_device , x11 - > window ,
2009-02-16 21:58:13 +01:00
& vdp_flip_target ) ;
2009-05-06 20:04:37 +02:00
CHECK_ST_ERROR ( " Error when calling vdp->presentation_queue_target_create_x11 " )
2009-02-16 21:58:13 +01:00
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > presentation_queue_create ( vdp_device , vdp_flip_target ,
2009-02-16 21:58:13 +01:00
& vdp_flip_queue ) ;
2009-05-06 20:04:37 +02:00
CHECK_ST_ERROR ( " Error when calling vdp->presentation_queue_create " )
2009-02-16 21:58:13 +01:00
return 0 ;
}
2009-05-06 20:04:37 +02:00
static int create_vdp_mixer ( struct vo * vo , VdpChromaType vdp_chroma_type )
{
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
# define VDP_NUM_MIXER_PARAMETER 3
2009-02-20 10:45:48 +01:00
# define MAX_NUM_FEATURES 5
int i ;
2009-02-16 21:58:13 +01:00
VdpStatus vdp_st ;
2009-02-20 10:45:48 +01:00
int feature_count = 0 ;
VdpVideoMixerFeature features [ MAX_NUM_FEATURES ] ;
VdpBool feature_enables [ MAX_NUM_FEATURES ] ;
2009-02-21 19:15:55 +01:00
static const VdpVideoMixerAttribute denoise_attrib [ ] = { VDP_VIDEO_MIXER_ATTRIBUTE_NOISE_REDUCTION_LEVEL } ;
2009-02-20 10:45:48 +01:00
const void * const denoise_value [ ] = { & denoise } ;
2009-02-21 19:15:55 +01:00
static const VdpVideoMixerAttribute sharpen_attrib [ ] = { VDP_VIDEO_MIXER_ATTRIBUTE_SHARPNESS_LEVEL } ;
2009-02-20 10:45:48 +01:00
const void * const sharpen_value [ ] = { & sharpen } ;
2009-03-17 00:03:18 +01:00
static const VdpVideoMixerAttribute skip_chroma_attrib [ ] = { VDP_VIDEO_MIXER_ATTRIBUTE_SKIP_CHROMA_DEINTERLACE } ;
const uint8_t skip_chroma_value = 1 ;
const void * const skip_chroma_value_ptr [ ] = { & skip_chroma_value } ;
2009-02-16 21:58:13 +01:00
static const VdpVideoMixerParameter parameters [ VDP_NUM_MIXER_PARAMETER ] = {
VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_WIDTH ,
VDP_VIDEO_MIXER_PARAMETER_VIDEO_SURFACE_HEIGHT ,
VDP_VIDEO_MIXER_PARAMETER_CHROMA_TYPE
} ;
const void * const parameter_values [ VDP_NUM_MIXER_PARAMETER ] = {
& vid_width ,
& vid_height ,
& vdp_chroma_type
} ;
2009-03-15 22:26:10 +01:00
features [ feature_count + + ] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL ;
2009-02-27 22:52:59 +01:00
if ( deint = = 4 )
2009-02-20 10:45:48 +01:00
features [ feature_count + + ] = VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL ;
if ( pullup )
features [ feature_count + + ] = VDP_VIDEO_MIXER_FEATURE_INVERSE_TELECINE ;
if ( denoise )
features [ feature_count + + ] = VDP_VIDEO_MIXER_FEATURE_NOISE_REDUCTION ;
if ( sharpen )
features [ feature_count + + ] = VDP_VIDEO_MIXER_FEATURE_SHARPNESS ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > video_mixer_create ( vdp_device , feature_count , features ,
2009-02-16 21:58:13 +01:00
VDP_NUM_MIXER_PARAMETER ,
parameters , parameter_values ,
& video_mixer ) ;
CHECK_ST_ERROR ( " Error when calling vdp_video_mixer_create " )
2009-02-20 10:45:48 +01:00
for ( i = 0 ; i < feature_count ; i + + ) feature_enables [ i ] = VDP_TRUE ;
2009-03-15 22:20:06 +01:00
if ( deint < 3 )
feature_enables [ 0 ] = VDP_FALSE ;
2009-02-20 10:45:48 +01:00
if ( feature_count )
2009-05-06 20:04:37 +02:00
vdp - > video_mixer_set_feature_enables ( video_mixer , feature_count , features , feature_enables ) ;
2009-02-20 10:45:48 +01:00
if ( denoise )
2009-05-06 20:04:37 +02:00
vdp - > video_mixer_set_attribute_values ( video_mixer , 1 , denoise_attrib , denoise_value ) ;
2009-02-20 10:45:48 +01:00
if ( sharpen )
2009-05-06 20:04:37 +02:00
vdp - > video_mixer_set_attribute_values ( video_mixer , 1 , sharpen_attrib , sharpen_value ) ;
2009-03-17 00:03:18 +01:00
if ( ! chroma_deint )
2009-05-06 20:04:37 +02:00
vdp - > video_mixer_set_attribute_values ( video_mixer , 1 , skip_chroma_attrib , skip_chroma_value_ptr ) ;
2009-02-20 10:45:48 +01:00
2009-02-16 21:58:13 +01:00
return 0 ;
}
// Free everything specific to a certain video file
2009-05-06 20:04:37 +02:00
static void free_video_specific ( struct vo * vo )
{
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
int i ;
VdpStatus vdp_st ;
if ( decoder ! = VDP_INVALID_HANDLE )
2009-05-06 20:04:37 +02:00
vdp - > decoder_destroy ( decoder ) ;
2009-02-16 21:58:13 +01:00
decoder = VDP_INVALID_HANDLE ;
decoder_max_refs = - 1 ;
2009-03-15 23:19:05 +01:00
for ( i = 0 ; i < 3 ; i + + )
deint_surfaces [ i ] = VDP_INVALID_HANDLE ;
2009-03-24 22:47:56 +01:00
for ( i = 0 ; i < 2 ; i + + )
2009-03-18 18:02:29 +01:00
if ( deint_mpi [ i ] ) {
deint_mpi [ i ] - > usage_count - - ;
deint_mpi [ i ] = NULL ;
}
2009-02-16 21:58:13 +01:00
for ( i = 0 ; i < MAX_VIDEO_SURFACES ; i + + ) {
if ( surface_render [ i ] . surface ! = VDP_INVALID_HANDLE ) {
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > video_surface_destroy ( surface_render [ i ] . surface ) ;
2009-02-16 21:58:13 +01:00
CHECK_ST_WARNING ( " Error when calling vdp_video_surface_destroy " )
}
surface_render [ i ] . surface = VDP_INVALID_HANDLE ;
}
2009-02-23 10:22:57 +01:00
if ( video_mixer ! = VDP_INVALID_HANDLE ) {
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > video_mixer_destroy ( video_mixer ) ;
2009-02-23 10:22:57 +01:00
CHECK_ST_WARNING ( " Error when calling vdp_video_mixer_destroy " )
}
2009-02-16 21:58:13 +01:00
video_mixer = VDP_INVALID_HANDLE ;
}
2009-05-06 20:04:37 +02:00
static int create_vdp_decoder ( struct vo * vo , int max_refs )
2009-03-21 18:10:19 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-03-21 18:10:19 +01:00
VdpStatus vdp_st ;
VdpDecoderProfile vdp_decoder_profile ;
if ( decoder ! = VDP_INVALID_HANDLE )
2009-05-06 20:04:37 +02:00
vdp - > decoder_destroy ( decoder ) ;
2009-03-21 18:10:19 +01:00
switch ( image_format ) {
case IMGFMT_VDPAU_MPEG1 :
vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG1 ;
break ;
case IMGFMT_VDPAU_MPEG2 :
vdp_decoder_profile = VDP_DECODER_PROFILE_MPEG2_MAIN ;
break ;
case IMGFMT_VDPAU_H264 :
vdp_decoder_profile = VDP_DECODER_PROFILE_H264_HIGH ;
mp_msg ( MSGT_VO , MSGL_V , " [vdpau] Creating H264 hardware decoder for %d reference frames. \n " , max_refs ) ;
break ;
case IMGFMT_VDPAU_WMV3 :
vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_MAIN ;
break ;
case IMGFMT_VDPAU_VC1 :
vdp_decoder_profile = VDP_DECODER_PROFILE_VC1_ADVANCED ;
break ;
}
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > decoder_create ( vdp_device , vdp_decoder_profile ,
2009-03-21 18:10:19 +01:00
vid_width , vid_height , max_refs , & decoder ) ;
CHECK_ST_WARNING ( " Failed creating VDPAU decoder " ) ;
if ( vdp_st ! = VDP_STATUS_OK ) {
decoder = VDP_INVALID_HANDLE ;
decoder_max_refs = 0 ;
2009-03-21 20:59:35 +01:00
return 0 ;
2009-03-21 18:10:19 +01:00
}
decoder_max_refs = max_refs ;
2009-03-21 20:59:35 +01:00
return 1 ;
2009-03-21 18:10:19 +01:00
}
2009-02-16 21:58:13 +01:00
/*
* connect to X server , create and map window , initialize all
* VDPAU objects , create different surfaces etc .
*/
2009-05-04 02:09:50 +02:00
static int config ( struct vo * vo , uint32_t width , uint32_t height ,
uint32_t d_width , uint32_t d_height , uint32_t flags ,
char * title , uint32_t format )
2009-02-16 21:58:13 +01:00
{
2009-05-04 02:09:50 +02:00
struct vo_x11_state * x11 = vo - > x11 ;
2009-02-16 21:58:13 +01:00
XVisualInfo vinfo ;
XSetWindowAttributes xswa ;
XWindowAttributes attribs ;
unsigned long xswamask ;
int depth ;
# ifdef CONFIG_XF86VM
int vm = flags & VOFLAG_MODESWITCHING ;
# endif
image_format = format ;
2009-03-23 00:58:40 +01:00
vid_width = width ;
vid_height = height ;
2009-05-06 20:04:37 +02:00
free_video_specific ( vo ) ;
if ( IMGFMT_IS_VDPAU ( image_format ) & & ! create_vdp_decoder ( vo , 2 ) )
2009-03-23 00:58:40 +01:00
return - 1 ;
2009-02-16 21:58:13 +01:00
visible_buf = 0 ;
{
# ifdef CONFIG_XF86VM
if ( vm )
2009-05-04 02:09:50 +02:00
vo_vm_switch ( vo ) ;
2009-02-16 21:58:13 +01:00
else
# endif
2009-05-04 02:09:50 +02:00
XGetWindowAttributes ( x11 - > display , DefaultRootWindow ( x11 - > display ) ,
& attribs ) ;
2009-02-16 21:58:13 +01:00
depth = attribs . depth ;
if ( depth ! = 15 & & depth ! = 16 & & depth ! = 24 & & depth ! = 32 )
depth = 24 ;
2009-05-04 02:09:50 +02:00
XMatchVisualInfo ( x11 - > display , x11 - > screen , depth , TrueColor , & vinfo ) ;
2009-02-16 21:58:13 +01:00
xswa . background_pixel = 0 ;
xswa . border_pixel = 0 ;
2009-05-08 17:43:54 +02:00
/* Do not use CWBackPixel: It leads to VDPAU errors after
aspect ratio changes . */
xswamask = CWBorderPixel ;
2009-02-16 21:58:13 +01:00
2009-05-04 02:09:50 +02:00
vo_x11_create_vo_window ( vo , & vinfo , vo - > dx , vo - > dy , d_width , d_height ,
2009-02-16 21:58:13 +01:00
flags , CopyFromParent , " vdpau " , title ) ;
2009-05-04 02:09:50 +02:00
XChangeWindowAttributes ( x11 - > display , x11 - > window , xswamask , & xswa ) ;
2009-02-16 21:58:13 +01:00
# ifdef CONFIG_XF86VM
if ( vm ) {
/* Grab the mouse pointer in our window */
if ( vo_grabpointer )
2009-05-04 02:09:50 +02:00
XGrabPointer ( x11 - > display , x11 - > window , True , 0 ,
2009-02-16 21:58:13 +01:00
GrabModeAsync , GrabModeAsync ,
2009-05-04 02:09:50 +02:00
x11 - > window , None , CurrentTime ) ;
XSetInputFocus ( x11 - > display , x11 - > window , RevertToNone , CurrentTime ) ;
2009-02-16 21:58:13 +01:00
}
# endif
}
if ( ( flags & VOFLAG_FULLSCREEN ) & & WinID < = 0 )
vo_fs = 1 ;
/* -----VDPAU related code here -------- */
2009-05-04 02:09:50 +02:00
if ( vdp_flip_queue = = VDP_INVALID_HANDLE
& & win_x11_init_vdpau_flip_queue ( vo ) )
2009-02-16 21:58:13 +01:00
return - 1 ;
2009-03-29 21:43:52 +02:00
vdp_chroma_type = VDP_CHROMA_TYPE_420 ;
switch ( image_format ) {
case IMGFMT_YV12 :
case IMGFMT_I420 :
case IMGFMT_IYUV :
vdp_pixel_format = VDP_YCBCR_FORMAT_YV12 ;
break ;
2009-03-30 23:17:42 +02:00
case IMGFMT_NV12 :
vdp_pixel_format = VDP_YCBCR_FORMAT_NV12 ;
break ;
2009-03-29 21:43:52 +02:00
case IMGFMT_YUY2 :
vdp_pixel_format = VDP_YCBCR_FORMAT_YUYV ;
vdp_chroma_type = VDP_CHROMA_TYPE_422 ;
break ;
case IMGFMT_UYVY :
vdp_pixel_format = VDP_YCBCR_FORMAT_UYVY ;
vdp_chroma_type = VDP_CHROMA_TYPE_422 ;
}
2009-05-06 20:04:37 +02:00
if ( create_vdp_mixer ( vo , vdp_chroma_type ) )
2009-02-16 21:58:13 +01:00
return - 1 ;
surface_num = 0 ;
vid_surface_num = - 1 ;
2009-05-04 02:09:50 +02:00
resize ( vo ) ;
2009-02-16 21:58:13 +01:00
return 0 ;
}
2009-05-04 02:09:50 +02:00
static void check_events ( struct vo * vo )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-05-04 02:09:50 +02:00
int e = vo_x11_check_events ( vo ) ;
2009-02-16 21:58:13 +01:00
if ( e & VO_EVENT_RESIZE )
2009-05-04 02:09:50 +02:00
resize ( vo ) ;
2009-02-16 21:58:13 +01:00
if ( ( e & VO_EVENT_EXPOSE | | e & VO_EVENT_RESIZE ) & & int_pause ) {
/* did we already draw a buffer */
if ( visible_buf ) {
/* redraw the last visible buffer */
VdpStatus vdp_st ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > presentation_queue_display ( vdp_flip_queue ,
2009-02-16 21:58:13 +01:00
output_surfaces [ surface_num ] ,
2009-05-04 02:09:50 +02:00
vo - > dwidth , vo - > dheight ,
2009-02-16 21:58:13 +01:00
0 ) ;
2009-05-06 20:04:37 +02:00
CHECK_ST_WARNING ( " Error when calling vdp->presentation_queue_display " )
2009-02-16 21:58:13 +01:00
}
}
}
2009-05-04 02:09:50 +02:00
static void draw_osd_I8A8 ( void * ctx , int x0 , int y0 , int w , int h ,
unsigned char * src , unsigned char * srca , int stride )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vo * vo = ctx ;
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
VdpOutputSurface output_surface = output_surfaces [ surface_num ] ;
VdpStatus vdp_st ;
int i , j ;
int pitch ;
int index_data_size_required ;
VdpRect output_indexed_rect_vid ;
VdpOutputSurfaceRenderBlendState blend_state ;
if ( ! w | | ! h )
return ;
index_data_size_required = 2 * w * h ;
if ( index_data_size < index_data_size_required ) {
index_data = realloc ( index_data , index_data_size_required ) ;
index_data_size = index_data_size_required ;
}
// index_data creation, component order - I, A, I, A, .....
for ( i = 0 ; i < h ; i + + )
for ( j = 0 ; j < w ; j + + ) {
index_data [ i * 2 * w + j * 2 ] = src [ i * stride + j ] ;
index_data [ i * 2 * w + j * 2 + 1 ] = - srca [ i * stride + j ] ;
}
output_indexed_rect_vid . x0 = x0 ;
output_indexed_rect_vid . y0 = y0 ;
output_indexed_rect_vid . x1 = x0 + w ;
output_indexed_rect_vid . y1 = y0 + h ;
pitch = w * 2 ;
2009-02-25 13:01:00 +01:00
// write source_data to osd_surface.
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > output_surface_put_bits_indexed ( osd_surface ,
2009-02-16 21:58:13 +01:00
VDP_INDEXED_FORMAT_I8A8 ,
( const void * const * ) & index_data ,
& pitch ,
& output_indexed_rect_vid ,
VDP_COLOR_TABLE_FORMAT_B8G8R8X8 ,
( void * ) palette ) ;
2009-05-06 20:04:37 +02:00
CHECK_ST_WARNING ( " Error when calling vdp->output_surface_put_bits_indexed " )
2009-02-16 21:58:13 +01:00
blend_state . struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION ;
blend_state . blend_factor_source_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE ;
blend_state . blend_factor_source_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE ;
blend_state . blend_factor_destination_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA ;
blend_state . blend_factor_destination_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA ;
blend_state . blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD ;
blend_state . blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > output_surface_render_output_surface ( output_surface ,
2009-02-16 21:58:13 +01:00
& output_indexed_rect_vid ,
2009-02-25 13:01:00 +01:00
osd_surface ,
2009-02-16 21:58:13 +01:00
& output_indexed_rect_vid ,
NULL ,
& blend_state ,
VDP_OUTPUT_SURFACE_RENDER_ROTATE_0 ) ;
2009-05-06 20:04:37 +02:00
CHECK_ST_WARNING ( " Error when calling vdp->output_surface_render_output_surface " )
2009-02-16 21:58:13 +01:00
}
2009-05-06 20:04:37 +02:00
static void draw_eosd ( struct vo * vo )
{
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-23 10:21:57 +01:00
VdpStatus vdp_st ;
VdpOutputSurface output_surface = output_surfaces [ surface_num ] ;
VdpOutputSurfaceRenderBlendState blend_state ;
int i ;
blend_state . struct_version = VDP_OUTPUT_SURFACE_RENDER_BLEND_STATE_VERSION ;
blend_state . blend_factor_source_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA ;
blend_state . blend_factor_source_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE ;
blend_state . blend_factor_destination_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA ;
blend_state . blend_factor_destination_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_FACTOR_SRC_ALPHA ;
blend_state . blend_equation_color = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD ;
blend_state . blend_equation_alpha = VDP_OUTPUT_SURFACE_RENDER_BLEND_EQUATION_ADD ;
for ( i = 0 ; i < eosd_render_count ; i + + ) {
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > output_surface_render_bitmap_surface (
2009-02-23 10:21:57 +01:00
output_surface , & eosd_targets [ i ] . dest ,
eosd_targets [ i ] . surface , & eosd_targets [ i ] . source ,
& eosd_targets [ i ] . color , & blend_state ,
VDP_OUTPUT_SURFACE_RENDER_ROTATE_0 ) ;
CHECK_ST_WARNING ( " EOSD: Error when rendering " )
}
}
2009-05-06 20:04:37 +02:00
static void generate_eosd ( struct vo * vo , mp_eosd_images_t * imgs )
{
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-23 10:21:57 +01:00
VdpStatus vdp_st ;
VdpRect destRect ;
int j , found ;
ass_image_t * img = imgs - > imgs ;
ass_image_t * i ;
// Nothing changed, no need to redraw
if ( imgs - > changed = = 0 )
return ;
eosd_render_count = 0 ;
// There's nothing to render!
if ( ! img )
return ;
if ( imgs - > changed = = 1 )
goto eosd_skip_upload ;
for ( j = 0 ; j < eosd_surface_count ; j + + )
eosd_surfaces [ j ] . in_use = 0 ;
for ( i = img ; i ; i = i - > next ) {
// Try to reuse a suitable surface
found = - 1 ;
for ( j = 0 ; j < eosd_surface_count ; j + + ) {
if ( eosd_surfaces [ j ] . surface ! = VDP_INVALID_HANDLE & & ! eosd_surfaces [ j ] . in_use & &
eosd_surfaces [ j ] . w > = i - > w & & eosd_surfaces [ j ] . h > = i - > h ) {
found = j ;
break ;
}
}
// None found, allocate a new surface
if ( found < 0 ) {
for ( j = 0 ; j < eosd_surface_count ; j + + ) {
if ( ! eosd_surfaces [ j ] . in_use ) {
if ( eosd_surfaces [ j ] . surface ! = VDP_INVALID_HANDLE )
2009-05-06 20:04:37 +02:00
vdp - > bitmap_surface_destroy ( eosd_surfaces [ j ] . surface ) ;
2009-02-23 10:21:57 +01:00
found = j ;
break ;
}
}
// Allocate new space for surface/target arrays
if ( found < 0 ) {
j = found = eosd_surface_count ;
eosd_surface_count = eosd_surface_count ? eosd_surface_count * 2 : EOSD_SURFACES_INITIAL ;
eosd_surfaces = realloc ( eosd_surfaces , eosd_surface_count * sizeof ( * eosd_surfaces ) ) ;
eosd_targets = realloc ( eosd_targets , eosd_surface_count * sizeof ( * eosd_targets ) ) ;
for ( j = found ; j < eosd_surface_count ; j + + ) {
eosd_surfaces [ j ] . surface = VDP_INVALID_HANDLE ;
eosd_surfaces [ j ] . in_use = 0 ;
}
}
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > bitmap_surface_create ( vdp_device , VDP_RGBA_FORMAT_A8 ,
2009-02-23 10:21:57 +01:00
i - > w , i - > h , VDP_TRUE , & eosd_surfaces [ found ] . surface ) ;
CHECK_ST_WARNING ( " EOSD: error when creating surface " )
eosd_surfaces [ found ] . w = i - > w ;
eosd_surfaces [ found ] . h = i - > h ;
}
eosd_surfaces [ found ] . in_use = 1 ;
eosd_targets [ eosd_render_count ] . surface = eosd_surfaces [ found ] . surface ;
destRect . x0 = 0 ;
destRect . y0 = 0 ;
destRect . x1 = i - > w ;
destRect . y1 = i - > h ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > bitmap_surface_put_bits_native ( eosd_targets [ eosd_render_count ] . surface ,
2009-02-23 10:21:57 +01:00
( const void * ) & i - > bitmap , & i - > stride , & destRect ) ;
CHECK_ST_WARNING ( " EOSD: putbits failed " )
eosd_render_count + + ;
}
eosd_skip_upload :
eosd_render_count = 0 ;
for ( i = img ; i ; i = i - > next ) {
// Render dest, color, etc.
eosd_targets [ eosd_render_count ] . color . alpha = 1.0 - ( ( i - > color > > 0 ) & 0xff ) / 255.0 ;
eosd_targets [ eosd_render_count ] . color . blue = ( ( i - > color > > 8 ) & 0xff ) / 255.0 ;
eosd_targets [ eosd_render_count ] . color . green = ( ( i - > color > > 16 ) & 0xff ) / 255.0 ;
eosd_targets [ eosd_render_count ] . color . red = ( ( i - > color > > 24 ) & 0xff ) / 255.0 ;
eosd_targets [ eosd_render_count ] . dest . x0 = i - > dst_x ;
eosd_targets [ eosd_render_count ] . dest . y0 = i - > dst_y ;
eosd_targets [ eosd_render_count ] . dest . x1 = i - > w + i - > dst_x ;
eosd_targets [ eosd_render_count ] . dest . y1 = i - > h + i - > dst_y ;
eosd_targets [ eosd_render_count ] . source . x0 = 0 ;
eosd_targets [ eosd_render_count ] . source . y0 = 0 ;
eosd_targets [ eosd_render_count ] . source . x1 = i - > w ;
eosd_targets [ eosd_render_count ] . source . y1 = i - > h ;
eosd_render_count + + ;
}
}
2009-05-04 02:09:50 +02:00
static void draw_osd ( struct vo * vo , struct osd_state * osd )
2009-02-16 21:58:13 +01:00
{
mp_msg ( MSGT_VO , MSGL_DBG2 , " DRAW_OSD \n " ) ;
2009-05-04 02:09:50 +02:00
osd_draw_text_ext ( osd , vo - > dwidth , vo - > dheight , border_x , border_y ,
border_x , border_y , vid_width , vid_height ,
draw_osd_I8A8 , vo ) ;
2009-02-16 21:58:13 +01:00
}
2009-05-04 02:09:50 +02:00
static void flip_page ( struct vo * vo )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
VdpStatus vdp_st ;
mp_msg ( MSGT_VO , MSGL_DBG2 , " \n FLIP_PAGE VID:%u -> OUT:%u \n " ,
surface_render [ vid_surface_num ] . surface , output_surfaces [ surface_num ] ) ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > presentation_queue_display ( vdp_flip_queue , output_surfaces [ surface_num ] ,
2009-05-04 02:09:50 +02:00
vo - > dwidth , vo - > dheight ,
2009-02-16 21:58:13 +01:00
0 ) ;
2009-05-06 20:04:37 +02:00
CHECK_ST_WARNING ( " Error when calling vdp->presentation_queue_display " )
2009-02-16 21:58:13 +01:00
2009-02-25 13:01:00 +01:00
surface_num = ( surface_num + 1 ) % NUM_OUTPUT_SURFACES ;
2009-02-16 21:58:13 +01:00
visible_buf = 1 ;
}
2009-05-04 02:09:50 +02:00
static int draw_slice ( struct vo * vo , uint8_t * image [ ] , int stride [ ] , int w ,
int h , int x , int y )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
VdpStatus vdp_st ;
struct vdpau_render_state * rndr = ( struct vdpau_render_state * ) image [ 0 ] ;
int max_refs = image_format = = IMGFMT_VDPAU_H264 ? rndr - > info . h264 . num_ref_frames : 2 ;
if ( ! IMGFMT_IS_VDPAU ( image_format ) )
return VO_FALSE ;
2009-03-21 18:10:19 +01:00
if ( ( decoder = = VDP_INVALID_HANDLE | | decoder_max_refs < max_refs )
2009-05-06 20:04:37 +02:00
& & ! create_vdp_decoder ( vo , max_refs ) )
2009-03-21 18:10:19 +01:00
return VO_FALSE ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > decoder_render ( decoder , rndr - > surface , ( void * ) & rndr - > info , rndr - > bitstream_buffers_used , rndr - > bitstream_buffers ) ;
2009-02-16 21:58:13 +01:00
CHECK_ST_WARNING ( " Failed VDPAU decoder rendering " ) ;
return VO_TRUE ;
}
2009-05-04 02:09:50 +02:00
static int draw_frame ( struct vo * vo , uint8_t * src [ ] )
2009-02-16 21:58:13 +01:00
{
return VO_ERROR ;
}
2009-05-06 20:04:37 +02:00
static struct vdpau_render_state * get_surface ( struct vo * vo , int number )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
if ( number > MAX_VIDEO_SURFACES )
return NULL ;
if ( surface_render [ number ] . surface = = VDP_INVALID_HANDLE ) {
VdpStatus vdp_st ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > video_surface_create ( vdp_device , vdp_chroma_type ,
2009-02-16 21:58:13 +01:00
vid_width , vid_height ,
& surface_render [ number ] . surface ) ;
CHECK_ST_WARNING ( " Error when calling vdp_video_surface_create " )
if ( vdp_st ! = VDP_STATUS_OK )
return NULL ;
}
mp_msg ( MSGT_VO , MSGL_DBG2 , " VID CREATE: %u \n " , surface_render [ number ] . surface ) ;
return & surface_render [ number ] ;
}
2009-05-04 02:09:50 +02:00
static uint32_t draw_image ( struct vo * vo , mp_image_t * mpi )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
if ( IMGFMT_IS_VDPAU ( image_format ) ) {
struct vdpau_render_state * rndr = mpi - > priv ;
vid_surface_num = rndr - surface_render ;
2009-03-18 18:02:29 +01:00
if ( deint_buffer_past_frames ) {
mpi - > usage_count + + ;
2009-03-24 22:47:56 +01:00
if ( deint_mpi [ 1 ] )
deint_mpi [ 1 ] - > usage_count - - ;
2009-03-18 18:02:29 +01:00
deint_mpi [ 1 ] = deint_mpi [ 0 ] ;
deint_mpi [ 0 ] = mpi ;
}
2009-02-16 21:58:13 +01:00
} else if ( ! ( mpi - > flags & MP_IMGFLAG_DRAW_CALLBACK ) ) {
VdpStatus vdp_st ;
void * destdata [ 3 ] = { mpi - > planes [ 0 ] , mpi - > planes [ 2 ] , mpi - > planes [ 1 ] } ;
2009-05-06 20:04:37 +02:00
struct vdpau_render_state * rndr = get_surface ( vo , deint_counter ) ;
2009-03-24 22:49:08 +01:00
deint_counter = ( deint_counter + 1 ) % 3 ;
2009-02-16 21:58:13 +01:00
vid_surface_num = rndr - surface_render ;
2009-03-30 23:17:42 +02:00
if ( image_format = = IMGFMT_NV12 )
destdata [ 1 ] = destdata [ 2 ] ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > video_surface_put_bits_y_cb_cr ( rndr - > surface ,
2009-03-29 21:43:52 +02:00
vdp_pixel_format ,
2009-02-16 21:58:13 +01:00
( const void * const * ) destdata ,
mpi - > stride ) ; // pitch
CHECK_ST_ERROR ( " Error when calling vdp_video_surface_put_bits_y_cb_cr " )
}
2009-03-29 13:15:22 +02:00
if ( mpi - > fields & MP_IMGFIELD_ORDERED )
2009-03-29 13:16:14 +02:00
top_field_first = ! ! ( mpi - > fields & MP_IMGFIELD_TOP_FIRST ) ;
2009-03-29 13:15:22 +02:00
else
top_field_first = 1 ;
2009-02-16 21:58:13 +01:00
2009-05-04 02:09:50 +02:00
video_to_output_surface ( vo ) ;
2009-02-16 21:58:13 +01:00
return VO_TRUE ;
}
2009-05-06 20:04:37 +02:00
static uint32_t get_image ( struct vo * vo , mp_image_t * mpi )
2009-02-16 21:58:13 +01:00
{
struct vdpau_render_state * rndr ;
// no dr for non-decoding for now
if ( ! IMGFMT_IS_VDPAU ( image_format ) ) return VO_FALSE ;
if ( mpi - > type ! = MP_IMGTYPE_NUMBERED ) return VO_FALSE ;
2009-05-06 20:04:37 +02:00
rndr = get_surface ( vo , mpi - > number ) ;
2009-02-16 21:58:13 +01:00
if ( ! rndr ) {
mp_msg ( MSGT_VO , MSGL_ERR , " [vdpau] no surfaces available in get_image \n " ) ;
// TODO: this probably breaks things forever, provide a dummy buffer?
return VO_FALSE ;
}
mpi - > flags | = MP_IMGFLAG_DIRECT ;
mpi - > stride [ 0 ] = mpi - > stride [ 1 ] = mpi - > stride [ 2 ] = 0 ;
mpi - > planes [ 0 ] = mpi - > planes [ 1 ] = mpi - > planes [ 2 ] = NULL ;
// hack to get around a check and to avoid a special-case in vd_ffmpeg.c
mpi - > planes [ 0 ] = ( void * ) rndr ;
mpi - > num_planes = 1 ;
mpi - > priv = rndr ;
return VO_TRUE ;
}
static int query_format ( uint32_t format )
{
2009-02-23 10:21:57 +01:00
int default_flags = VFCAP_CSP_SUPPORTED | VFCAP_CSP_SUPPORTED_BY_HW | VFCAP_HWSCALE_UP | VFCAP_HWSCALE_DOWN | VFCAP_OSD | VFCAP_EOSD | VFCAP_EOSD_UNSCALED ;
2009-02-16 21:58:13 +01:00
switch ( format ) {
case IMGFMT_YV12 :
2009-03-29 21:25:22 +02:00
case IMGFMT_I420 :
case IMGFMT_IYUV :
2009-03-30 23:17:42 +02:00
case IMGFMT_NV12 :
2009-03-29 21:43:52 +02:00
case IMGFMT_YUY2 :
case IMGFMT_UYVY :
2009-02-18 13:30:15 +01:00
return default_flags | VOCAP_NOSLICES ;
2009-02-16 21:58:13 +01:00
case IMGFMT_VDPAU_MPEG1 :
case IMGFMT_VDPAU_MPEG2 :
case IMGFMT_VDPAU_H264 :
case IMGFMT_VDPAU_WMV3 :
case IMGFMT_VDPAU_VC1 :
2009-02-18 13:30:15 +01:00
return default_flags ;
2009-02-16 21:58:13 +01:00
}
return 0 ;
}
2009-05-06 20:04:37 +02:00
static void destroy_vdpau_objects ( struct vo * vo )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
int i ;
VdpStatus vdp_st ;
2009-05-06 20:04:37 +02:00
free_video_specific ( vo ) ;
2009-02-16 21:58:13 +01:00
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > presentation_queue_destroy ( vdp_flip_queue ) ;
CHECK_ST_WARNING ( " Error when calling vdp->presentation_queue_destroy " )
2009-02-16 21:58:13 +01:00
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > presentation_queue_target_destroy ( vdp_flip_target ) ;
CHECK_ST_WARNING ( " Error when calling vdp->presentation_queue_target_destroy " )
2009-02-16 21:58:13 +01:00
2009-02-25 13:01:00 +01:00
for ( i = 0 ; i < = NUM_OUTPUT_SURFACES ; i + + ) {
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > output_surface_destroy ( output_surfaces [ i ] ) ;
2009-02-16 21:58:13 +01:00
output_surfaces [ i ] = VDP_INVALID_HANDLE ;
2009-05-06 20:04:37 +02:00
CHECK_ST_WARNING ( " Error when calling vdp->output_surface_destroy " )
2009-02-16 21:58:13 +01:00
}
2009-02-23 10:21:57 +01:00
for ( i = 0 ; i < eosd_surface_count ; i + + ) {
if ( eosd_surfaces [ i ] . surface ! = VDP_INVALID_HANDLE ) {
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > bitmap_surface_destroy ( eosd_surfaces [ i ] . surface ) ;
CHECK_ST_WARNING ( " Error when calling vdp->bitmap_surface_destroy " )
2009-02-23 10:21:57 +01:00
}
eosd_surfaces [ i ] . surface = VDP_INVALID_HANDLE ;
}
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > device_destroy ( vdp_device ) ;
2009-02-16 21:58:13 +01:00
CHECK_ST_WARNING ( " Error when calling vdp_device_destroy " )
}
2009-05-04 02:09:50 +02:00
static void uninit ( struct vo * vo )
2009-02-16 21:58:13 +01:00
{
2009-05-04 02:09:50 +02:00
if ( ! vo - > config_count )
2009-02-16 21:58:13 +01:00
return ;
visible_buf = 0 ;
/* Destroy all vdpau objects */
2009-05-06 20:04:37 +02:00
destroy_vdpau_objects ( vo ) ;
2009-02-16 21:58:13 +01:00
free ( index_data ) ;
index_data = NULL ;
2009-02-23 10:21:57 +01:00
free ( eosd_surfaces ) ;
eosd_surfaces = NULL ;
free ( eosd_targets ) ;
eosd_targets = NULL ;
2009-02-16 21:58:13 +01:00
# ifdef CONFIG_XF86VM
2009-05-04 02:09:50 +02:00
vo_vm_close ( vo ) ;
2009-02-16 21:58:13 +01:00
# endif
2009-05-04 02:09:50 +02:00
vo_x11_uninit ( vo ) ;
2009-02-16 21:58:13 +01:00
dlclose ( vdpau_lib_handle ) ;
}
2009-03-07 09:51:40 +01:00
static const opt_t subopts [ ] = {
2009-02-20 10:45:48 +01:00
{ " deint " , OPT_ARG_INT , & deint , ( opt_test_f ) int_non_neg } ,
2009-03-17 00:03:18 +01:00
{ " chroma-deint " , OPT_ARG_BOOL , & chroma_deint , NULL } ,
2009-02-20 10:45:48 +01:00
{ " pullup " , OPT_ARG_BOOL , & pullup , NULL } ,
{ " denoise " , OPT_ARG_FLOAT , & denoise , NULL } ,
{ " sharpen " , OPT_ARG_FLOAT , & sharpen , NULL } ,
{ NULL }
} ;
static const char help_msg [ ] =
" \n -vo vdpau command line help: \n "
" Example: mplayer -vo vdpau:deint=2 \n "
" \n Options: \n "
2009-02-27 22:46:13 +01:00
" deint (all modes > 0 respect -field-dominance) \n "
2009-02-20 10:45:48 +01:00
" 0: no deinterlacing \n "
2009-02-27 22:52:59 +01:00
" 1: only show first field \n "
2009-03-18 18:02:29 +01:00
" 2: bob deinterlacing \n "
" 3: temporal deinterlacing (resource-hungry) \n "
" 4: temporal-spatial deinterlacing (very resource-hungry) \n "
2009-03-17 00:03:18 +01:00
" chroma-deint \n "
" Operate on luma and chroma when using temporal deinterlacing (default) \n "
" Use nochroma-deint to speed up temporal deinterlacing \n "
2009-02-20 10:45:48 +01:00
" pullup \n "
2009-03-15 22:48:52 +01:00
" Try to apply inverse-telecine (needs temporal deinterlacing) \n "
2009-02-20 10:45:48 +01:00
" denoise \n "
" Apply denoising, argument is strength from 0.0 to 1.0 \n "
" sharpen \n "
" Apply sharpening or softening, argument is strength from -1.0 to 1.0 \n "
;
2009-05-04 02:09:50 +02:00
static int preinit ( struct vo * vo , const char * arg )
2009-02-16 21:58:13 +01:00
{
int i ;
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = talloc_zero ( vo , struct vdpctx ) ;
vo - > priv = vc ;
2009-02-16 21:58:13 +01:00
2009-02-20 10:45:48 +01:00
deint = 0 ;
2009-02-27 22:55:28 +01:00
deint_type = 3 ;
2009-03-15 22:20:06 +01:00
deint_counter = 0 ;
2009-03-18 18:02:29 +01:00
deint_buffer_past_frames = 0 ;
2009-03-24 22:47:56 +01:00
deint_mpi [ 0 ] = deint_mpi [ 1 ] = NULL ;
2009-03-17 00:03:18 +01:00
chroma_deint = 1 ;
2009-02-20 10:45:48 +01:00
pullup = 0 ;
denoise = 0 ;
sharpen = 0 ;
if ( subopt_parse ( arg , subopts ) ! = 0 ) {
mp_msg ( MSGT_VO , MSGL_FATAL , help_msg ) ;
return - 1 ;
2009-02-16 21:58:13 +01:00
}
2009-02-27 22:55:28 +01:00
if ( deint )
deint_type = deint ;
2009-03-26 00:32:27 +01:00
if ( deint > 1 )
2009-03-18 18:02:29 +01:00
deint_buffer_past_frames = 1 ;
2009-02-16 21:58:13 +01:00
2009-05-06 20:04:37 +02:00
char * vdpaulibrary = " libvdpau.so.1 " ;
char * vdpau_device_create = " vdp_device_create_x11 " ;
2009-02-16 21:58:13 +01:00
vdpau_lib_handle = dlopen ( vdpaulibrary , RTLD_LAZY ) ;
if ( ! vdpau_lib_handle ) {
mp_msg ( MSGT_VO , MSGL_ERR , " [vdpau] Could not open dynamic library %s \n " ,
vdpaulibrary ) ;
return - 1 ;
}
vdp_device_create = dlsym ( vdpau_lib_handle , vdpau_device_create ) ;
if ( ! vdp_device_create ) {
mp_msg ( MSGT_VO , MSGL_ERR , " [vdpau] Could not find function %s in %s \n " ,
vdpau_device_create , vdpaulibrary ) ;
return - 1 ;
}
2009-05-04 02:09:50 +02:00
if ( ! vo_init ( vo ) | | win_x11_init_vdpau_procs ( vo ) )
2009-02-16 21:58:13 +01:00
return - 1 ;
decoder = VDP_INVALID_HANDLE ;
for ( i = 0 ; i < MAX_VIDEO_SURFACES ; i + + )
surface_render [ i ] . surface = VDP_INVALID_HANDLE ;
video_mixer = VDP_INVALID_HANDLE ;
2009-03-04 20:37:07 +01:00
for ( i = 0 ; i < = NUM_OUTPUT_SURFACES ; i + + )
2009-02-16 21:58:13 +01:00
output_surfaces [ i ] = VDP_INVALID_HANDLE ;
vdp_flip_queue = VDP_INVALID_HANDLE ;
output_surface_width = output_surface_height = - 1 ;
// full grayscale palette.
for ( i = 0 ; i < PALETTE_SIZE ; + + i )
palette [ i ] = ( i < < 16 ) | ( i < < 8 ) | i ;
index_data = NULL ;
index_data_size = 0 ;
2009-02-23 10:21:57 +01:00
eosd_surface_count = eosd_render_count = 0 ;
eosd_surfaces = NULL ;
eosd_targets = NULL ;
2009-02-28 14:20:01 +01:00
procamp . struct_version = VDP_PROCAMP_VERSION ;
procamp . brightness = 0.0 ;
procamp . contrast = 1.0 ;
procamp . saturation = 1.0 ;
procamp . hue = 0.0 ;
2009-02-16 21:58:13 +01:00
return 0 ;
}
2009-05-06 20:04:37 +02:00
static int get_equalizer ( struct vo * vo , const char * name , int * value )
{
struct vdpctx * vc = vo - > priv ;
2009-02-28 14:20:01 +01:00
if ( ! strcasecmp ( name , " brightness " ) )
* value = procamp . brightness * 100 ;
else if ( ! strcasecmp ( name , " contrast " ) )
* value = ( procamp . contrast - 1.0 ) * 100 ;
else if ( ! strcasecmp ( name , " saturation " ) )
* value = ( procamp . saturation - 1.0 ) * 100 ;
else if ( ! strcasecmp ( name , " hue " ) )
2009-02-28 16:45:24 +01:00
* value = procamp . hue * 100 / M_PI ;
2009-02-28 14:20:01 +01:00
else
return VO_NOTIMPL ;
return VO_TRUE ;
}
2009-05-06 20:04:37 +02:00
static int set_equalizer ( struct vo * vo , const char * name , int value )
{
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-28 14:20:01 +01:00
VdpStatus vdp_st ;
VdpCSCMatrix matrix ;
2009-02-28 16:42:17 +01:00
static const VdpVideoMixerAttribute attributes [ ] = { VDP_VIDEO_MIXER_ATTRIBUTE_CSC_MATRIX } ;
2009-02-28 14:20:01 +01:00
const void * attribute_values [ ] = { & matrix } ;
if ( ! strcasecmp ( name , " brightness " ) )
procamp . brightness = value / 100.0 ;
else if ( ! strcasecmp ( name , " contrast " ) )
procamp . contrast = value / 100.0 + 1.0 ;
else if ( ! strcasecmp ( name , " saturation " ) )
procamp . saturation = value / 100.0 + 1.0 ;
else if ( ! strcasecmp ( name , " hue " ) )
2009-02-28 16:45:24 +01:00
procamp . hue = value / 100.0 * M_PI ;
2009-02-28 14:20:01 +01:00
else
return VO_NOTIMPL ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > generate_csc_matrix ( & procamp , VDP_COLOR_STANDARD_ITUR_BT_601 ,
2009-02-28 14:20:01 +01:00
& matrix ) ;
CHECK_ST_WARNING ( " Error when generating CSC matrix " )
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > video_mixer_set_attribute_values ( video_mixer , 1 , attributes ,
2009-02-28 14:20:01 +01:00
attribute_values ) ;
CHECK_ST_WARNING ( " Error when setting CSC matrix " )
return VO_TRUE ;
}
2009-05-04 02:09:50 +02:00
static int control ( struct vo * vo , uint32_t request , void * data )
2009-02-16 21:58:13 +01:00
{
2009-05-06 20:04:37 +02:00
struct vdpctx * vc = vo - > priv ;
struct vdp_functions * vdp = vc - > vdp ;
2009-02-16 21:58:13 +01:00
switch ( request ) {
2009-02-26 19:20:32 +01:00
case VOCTRL_GET_DEINTERLACE :
* ( int * ) data = deint ;
return VO_TRUE ;
case VOCTRL_SET_DEINTERLACE :
deint = * ( int * ) data ;
2009-02-27 22:55:28 +01:00
if ( deint )
deint = deint_type ;
2009-03-15 22:20:06 +01:00
if ( deint_type > 2 ) {
VdpStatus vdp_st ;
VdpVideoMixerFeature features [ 1 ] =
{ deint_type = = 3 ?
VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL :
VDP_VIDEO_MIXER_FEATURE_DEINTERLACE_TEMPORAL_SPATIAL } ;
VdpBool feature_enables [ 1 ] = { deint ? VDP_TRUE : VDP_FALSE } ;
2009-05-06 20:04:37 +02:00
vdp_st = vdp - > video_mixer_set_feature_enables ( video_mixer , 1 ,
2009-03-15 22:20:06 +01:00
features ,
feature_enables ) ;
CHECK_ST_WARNING ( " Error changing deinterlacing settings " )
2009-03-18 18:02:29 +01:00
deint_buffer_past_frames = 1 ;
2009-03-15 22:20:06 +01:00
}
2009-02-26 19:20:32 +01:00
return VO_TRUE ;
2009-02-16 21:58:13 +01:00
case VOCTRL_PAUSE :
return ( int_pause = 1 ) ;
case VOCTRL_RESUME :
return ( int_pause = 0 ) ;
case VOCTRL_QUERY_FORMAT :
return query_format ( * ( uint32_t * ) data ) ;
case VOCTRL_GET_IMAGE :
2009-05-06 20:04:37 +02:00
return get_image ( vo , data ) ;
2009-02-16 21:58:13 +01:00
case VOCTRL_DRAW_IMAGE :
2009-05-04 02:09:50 +02:00
return draw_image ( vo , data ) ;
2009-02-16 21:58:13 +01:00
case VOCTRL_BORDER :
2009-05-04 02:09:50 +02:00
vo_x11_border ( vo ) ;
resize ( vo ) ;
return VO_TRUE ;
2009-02-16 21:58:13 +01:00
case VOCTRL_FULLSCREEN :
2009-05-04 02:09:50 +02:00
vo_x11_fullscreen ( vo ) ;
resize ( vo ) ;
2009-02-16 21:58:13 +01:00
return VO_TRUE ;
case VOCTRL_GET_PANSCAN :
return VO_TRUE ;
case VOCTRL_SET_PANSCAN :
2009-05-04 02:09:50 +02:00
resize ( vo ) ;
2009-02-16 21:58:13 +01:00
return VO_TRUE ;
case VOCTRL_SET_EQUALIZER : {
2009-02-18 00:07:37 +01:00
struct voctrl_set_equalizer_args * args = data ;
2009-05-06 20:04:37 +02:00
return set_equalizer ( vo , args - > name , args - > value ) ;
2009-02-16 21:58:13 +01:00
}
2009-02-18 00:07:37 +01:00
case VOCTRL_GET_EQUALIZER :
{
struct voctrl_get_equalizer_args * args = data ;
2009-05-06 20:04:37 +02:00
return get_equalizer ( vo , args - > name , args - > valueptr ) ;
2009-02-16 21:58:13 +01:00
}
case VOCTRL_ONTOP :
2009-05-04 02:09:50 +02:00
vo_x11_ontop ( vo ) ;
2009-02-16 21:58:13 +01:00
return VO_TRUE ;
case VOCTRL_UPDATE_SCREENINFO :
2009-05-04 02:09:50 +02:00
update_xinerama_info ( vo ) ;
2009-02-16 21:58:13 +01:00
return VO_TRUE ;
2009-02-23 10:21:57 +01:00
case VOCTRL_DRAW_EOSD :
if ( ! data )
return VO_FALSE ;
2009-05-06 20:04:37 +02:00
generate_eosd ( vo , data ) ;
draw_eosd ( vo ) ;
2009-02-23 10:21:57 +01:00
return VO_TRUE ;
case VOCTRL_GET_EOSD_RES : {
mp_eosd_res_t * r = data ;
r - > mt = r - > mb = r - > ml = r - > mr = 0 ;
if ( vo_fs ) {
2009-05-04 02:09:50 +02:00
r - > w = vo - > opts - > vo_screenwidth ;
r - > h = vo - > opts - > vo_screenheight ;
2009-02-23 10:21:57 +01:00
r - > ml = r - > mr = border_x ;
r - > mt = r - > mb = border_y ;
2009-02-25 16:17:14 +01:00
} else {
2009-05-04 02:09:50 +02:00
r - > w = vo - > dwidth ;
r - > h = vo - > dheight ;
2009-02-25 16:17:14 +01:00
}
2009-02-23 10:21:57 +01:00
return VO_TRUE ;
}
2009-02-16 21:58:13 +01:00
}
return VO_NOTIMPL ;
}
2009-05-04 02:09:50 +02:00
const struct vo_driver video_out_vdpau = {
. is_new = 1 ,
2009-05-06 21:21:19 +02:00
. info = & ( const struct vo_info_s ) {
2009-05-04 02:09:50 +02:00
" VDPAU with X11 " ,
" vdpau " ,
" Rajib Mahapatra <rmahapatra@nvidia.com> and others " ,
" "
} ,
. preinit = preinit ,
. config = config ,
. control = control ,
. draw_frame = draw_frame ,
. draw_slice = draw_slice ,
. draw_osd = draw_osd ,
. flip_page = flip_page ,
. check_events = check_events ,
. uninit = uninit ,
} ;