X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fmodules%2Favformat%2Fvdpau.c;h=594e571d8cbd2fc9bbb430513ed90e735d8f4f6c;hb=c5e831a879dda30d5d2a746ddc58f23d5e42e5d5;hp=16b806c154af87c38f6b4d3ff9ed6293f4e35a30;hpb=fec9689fa3890be53dd74fba4c0c4c317e2fb7b9;p=mlt diff --git a/src/modules/avformat/vdpau.c b/src/modules/avformat/vdpau.c index 16b806c1..594e571d 100644 --- a/src/modules/avformat/vdpau.c +++ b/src/modules/avformat/vdpau.c @@ -18,10 +18,14 @@ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -#include +#include +#include +#include extern pthread_mutex_t mlt_sdl_mutex; +static VdpDeviceCreateX11 *vdpau_device_create_x11; +static VdpDeviceDestroy *vdp_device_destroy; static VdpGetProcAddress *vdp_get_proc_address; static VdpGetErrorString *vdp_get_error_string; static VdpGetApiVersion *vdp_get_api_version; @@ -33,79 +37,104 @@ static VdpDecoderCreate *vdp_decoder_create; static VdpDecoderDestroy *vdp_decoder_destroy; static VdpDecoderRender *vdp_decoder_render; -struct -{ - VdpDevice device; - VdpDecoder decoder; - void *producer; -} *g_vdpau = NULL; +// TODO: Shouldn't these be protected by a mutex? +static int vdpau_init_done = 0; +static int vdpau_supported = 1; /** VDPAUD functions */ -static void vdpau_decoder_close(); +static void vdpau_fini( producer_avformat self ) +{ + if ( !self->vdpau ) + return; + mlt_log_debug( NULL, "vdpau_fini (%x)\n", self->vdpau->device ); + if ( self->vdpau->decoder != VDP_INVALID_HANDLE ) + vdp_decoder_destroy( self->vdpau->decoder ); + if ( self->vdpau->device != VDP_INVALID_HANDLE ) + vdp_device_destroy( self->vdpau->device ); + free( self->vdpau ); + self->vdpau = NULL; +} -static int vdpau_init( producer_avformat this ) +static int vdpau_init( producer_avformat self ) { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_init\n" ); + if ( !vdpau_supported ) + return 0; + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_init\n" ); int success = 0; - mlt_properties properties = MLT_PRODUCER_PROPERTIES( this->parent ); - Display *display = (Display*) strtol( mlt_environment( "x11_display" ), NULL, 16 ); - if ( !display || mlt_properties_get_int( properties, "novdpau" ) ) + mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent ); + Display *display = XOpenDisplay( NULL ); + + if ( !display || mlt_properties_get_int( properties, "novdpau" ) + || ( getenv( "MLT_NO_VDPAU" ) && strcmp( getenv( "MLT_NO_VDPAU" ), "1" ) == 0 ) ) return success; - if ( !g_vdpau ) + void *object = NULL; + if ( !vdpau_init_done ) { int flags = RTLD_NOW; - void *object = dlopen( "/usr/lib/libvdpau.so", flags ); - + object = dlopen( "/usr/lib/libvdpau.so", flags ); +#ifdef ARCH_X86_64 + if ( !object ) + object = dlopen( "/usr/lib64/libvdpau.so", flags ); + if ( !object ) + object = dlopen( "/usr/lib/x86_64-linux-gnu/libvdpau.so.1", flags ); +#elif ARCH_X86 + if ( !object ) + object = dlopen( "/usr/lib/i386-linux-gnu/libvdpau.so.1", flags ); +#endif + if ( !object ) + object = dlopen( "/usr/local/lib/libvdpau.so", flags ); if ( object ) + vdpau_device_create_x11 = dlsym( object, "vdp_device_create_x11" ); + else { - VdpDeviceCreateX11 *create_device = dlsym( object, "vdp_device_create_x11" ); - if ( create_device ) - { - int screen = mlt_properties_get_int( properties, "x11_screen" ); - VdpDevice device; + mlt_log( MLT_PRODUCER_SERVICE(self->parent), MLT_LOG_WARNING, "%s: failed to dlopen libvdpau.so\n (%s)\n", __FUNCTION__, dlerror() ); + // Don't try again. + vdpau_supported = 0; + return success; + } + } + + if ( vdpau_device_create_x11 ) + { + int screen = mlt_properties_get_int( properties, "x11_screen" ); + + self->vdpau = calloc( 1, sizeof( *self->vdpau ) ); + self->vdpau->device = VDP_INVALID_HANDLE; + self->vdpau->decoder = VDP_INVALID_HANDLE; - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "X11 Display = %p\n", display ); - if ( VDP_STATUS_OK == create_device( display, screen, &device, &vdp_get_proc_address ) ) - { - // Allocate the global VDPAU context - g_vdpau = calloc( 1, sizeof( *g_vdpau ) ); - if ( g_vdpau ) - { - g_vdpau->device = device; - g_vdpau->decoder = VDP_INVALID_HANDLE; - g_vdpau->producer = this; - vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_GET_ERROR_STRING, (void**) &vdp_get_error_string ); - vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_GET_API_VERSION, (void**) &vdp_get_api_version ); - vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_GET_INFORMATION_STRING, (void**) &vdp_get_information_string ); - vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, (void**) &vdp_surface_create ); - vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, (void**) &vdp_surface_destroy ); - vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, (void**) &vdp_surface_get_bits ); - vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_DECODER_CREATE, (void**) &vdp_decoder_create ); - vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_DECODER_DESTROY, (void**) &vdp_decoder_destroy ); - vdp_get_proc_address( g_vdpau->device, VDP_FUNC_ID_DECODER_RENDER, (void**) &vdp_decoder_render ); - success = 1; - } - } - } - if ( !success ) - { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to initialize device\n" ); - dlclose( object ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "X11 Display = %p\n", display ); + if ( VDP_STATUS_OK == vdpau_device_create_x11( display, screen, &self->vdpau->device, &vdp_get_proc_address ) ) + { + if ( !vdpau_init_done ) { + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_ERROR_STRING, (void**) &vdp_get_error_string ); + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_API_VERSION, (void**) &vdp_get_api_version ); + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_GET_INFORMATION_STRING, (void**) &vdp_get_information_string ); + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_CREATE, (void**) &vdp_surface_create ); + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_DESTROY, (void**) &vdp_surface_destroy ); + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_VIDEO_SURFACE_GET_BITS_Y_CB_CR, (void**) &vdp_surface_get_bits ); + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_CREATE, (void**) &vdp_decoder_create ); + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_DESTROY, (void**) &vdp_decoder_destroy ); + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DECODER_RENDER, (void**) &vdp_decoder_render ); + vdp_get_proc_address( self->vdpau->device, VDP_FUNC_ID_DEVICE_DESTROY, (void**) &vdp_device_destroy ); + vdpau_init_done = 1; } + success = 1; } } - else + + if ( !success ) { - success = 1; - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "VDPAU already initialized\n" ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize device\n" ); + if ( object ) + dlclose( object ); + if ( self->vdpau ) + free( self->vdpau ); + self->vdpau = NULL; } - - if ( g_vdpau && g_vdpau->producer != this ) - vdpau_decoder_close(); - + return success; } @@ -117,12 +146,12 @@ static enum PixelFormat vdpau_get_format( struct AVCodecContext *s, const enum P static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame ) { int error = 0; - producer_avformat this = codec_context->opaque; - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_get_buffer\n" ); + producer_avformat self = codec_context->opaque; + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_get_buffer\n" ); - if ( g_vdpau->producer == this && mlt_deque_count( this->vdpau->deque ) ) + if ( self->vdpau && mlt_deque_count( self->vdpau->deque ) ) { - struct vdpau_render_state *render = mlt_deque_pop_front( this->vdpau->deque ); + struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque ); if ( render ) { @@ -137,28 +166,26 @@ static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame ) frame->reordered_opaque = codec_context->reordered_opaque; if ( frame->reference ) { - frame->age = this->vdpau->ip_age[0]; - this->vdpau->ip_age[0] = this->vdpau->ip_age[1] + 1; - this->vdpau->ip_age[1] = 1; - this->vdpau->b_age++; + self->vdpau->ip_age[0] = self->vdpau->ip_age[1] + 1; + self->vdpau->ip_age[1] = 1; + self->vdpau->b_age++; } else { - frame->age = this->vdpau->b_age; - this->vdpau->ip_age[0] ++; - this->vdpau->ip_age[1] ++; - this->vdpau->b_age = 1; + self->vdpau->ip_age[0] ++; + self->vdpau->ip_age[1] ++; + self->vdpau->b_age = 1; } } else { - mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU surface underrun\n" ); + mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" ); error = -1; } } else { - mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU surface underrun\n" ); + mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU surface underrun\n" ); error = -1; } @@ -167,147 +194,123 @@ static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame ) static void vdpau_release_buffer( AVCodecContext *codec_context, AVFrame *frame ) { - producer_avformat this = codec_context->opaque; - struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_release_buffer (%x)\n", render->surface ); - int i; + producer_avformat self = codec_context->opaque; + if ( self->vdpau ) + { + struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_release_buffer (%x)\n", render->surface ); + int i; - render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; - for ( i = 0; i < 4; i++ ) - frame->data[i] = NULL; - mlt_deque_push_back( this->vdpau->deque, render ); + render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE; + for ( i = 0; i < 4; i++ ) + frame->data[i] = NULL; + mlt_deque_push_back( self->vdpau->deque, render ); + } } static void vdpau_draw_horiz( AVCodecContext *codec_context, const AVFrame *frame, int offset[4], int y, int type, int height ) { - producer_avformat this = codec_context->opaque; - struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; - VdpVideoSurface surface = render->surface; - VdpStatus status = vdp_decoder_render( g_vdpau->decoder, surface, (void*) &render->info, - render->bitstream_buffers_used, render->bitstream_buffers ); - - if ( status != VDP_STATUS_OK ) + producer_avformat self = codec_context->opaque; + if ( self->vdpau ) { - this->vdpau->is_decoded = 0; - mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to decode (%s)\n", - vdp_get_error_string( status ) ); - } - else - { - this->vdpau->is_decoded = 1; + struct vdpau_render_state *render = (struct vdpau_render_state*) frame->data[0]; + VdpVideoSurface surface = render->surface; + VdpStatus status = vdp_decoder_render( self->vdpau->decoder, surface, (void*) &render->info, + render->bitstream_buffers_used, render->bitstream_buffers ); + + if ( status != VDP_STATUS_OK ) + { + self->vdpau->is_decoded = 0; + mlt_log_warning( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to decode (%s)\n", + vdp_get_error_string( status ) ); + } + else + { + self->vdpau->is_decoded = 1; + } } } -static int vdpau_decoder_init( producer_avformat this ) +static int vdpau_decoder_init( producer_avformat self ) { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_decoder_init\n" ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_decoder_init\n" ); int success = 1; - this->video_codec->opaque = this; - this->video_codec->get_format = vdpau_get_format; - this->video_codec->get_buffer = vdpau_get_buffer; - this->video_codec->release_buffer = vdpau_release_buffer; - this->video_codec->draw_horiz_band = vdpau_draw_horiz; - this->video_codec->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; - this->video_codec->pix_fmt = PIX_FMT_VDPAU_H264; + self->video_codec->opaque = self; + self->video_codec->get_format = vdpau_get_format; + self->video_codec->get_buffer = vdpau_get_buffer; + self->video_codec->release_buffer = vdpau_release_buffer; + self->video_codec->draw_horiz_band = vdpau_draw_horiz; + self->video_codec->slice_flags = SLICE_FLAG_CODED_ORDER | SLICE_FLAG_ALLOW_FIELD; + self->video_codec->pix_fmt = PIX_FMT_VDPAU_H264; VdpDecoderProfile profile = VDP_DECODER_PROFILE_H264_HIGH; - uint32_t max_references = this->video_codec->refs; + uint32_t max_references = self->video_codec->refs; pthread_mutex_lock( &mlt_sdl_mutex ); - VdpStatus status = vdp_decoder_create( g_vdpau->device, - profile, this->video_codec->width, this->video_codec->height, max_references, &g_vdpau->decoder ); + VdpStatus status = vdp_decoder_create( self->vdpau->device, + profile, self->video_codec->width, self->video_codec->height, max_references, &self->vdpau->decoder ); pthread_mutex_unlock( &mlt_sdl_mutex ); if ( status == VDP_STATUS_OK ) { - if ( !this->vdpau ) - { - int i, n = FFMIN( this->video_codec->refs + 1, MAX_VDPAU_SURFACES ); - - this->vdpau = calloc( 1, sizeof( *this->vdpau ) ); - this->vdpau->deque = mlt_deque_init(); + int i, n = FFMIN( self->video_codec->refs + 2, MAX_VDPAU_SURFACES ); + + self->vdpau->deque = mlt_deque_init(); for ( i = 0; i < n; i++ ) { - if ( VDP_STATUS_OK == vdp_surface_create( g_vdpau->device, VDP_CHROMA_TYPE_420, - this->video_codec->width, this->video_codec->height, &this->vdpau->render_states[i].surface ) ) + if ( VDP_STATUS_OK == vdp_surface_create( self->vdpau->device, VDP_CHROMA_TYPE_420, + self->video_codec->width, self->video_codec->height, &self->vdpau->render_states[i].surface ) ) { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "successfully created VDPAU surface %x\n", - this->vdpau->render_states[i].surface ); - mlt_deque_push_back( this->vdpau->deque, &this->vdpau->render_states[i] ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "successfully created VDPAU surface %x\n", + self->vdpau->render_states[i].surface ); + mlt_deque_push_back( self->vdpau->deque, &self->vdpau->render_states[i] ); } else { - mlt_log_info( MLT_PRODUCER_SERVICE(this->parent), "failed to create VDPAU surface %dx%d\n", - this->video_codec->width, this->video_codec->height ); - while ( mlt_deque_count( this->vdpau->deque ) ) + mlt_log_info( MLT_PRODUCER_SERVICE(self->parent), "failed to create VDPAU surface %dx%d\n", + self->video_codec->width, self->video_codec->height ); + while ( mlt_deque_count( self->vdpau->deque ) ) { - struct vdpau_render_state *render = mlt_deque_pop_front( this->vdpau->deque ); + struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque ); vdp_surface_destroy( render->surface ); } - mlt_deque_close( this->vdpau->deque ); - free( this->vdpau ); - this->vdpau = NULL; - vdp_decoder_destroy( g_vdpau->decoder ); - g_vdpau->decoder = VDP_INVALID_HANDLE; + mlt_deque_close( self->vdpau->deque ); success = 0; break; } } - this->vdpau->b_age = this->vdpau->ip_age[0] = this->vdpau->ip_age[1] = 256*256*256*64; // magic from Avidemux - } - g_vdpau->producer = this; + if ( self->vdpau ) + self->vdpau->b_age = self->vdpau->ip_age[0] = self->vdpau->ip_age[1] = 256*256*256*64; // magic from Avidemux } else { success = 0; - g_vdpau->decoder = VDP_INVALID_HANDLE; - mlt_log_error( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to initialize decoder (%s)\n", + self->vdpau->decoder = VDP_INVALID_HANDLE; + mlt_log_error( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize decoder (%s)\n", vdp_get_error_string( status ) ); } return success; } -static void vdpau_producer_close( producer_avformat this ) +static void vdpau_producer_close( producer_avformat self ) { - if ( this->vdpau ) + if ( self->vdpau ) { - mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_producer_close\n" ); + mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_producer_close\n" ); int i; for ( i = 0; i < MAX_VDPAU_SURFACES; i++ ) { - if ( this->vdpau->render_states[i].surface != VDP_INVALID_HANDLE ) - vdp_surface_destroy( this->vdpau->render_states[i].surface ); - this->vdpau->render_states[i].surface = VDP_INVALID_HANDLE; + if ( self->vdpau->render_states[i].surface != VDP_INVALID_HANDLE ) + vdp_surface_destroy( self->vdpau->render_states[i].surface ); + self->vdpau->render_states[i].surface = VDP_INVALID_HANDLE; } - mlt_deque_close( this->vdpau->deque ); - if ( this->vdpau->buffer ) - mlt_pool_release( this->vdpau->buffer ); - this->vdpau->buffer = NULL; - free( this->vdpau ); - this->vdpau = NULL; - } -} -static void vdpau_decoder_close( ) -{ - mlt_log_debug( NULL, "vdpau_decoder_close (%x)\n", g_vdpau->decoder ); - if ( g_vdpau && g_vdpau->decoder != VDP_INVALID_HANDLE ) - { - vdp_decoder_destroy( g_vdpau->decoder ); - g_vdpau->decoder = VDP_INVALID_HANDLE; - g_vdpau->producer = NULL; - } - -} + mlt_deque_close( self->vdpau->deque ); + if ( self->vdpau->buffer ) + mlt_pool_release( self->vdpau->buffer ); + self->vdpau->buffer = NULL; -static void vdpau_close( void *ignored ) -{ - mlt_log_debug( NULL, "vdpau_close\n" ); - if ( g_vdpau ) - { - vdpau_decoder_close( ); - free( g_vdpau ); - g_vdpau = NULL; + vdpau_fini( self ); } }