]> git.sesse.net Git - mlt/blobdiff - src/modules/avformat/vdpau.c
Add support for libavformat and libavcodec major version 55.
[mlt] / src / modules / avformat / vdpau.c
index e4237f8735a08c8bfbea61217b22d7c06233b004..a98b1769262d6bec1977eefc040e5465ccafcee9 100644 (file)
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#include <vdpau.h>
+#include <libavcodec/vdpau.h>
+#include <X11/Xlib.h>
+#include <dlfcn.h>
 
 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,80 +37,103 @@ 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 );
+       mlt_properties properties = MLT_PRODUCER_PROPERTIES( self->parent );
+       Display *display = XOpenDisplay( NULL );
        
-       if ( !mlt_environment( "x11_display" ) || mlt_properties_get_int( properties, "novdpau" ) )
+       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;
-                               Display *display = (Display*) strtol( mlt_environment( "x11_display" ), NULL, 16 );
+                       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 )
+                       vdpau_fini( self );
        }
-       
-       if ( g_vdpau && g_vdpau->producer != this )
-               vdpau_decoder_close();
-       
+
        return success;
 }
 
@@ -118,12 +145,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 )
                {
@@ -138,28 +165,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;
        }
        
@@ -168,149 +193,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;
 
-#if 0
-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 );
        }
 }
-#endif