]> git.sesse.net Git - mlt/commitdiff
Merge branch 'master' of xtremedia:git/mltframework.org/mlt
authorDan Dennedy <dan@dennedy.org>
Thu, 1 Dec 2011 23:40:27 +0000 (15:40 -0800)
committerDan Dennedy <dan@dennedy.org>
Thu, 1 Dec 2011 23:40:27 +0000 (15:40 -0800)
src/modules/avformat/producer_avformat.c
src/modules/avformat/vdpau.c
src/modules/core/consumer_multi.c

index 1371cc8cd376c0526cda713a133868759dc726f2..a228ec733b56952ba2fd11262700c8c4d73224ec 100644 (file)
@@ -126,6 +126,9 @@ struct producer_avformat_s
                int ip_age[2];
                int is_decoded;
                uint8_t *buffer;
+
+               VdpDevice device;
+               VdpDecoder decoder;
        } *vdpau;
 #endif
 };
@@ -1460,15 +1463,13 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
                                if ( must_decode || int_position >= req_position )
                                {
 #ifdef VDPAU
-                                       if ( g_vdpau && self->vdpau )
+                                       if ( self->vdpau )
                                        {
-                                               if ( g_vdpau->producer != self )
+                                               if ( self->vdpau->decoder == VDP_INVALID_HANDLE )
                                                {
-                                                       vdpau_decoder_close();
                                                        vdpau_decoder_init( self );
                                                }
-                                               if ( self->vdpau )
-                                                       self->vdpau->is_decoded = 0;
+                                               self->vdpau->is_decoded = 0;
                                        }
 #endif
                                        codec_context->reordered_opaque = pkt.pts;
@@ -1703,7 +1704,7 @@ static int video_codec_init( producer_avformat self, int index, mlt_properties p
                                {
                                        self->video_codec = codec_context;
                                        if ( !vdpau_decoder_init( self ) )
-                                               vdpau_decoder_close();
+                                               vdpau_fini( self );
                                }
                        }
                        if ( !self->vdpau )
index fcb16be800a7899b8b499233d7dcebc59525ad62..b5710b382227c7c97e55c6561e0893133f319a47 100644 (file)
@@ -24,6 +24,8 @@
 
 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;
@@ -35,17 +37,23 @@ 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;
+static int vdpau_init_done = 0;
 
 /** 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 self )
 {
@@ -58,66 +66,61 @@ static int vdpau_init( producer_avformat self )
             || ( 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/lib64/libvdpau.so", flags );
-
+               object = dlopen( "/usr/lib64/libvdpau.so", flags );
                if ( !object )
                        object = dlopen( "/usr/lib/libvdpau.so", flags );
                if ( !object )
                        object = dlopen( "/usr/local/lib/libvdpau.so", flags );
                if ( object )
-               {
-                       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_debug( MLT_PRODUCER_SERVICE(self->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 = self;
-                                               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(self->parent), "VDPAU failed to initialize device\n" );
-                               dlclose( object );
-                       }
-               }
+                       vdpau_device_create_x11 = dlsym( object, "vdp_device_create_x11" );
                else
                {
                        mlt_log( MLT_PRODUCER_SERVICE(self->parent), MLT_LOG_WARNING, "%s: failed to dlopen libvdpau.so\n  (%s)\n", __FUNCTION__, dlerror() );
+                       return success;
                }
        }
-       else
+                       
+       if ( vdpau_device_create_x11 )
        {
-               success = 1;
-               mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "VDPAU already initialized\n" );
+               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(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;
+               }
        }
        
-       if ( g_vdpau && g_vdpau->producer != self )
-               vdpau_decoder_close();
-       
+       if ( !success )
+       {
+               mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "VDPAU failed to initialize device\n" );
+               if ( object )
+                       dlclose( object );
+               if ( self->vdpau )
+                       vdpau_fini( self );
+       }
+
        return success;
 }
 
@@ -132,7 +135,7 @@ static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame )
        producer_avformat self = codec_context->opaque;
        mlt_log_debug( MLT_PRODUCER_SERVICE(self->parent), "vdpau_get_buffer\n" );
        
-       if ( g_vdpau->producer == self && self->vdpau && mlt_deque_count( self->vdpau->deque ) )
+       if ( self->vdpau && mlt_deque_count( self->vdpau->deque ) )
        {
                struct vdpau_render_state *render = mlt_deque_pop_front( self->vdpau->deque );
                
@@ -200,7 +203,7 @@ static void vdpau_draw_horiz( AVCodecContext *codec_context, const AVFrame *fram
        {
                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,
+               VdpStatus status = vdp_decoder_render( self->vdpau->decoder, surface, (void*) &render->info,
                        render->bitstream_buffers_used, render->bitstream_buffers );
 
                if ( status != VDP_STATUS_OK )
@@ -232,21 +235,18 @@ static int vdpau_decoder_init( producer_avformat self )
        VdpDecoderProfile profile = VDP_DECODER_PROFILE_H264_HIGH;
        uint32_t max_references = self->video_codec->refs;
        pthread_mutex_lock( &mlt_sdl_mutex );
-       VdpStatus status = vdp_decoder_create( g_vdpau->device,
-               profile, self->video_codec->width, self->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 ( !self->vdpau )
-               {
                        int i, n = FFMIN( self->video_codec->refs + 2, MAX_VDPAU_SURFACES );
-       
-                       self->vdpau = calloc( 1, sizeof( *self->vdpau ) );
+
                        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,
+                               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(self->parent), "successfully created VDPAU surface %x\n",
@@ -263,23 +263,17 @@ static int vdpau_decoder_init( producer_avformat self )
                                                vdp_surface_destroy( render->surface );
                                        }
                                        mlt_deque_close( self->vdpau->deque );
-                                       free( self->vdpau );
-                                       self->vdpau = NULL;
-                                       vdp_decoder_destroy( g_vdpau->decoder );
-                                       g_vdpau->decoder = VDP_INVALID_HANDLE;
                                        success = 0;
                                        break;
                                }
                        }
                        if ( self->vdpau )
                                self->vdpau->b_age = self->vdpau->ip_age[0] = self->vdpau->ip_age[1] = 256*256*256*64; // magic from Avidemux
-               }
-               g_vdpau->producer = self;
        }
        else
        {
                success = 0;
-               g_vdpau->decoder = VDP_INVALID_HANDLE;
+               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 ) );
        }
@@ -299,36 +293,12 @@ static void vdpau_producer_close( producer_avformat self )
                                vdp_surface_destroy( self->vdpau->render_states[i].surface );
                        self->vdpau->render_states[i].surface = VDP_INVALID_HANDLE;
                }
+
                mlt_deque_close( self->vdpau->deque );
                if ( self->vdpau->buffer )
                        mlt_pool_release( self->vdpau->buffer );
                self->vdpau->buffer = NULL;
-               free( self->vdpau );
-               self->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;
-       }
-       
-}
 
-#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
index 0cf52f0ceb96ea83c56f4c7f09ec9f25834f80b6..948bf4a9fe9c2325e8bdae445272068a6bf4b644 100644 (file)
@@ -22,6 +22,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <pthread.h>
+#include <sys/time.h>
 
 // Forward references
 static int start( mlt_consumer consumer );
@@ -41,26 +42,35 @@ mlt_consumer consumer_multi_init( mlt_profile profile, mlt_service_type type, co
 
        if ( consumer )
        {
+               mlt_properties properties = MLT_CONSUMER_PROPERTIES(consumer);
+
+               // Set defaults
+               mlt_properties_set( properties, "resource", arg );
+               mlt_properties_set_int( properties, "real_time", -1 );
+               mlt_properties_set_int( properties, "terminate_on_pause", 1 );
+
+               // Init state
+               mlt_properties_set_int( properties, "joined", 1 );
+
                // Assign callbacks
                consumer->close = consumer_close;
                consumer->start = start;
                consumer->stop = stop;
                consumer->is_stopped = is_stopped;
-
-               mlt_properties_set( MLT_CONSUMER_PROPERTIES(consumer), "resource", arg );
-               mlt_properties_set_int( MLT_CONSUMER_PROPERTIES(consumer), "real_time", -1 );
        }
 
        return consumer;
 }
 
-static mlt_consumer create_consumer( mlt_profile profile, char *id )
+static mlt_consumer create_consumer( mlt_profile profile, char *id, char *arg )
 {
        char *myid = id ? strdup( id ) : NULL;
-       char *arg = myid ? strchr( myid, ':' ) : NULL;
-       if ( arg != NULL )
-               *arg ++ = '\0';
-       mlt_consumer consumer = mlt_factory_consumer( profile, myid, arg );
+       char *myarg = ( myid && !arg ) ? strchr( myid, ':' ) : NULL;
+       if ( myarg )
+               *myarg ++ = '\0';
+       else
+               myarg = arg;
+       mlt_consumer consumer = mlt_factory_consumer( profile, myid, myarg );
        if ( myid )
                free( myid );
        return consumer;
@@ -134,7 +144,8 @@ static mlt_consumer generate_consumer( mlt_consumer consumer, mlt_properties pro
                profile = mlt_profile_init( mlt_properties_get( props, "mlt_profile" ) );
        if ( !profile )
                profile = mlt_profile_clone( mlt_service_profile( MLT_CONSUMER_SERVICE(consumer) ) );
-       mlt_consumer nested = create_consumer( profile, mlt_properties_get( props, "mlt_service" ) );
+       mlt_consumer nested = create_consumer( profile, mlt_properties_get( props, "mlt_service" ),
+               mlt_properties_get( props, "target" ) );
 
        if ( nested )
        {
@@ -372,11 +383,27 @@ static void foreach_consumer_stop( mlt_consumer consumer )
        mlt_consumer nested = NULL;
        char key[30];
        int index = 0;
+       struct timespec tm = { 0, 1000 * 1000 };
 
        do {
                snprintf( key, sizeof(key), "%d.consumer", index++ );
                nested = mlt_properties_get_data( properties, key, NULL );
-               if ( nested ) mlt_consumer_stop( nested );
+               if ( nested )
+               {
+                       // Let consumer with terminate_on_pause stop on their own
+                       if ( mlt_properties_get_int( MLT_CONSUMER_PROPERTIES(nested), "terminate_on_pause" ) )
+                       {
+                               // Send additional dummy frame to unlatch nested consumer's threads
+                               mlt_consumer_put_frame( nested, mlt_frame_init( MLT_CONSUMER_SERVICE(consumer) ) );
+                               // wait for stop
+                               while ( !mlt_consumer_is_stopped( nested ) )
+                                       nanosleep( &tm, NULL );
+                       }
+                       else
+                       {
+                               mlt_consumer_stop( nested );
+                       }
+               }
        } while ( nested );
 }
 
@@ -396,6 +423,7 @@ static int start( mlt_consumer consumer )
 
                // Set the running state
                mlt_properties_set_int( properties, "running", 1 );
+               mlt_properties_set_int( properties, "joined", 0 );
 
                // Construct and start nested consumers
                if ( !mlt_properties_get_data( properties, "0.consumer", NULL ) )
@@ -414,7 +442,7 @@ static int start( mlt_consumer consumer )
 static int stop( mlt_consumer consumer )
 {
        // Check that we're running
-       if ( !is_stopped( consumer ) )
+       if ( !mlt_properties_get_int( MLT_CONSUMER_PROPERTIES(consumer), "joined" ) )
        {
                mlt_properties properties = MLT_CONSUMER_PROPERTIES( consumer );
                pthread_t *thread = mlt_properties_get_data( properties, "thread", NULL );
@@ -428,6 +456,7 @@ static int stop( mlt_consumer consumer )
                        foreach_consumer_refresh( consumer );
                        pthread_join( *thread, NULL );
                }
+               mlt_properties_set_int( properties, "joined", 1 );
 
                // Stop nested consumers
                foreach_consumer_stop( consumer );
@@ -487,14 +516,19 @@ static void *consumer_thread( void *arg )
                }
                else
                {
-                       if ( frame ) mlt_frame_close( frame );
-                       foreach_consumer_put( consumer, NULL );
+                       if ( frame && terminated )
+                       {
+                               // Send this termination frame to nested consumers for their cancellation
+                               foreach_consumer_put( consumer, frame );
+                               mlt_events_fire( properties, "consumer-frame-show", frame, NULL );
+                       }
+                       if ( frame )
+                               mlt_frame_close( frame );
                        terminated = 1;
                }
        }
 
        // Indicate that the consumer is stopped
-       mlt_properties_set_int( properties, "running", 0 );
        mlt_consumer_stopped( consumer );
 
        return NULL;
@@ -506,6 +540,7 @@ static void *consumer_thread( void *arg )
 static void consumer_close( mlt_consumer consumer )
 {
        mlt_consumer_stop( consumer );
+
        // Close the parent
        mlt_consumer_close( consumer );
        free( consumer );