]> git.sesse.net Git - mlt/commitdiff
add caching to decklink producer
authorDan Dennedy <dan@dennedy.org>
Sat, 19 Nov 2011 22:31:17 +0000 (14:31 -0800)
committerDan Dennedy <dan@dennedy.org>
Sat, 19 Nov 2011 22:31:17 +0000 (14:31 -0800)
Now it supports YADIF deinterlace and framerate conversion.

src/modules/decklink/producer_decklink.cpp

index 5eadc1c75b37687d4ae355a67873997d165291f3..a857ac4d7ce73d5f07d8ccea7ee5cad96d9b6e51 100644 (file)
@@ -47,6 +47,7 @@ private:
        int              m_topFieldFirst;
        int              m_colorspace;
        int              m_vancLines;
+       mlt_cache        m_cache;
 
        BMDDisplayMode getDisplayMode( mlt_profile profile, int vancLines )
        {
@@ -89,17 +90,18 @@ public:
 
        ~DeckLinkProducer()
        {
-               if ( m_decklinkInput )
-                       m_decklinkInput->Release();
-               if ( m_decklink )
-                       m_decklink->Release();
                if ( m_queue )
                {
                        stop();
                        mlt_deque_close( m_queue );
                        pthread_mutex_destroy( &m_mutex );
                        pthread_cond_destroy( &m_condition );
+                       mlt_cache_close( m_cache );
                }
+               if ( m_decklinkInput )
+                       m_decklinkInput->Release();
+               if ( m_decklink )
+                       m_decklink->Release();
        }
 
        bool open( unsigned card =  0 )
@@ -142,6 +144,10 @@ public:
                        m_started = false;
                        m_dropped = 0;
                        m_isBuffering = true;
+                       m_cache = mlt_cache_init();
+
+                       // 3 covers YADIF and increasing framerate use cases
+                       mlt_cache_set_size( m_cache, 3 );
                }
                catch ( const char *error )
                {
@@ -240,12 +246,33 @@ public:
                pthread_mutex_unlock( &m_mutex );
        }
 
+       mlt_frame cloneFrame( mlt_frame frame )
+       {
+               mlt_frame new_frame = mlt_frame_init( NULL );
+               mlt_properties properties = MLT_FRAME_PROPERTIES( frame );
+               mlt_properties new_props = MLT_FRAME_PROPERTIES( new_frame );
+               void *data;
+               void *copy;
+               int size;
+
+               mlt_properties_inherit( new_props, properties );
+               mlt_properties_set_int( new_props, "audio_samples", 0 );
+               data = mlt_properties_get_data( properties, "image", &size );
+               copy = mlt_pool_alloc( size );
+               memcpy( copy, data, size );
+               mlt_properties_set_data( new_props, "image", copy, size, mlt_pool_release, NULL );
+
+               return new_frame;
+       }
+
        mlt_frame getFrame()
        {
                mlt_frame frame = NULL;
                struct timeval now;
                struct timespec tm;
                double fps = mlt_producer_get_fps( getProducer() );
+               mlt_position position = mlt_producer_position( getProducer() );
+               mlt_cache_item cached = mlt_cache_get( m_cache, (void*) position );
 
                // Allow the buffer to fill to the requested initial buffer level.
                if ( m_isBuffering )
@@ -270,24 +297,36 @@ public:
                        pthread_mutex_unlock( &m_mutex );
                }
 
-               // Wait if queue is empty
-               pthread_mutex_lock( &m_mutex );
-               while ( mlt_deque_count( m_queue ) < 1 )
+               if ( cached )
                {
-                       // Wait up to twice frame duration
-                       gettimeofday( &now, NULL );
-                       long usec = now.tv_sec * 1000000 + now.tv_usec;
-                       usec += 2000000 / fps;
-                       tm.tv_sec = usec / 1000000;
-                       tm.tv_nsec = (usec % 1000000) * 1000;
-                       if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
-                               // Stop waiting if error (timed out)
-                               break;
+                       // Copy cached frame instead of pulling from queue
+                       frame = cloneFrame( (mlt_frame) mlt_cache_item_data( cached, NULL ) );
+                       mlt_cache_item_close( cached );
                }
+               else
+               {
+                       // Wait if queue is empty
+                       pthread_mutex_lock( &m_mutex );
+                       while ( mlt_deque_count( m_queue ) < 1 )
+                       {
+                               // Wait up to twice frame duration
+                               gettimeofday( &now, NULL );
+                               long usec = now.tv_sec * 1000000 + now.tv_usec;
+                               usec += 2000000 / fps;
+                               tm.tv_sec = usec / 1000000;
+                               tm.tv_nsec = (usec % 1000000) * 1000;
+                               if ( pthread_cond_timedwait( &m_condition, &m_mutex, &tm ) )
+                                       // Stop waiting if error (timed out)
+                                       break;
+                       }
+                       frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
+                       pthread_mutex_unlock( &m_mutex );
 
-               // Get the first frame from the queue
-               frame = ( mlt_frame ) mlt_deque_pop_front( m_queue );
-               pthread_mutex_unlock( &m_mutex );
+                       // add to cache
+                       if ( frame )
+                               mlt_cache_put( m_cache, (void*) position, cloneFrame( frame ), 0,
+                                       (mlt_destructor) mlt_frame_close );
+               }
 
                // Set frame timestamp and properties
                if ( frame )
@@ -315,6 +354,9 @@ public:
                        mlt_properties_set_int( properties, "audio_channels",
                                mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "channels" ) );
                }
+               else
+                       mlt_log_warning( getProducer(), "buffer underrun\n" );
+
                return frame;
        }