]> git.sesse.net Git - mlt/commitdiff
Add cache support to avformat producer.
authorDan Dennedy <dan@dennedy.org>
Sat, 12 Dec 2009 20:29:09 +0000 (12:29 -0800)
committerDan Dennedy <dan@dennedy.org>
Sat, 12 Dec 2009 20:29:09 +0000 (12:29 -0800)
This also includes a change to make VDPAU work on some versions of
FFmpeg beyond Sept 15, 2009 (do not know exactly when).

src/modules/avformat/producer_avformat.c
src/modules/avformat/vdpau.c

index 7b5ddbb8dfaa28a17570860f53d89b06f1edfeaa..738647e94f55ef3590d12ac38d8d45f92f338fa2 100644 (file)
@@ -27,6 +27,7 @@
 #include <framework/mlt_log.h>
 #include <framework/mlt_deque.h>
 #include <framework/mlt_factory.h>
+#include <framework/mlt_cache.h>
 
 // ffmpeg Header files
 #include <avformat.h>
@@ -64,7 +65,7 @@ void avformat_unlock( );
 
 struct producer_avformat_s
 {
-       struct mlt_producer_s parent;
+       mlt_producer parent;
        AVFormatContext *dummy_context;
        AVFormatContext *audio_format;
        AVFormatContext *video_format;
@@ -115,6 +116,7 @@ typedef struct producer_avformat_s *producer_avformat;
 static int producer_open( producer_avformat this, mlt_profile profile, char *file );
 static int producer_get_frame( mlt_producer this, mlt_frame_ptr frame, int index );
 static void producer_format_close( void *context );
+static void producer_avformat_close( producer_avformat );
 static void producer_close( mlt_producer parent );
 
 #ifdef VDPAU
@@ -163,12 +165,13 @@ mlt_producer producer_avformat_init( mlt_profile profile, char *file )
        if ( !skip && file )
        {
                // Construct the producer
+               mlt_producer producer = calloc( 1, sizeof( struct mlt_producer_s ) );
                producer_avformat this = calloc( 1, sizeof( struct producer_avformat_s ) );
 
                // Initialise it
-               if ( mlt_producer_init( &this->parent, this ) == 0 )
+               if ( mlt_producer_init( producer, this ) == 0 )
                {
-                       mlt_producer producer = &this->parent;
+                       this->parent = producer;
 
                        // Get the properties
                        mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
@@ -182,8 +185,6 @@ mlt_producer producer_avformat_init( mlt_profile profile, char *file )
                        // Register our get_frame implementation
                        producer->get_frame = producer_get_frame;
                        
-                       this->resample_factor = 1.0;
-
                        // Open the file
                        if ( producer_open( this, profile, file ) != 0 )
                        {
@@ -193,17 +194,14 @@ mlt_producer producer_avformat_init( mlt_profile profile, char *file )
                        }
                        else
                        {
-                               // Close the file to release resources for large playlists - reopen later as needed
-                               producer_format_close( this->dummy_context );
-                               this->dummy_context = NULL;
-                               producer_format_close( this->audio_format );
-                               this->audio_format = NULL;
-                               producer_format_close( this->video_format );
-                               this->video_format = NULL;
-
                                // Default the user-selectable indices from the auto-detected indices
                                mlt_properties_set_int( properties, "audio_index",  this->audio_index );
                                mlt_properties_set_int( properties, "video_index",  this->video_index );
+                               
+#ifdef VDPAU
+                               mlt_service_cache_set_size( MLT_PRODUCER_SERVICE(producer), "producer_avformat", 5 );
+#endif
+                               mlt_service_cache_put( MLT_PRODUCER_SERVICE(producer), "producer_avformat", this, 0, (mlt_destructor) producer_avformat_close );
                        }
                        return producer;
                }
@@ -422,7 +420,7 @@ static int producer_open( producer_avformat this, mlt_profile profile, char *fil
        AVFormatContext *context = NULL;
 
        // Get the properties
-       mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent );
+       mlt_properties properties = MLT_PRODUCER_PROPERTIES( this->parent );
 
        // We will treat everything with the producer fps
        double fps = mlt_profile_fps( profile );
@@ -701,6 +699,9 @@ static void get_audio_streams_info( producer_avformat this )
        }
        mlt_log_verbose( NULL, "[producer avformat] audio: total_streams %d max_stream %d total_channels %d max_channels %d\n",
                this->audio_streams, this->audio_max_stream, this->total_channels, this->max_channel );
+       
+       // Other audio-specific initializations
+       this->resample_factor = 1.0;
 }
 
 static inline void convert_image( AVFrame *frame, uint8_t *buffer, int pix_fmt, mlt_image_format *format, int width, int height )
@@ -847,7 +848,7 @@ static int producer_get_image( mlt_frame frame, uint8_t **buffer, mlt_image_form
 {
        // Get the producer
        producer_avformat this = mlt_frame_pop_service( frame );
-       mlt_producer producer = &this->parent;
+       mlt_producer producer = this->parent;
 
        // Get the properties from the frame
        mlt_properties frame_properties = MLT_FRAME_PROPERTIES( frame );
@@ -1343,7 +1344,7 @@ static int video_codec_init( producer_avformat this, int index, mlt_properties p
                if ( source_fps > 0 )
                        mlt_properties_set_double( properties, "source_fps", source_fps );
                else
-                       mlt_properties_set_double( properties, "source_fps", mlt_producer_get_fps( &this->parent ) );
+                       mlt_properties_set_double( properties, "source_fps", mlt_producer_get_fps( this->parent ) );
        }
        return this->video_codec && this->video_index > -1;
 }
@@ -1354,7 +1355,7 @@ static int video_codec_init( producer_avformat this, int index, mlt_properties p
 static void producer_set_up_video( producer_avformat this, mlt_frame frame )
 {
        // Get the producer
-       mlt_producer producer = &this->parent;
+       mlt_producer producer = this->parent;
 
        // Get the properties
        mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
@@ -1591,10 +1592,10 @@ static int producer_get_audio( mlt_frame frame, void **buffer, mlt_audio_format
        mlt_position position = mlt_properties_get_position( MLT_FRAME_PROPERTIES( frame ), "avformat_position" );
 
        // Calculate the real time code
-       double real_timecode = producer_time_of_frame( &this->parent, position );
+       double real_timecode = producer_time_of_frame( this->parent, position );
 
        // Get the source fps
-       double source_fps = mlt_properties_get_double( MLT_PRODUCER_PROPERTIES( &this->parent ), "source_fps" );
+       double source_fps = mlt_properties_get_double( MLT_PRODUCER_PROPERTIES( this->parent ), "source_fps" );
 
        // Number of frames to ignore (for ffwd)
        int ignore = 0;
@@ -1810,7 +1811,7 @@ static int audio_codec_init( producer_avformat this, int index, mlt_properties p
 static void producer_set_up_audio( producer_avformat this, mlt_frame frame )
 {
        // Get the producer
-       mlt_producer producer = &this->parent;
+       mlt_producer producer = this->parent;
 
        // Get the properties
        mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
@@ -1898,16 +1899,31 @@ static void producer_set_up_audio( producer_avformat this, mlt_frame frame )
 static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
 {
        // Access the private data
-       producer_avformat this = producer->child;
+       mlt_cache_item cache_item = mlt_service_cache_get( MLT_PRODUCER_SERVICE(producer), "producer_avformat" );
+       producer_avformat this = mlt_cache_item_data( cache_item, NULL );
 
        // Create an empty frame
        *frame = mlt_frame_init( MLT_PRODUCER_SERVICE( producer ) );
+       
+       if ( *frame )
+               mlt_properties_set_data( MLT_FRAME_PROPERTIES(*frame), "avformat_cache", cache_item, 0, (mlt_destructor) mlt_cache_item_close, NULL );
+       else
+               mlt_cache_item_close( cache_item );
 
        // Update timecode on the frame we're creating
        mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
 
        // Set the position of this producer
        mlt_properties_set_position( MLT_FRAME_PROPERTIES( *frame ), "avformat_position", mlt_producer_frame( producer ) );
+       
+       // If cache miss
+       if ( !this )
+       {
+               this = calloc( 1, sizeof( struct producer_avformat_s ) );
+               producer->child = this;
+               this->parent = producer;
+               mlt_service_cache_put( MLT_PRODUCER_SERVICE(producer), "producer_avformat", this, 0, (mlt_destructor) producer_avformat_close );
+       }
 
        // Set up the video
        producer_set_up_video( this, *frame );
@@ -1921,11 +1937,9 @@ static int producer_get_frame( mlt_producer producer, mlt_frame_ptr frame, int i
        return 0;
 }
 
-static void producer_close( mlt_producer parent )
+static void producer_avformat_close( producer_avformat this )
 {
-       // Obtain this
-       producer_avformat this = parent->child;
-
+       mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "producer_avformat_close\n" );
        // Close the file
        av_free( this->av_frame );
        int i;
@@ -1944,11 +1958,15 @@ static void producer_close( mlt_producer parent )
 #ifdef VDPAU
        vdpau_producer_close( this );
 #endif
+       free( this );
+}
 
+static void producer_close( mlt_producer parent )
+{
        // Close the parent
        parent->close = NULL;
        mlt_producer_close( parent );
 
        // Free the memory
-       free( this );
+       free( parent );
 }
index 42a2f7d964b39c4b5950a8244bef2f32d0c28c92..16b806c154af87c38f6b4d3ff9ed6293f4e35a30 100644 (file)
@@ -47,9 +47,9 @@ static void vdpau_decoder_close();
 
 static int vdpau_init( producer_avformat this )
 {
-       mlt_log_debug( MLT_PRODUCER_SERVICE(&this->parent), "vdpau_init\n" );
+       mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_init\n" );
        int success = 0;
-       mlt_properties properties = MLT_PRODUCER_PROPERTIES( &this->parent );
+       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" ) )
                return success;
@@ -67,7 +67,7 @@ static int vdpau_init( producer_avformat this )
                                int screen = mlt_properties_get_int( properties, "x11_screen" );
                                VdpDevice device;
                                
-                               mlt_log_debug( MLT_PRODUCER_SERVICE(&this->parent), "X11 Display = %p\n", display );
+                               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
@@ -92,7 +92,7 @@ static int vdpau_init( producer_avformat this )
                        }
                        if ( !success )
                        {
-                               mlt_log_debug( MLT_PRODUCER_SERVICE(&this->parent), "VDPAU failed to initialize device\n" );
+                               mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to initialize device\n" );
                                dlclose( object );
                        }
                }
@@ -100,7 +100,7 @@ static int vdpau_init( producer_avformat this )
        else
        {
                success = 1;
-               mlt_log_debug( MLT_PRODUCER_SERVICE(&this->parent), "VDPAU already initialized\n" );
+               mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "VDPAU already initialized\n" );
        }
        
        if ( g_vdpau && g_vdpau->producer != this )
@@ -109,11 +109,16 @@ static int vdpau_init( producer_avformat this )
        return success;
 }
 
+static enum PixelFormat vdpau_get_format( struct AVCodecContext *s, const enum PixelFormat *fmt )
+{
+       return PIX_FMT_VDPAU_H264;
+}
+
 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" );
+       mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_get_buffer\n" );
        
        if ( g_vdpau->producer == this && mlt_deque_count( this->vdpau->deque ) )
        {
@@ -147,13 +152,13 @@ static int vdpau_get_buffer( AVCodecContext *codec_context, AVFrame *frame )
                }
                else
                {
-                       mlt_log_warning( MLT_PRODUCER_SERVICE(&this->parent), "VDPAU surface underrun\n" );
+                       mlt_log_warning( MLT_PRODUCER_SERVICE(this->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(this->parent), "VDPAU surface underrun\n" );
                error = -1;
        }
        
@@ -164,7 +169,7 @@ 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 );
+       mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_release_buffer (%x)\n", render->surface );
        int i;
 
        render->state &= ~FF_VDPAU_STATE_USED_FOR_REFERENCE;
@@ -184,7 +189,7 @@ static void vdpau_draw_horiz( AVCodecContext *codec_context, const AVFrame *fram
        if ( status != VDP_STATUS_OK )
        {
                this->vdpau->is_decoded = 0;
-               mlt_log_warning( MLT_PRODUCER_SERVICE(&this->parent), "VDPAU failed to decode (%s)\n",
+               mlt_log_warning( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to decode (%s)\n",
                        vdp_get_error_string( status ) );
        }
        else
@@ -195,14 +200,16 @@ static void vdpau_draw_horiz( AVCodecContext *codec_context, const AVFrame *fram
 
 static int vdpau_decoder_init( producer_avformat this )
 {
-       mlt_log_debug( MLT_PRODUCER_SERVICE(&this->parent), "vdpau_decoder_init\n" );
+       mlt_log_debug( MLT_PRODUCER_SERVICE(this->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;
        
        VdpDecoderProfile profile = VDP_DECODER_PROFILE_H264_HIGH;
        uint32_t max_references = this->video_codec->refs;
@@ -224,13 +231,13 @@ static int vdpau_decoder_init( producer_avformat this )
                                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 ) )
                                {
-                                       mlt_log_debug( MLT_PRODUCER_SERVICE(&this->parent), "successfully created VDPAU surface %x\n",
+                                       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] );
                                }
                                else
                                {
-                                       mlt_log_info( MLT_PRODUCER_SERVICE(&this->parent), "failed to create VDPAU surface %dx%d\n",
+                                       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 ) )
                                        {
@@ -254,7 +261,7 @@ static int vdpau_decoder_init( producer_avformat this )
        {
                success = 0;
                g_vdpau->decoder = VDP_INVALID_HANDLE;
-               mlt_log_error( MLT_PRODUCER_SERVICE(&this->parent), "VDPAU failed to initialize decoder (%s)\n",
+               mlt_log_error( MLT_PRODUCER_SERVICE(this->parent), "VDPAU failed to initialize decoder (%s)\n",
                        vdp_get_error_string( status ) );
        }
        
@@ -265,7 +272,7 @@ static void vdpau_producer_close( producer_avformat this )
 {
        if ( this->vdpau )
        {
-               mlt_log_debug( MLT_PRODUCER_SERVICE(&this->parent), "vdpau_producer_close\n" );
+               mlt_log_debug( MLT_PRODUCER_SERVICE(this->parent), "vdpau_producer_close\n" );
                int i;
                for ( i = 0; i < MAX_VDPAU_SURFACES; i++ )
                {