]> git.sesse.net Git - mlt/blobdiff - src/modules/decklink/producer_decklink.cpp
Fix compiler warnings due to non-virtual destructors.
[mlt] / src / modules / decklink / producer_decklink.cpp
index 93489091d8dc46955eceaf8ed8e727b3f4150e85..877c0eacc400742e3ea686e92eb3b2613b74f94e 100644 (file)
 #include <unistd.h>
 #include <limits.h>
 #include <sys/time.h>
-#ifdef WIN32
-#include <objbase.h>
-#include "DeckLinkAPI_h.h"
-#else
-#include "DeckLinkAPI.h"
-#endif
-
-#define SAFE_RELEASE(V) if (V) { V->Release(); V = NULL; }
+#include "common.h"
 
 class DeckLinkProducer
        : public IDeckLinkInputCallback
@@ -50,6 +43,7 @@ private:
        int              m_colorspace;
        int              m_vancLines;
        mlt_cache        m_cache;
+       bool             m_reprio;
 
        BMDDisplayMode getDisplayMode( mlt_profile profile, int vancLines )
        {
@@ -74,7 +68,7 @@ private:
 
                                if ( width == profile->width && p == profile->progressive
                                         && ( height + vancLines == profile->height || ( height == 486 && profile->height == 480 + vancLines ) )
-                                        && fps == mlt_profile_fps( profile ) )
+                                        && (int) fps == (int) mlt_profile_fps( profile ) )
                                        result = mode->GetDisplayMode();
                                SAFE_RELEASE( mode );
                        }
@@ -94,11 +88,12 @@ public:
 
        DeckLinkProducer()
        {
+               m_producer = NULL;
                m_decklink = NULL;
                m_decklinkInput = NULL;
        }
 
-       ~DeckLinkProducer()
+       virtual ~DeckLinkProducer()
        {
                if ( m_queue )
                {
@@ -112,55 +107,6 @@ public:
                SAFE_RELEASE( m_decklink );
        }
 
-       bool listDevices( mlt_properties properties )
-       {
-               IDeckLinkIterator* decklinkIterator = NULL;
-               try
-               {
-                       int i = 0;
-#ifdef WIN32
-                       HRESULT result =  CoInitialize( NULL );
-                       if ( FAILED( result ) )
-                               throw "COM initialization failed";
-                       result = CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator );
-                       if ( FAILED( result ) )
-                               throw "The DeckLink drivers are not installed.";
-#else
-                       decklinkIterator = CreateDeckLinkIteratorInstance();
-                       if ( !decklinkIterator )
-                               throw "The DeckLink drivers are not installed.";
-#endif
-                       for ( ; decklinkIterator->Next( &m_decklink ) == S_OK; i++ )
-                       {
-                               if ( m_decklink->QueryInterface( IID_IDeckLinkInput, (void**) &m_decklinkInput ) == S_OK )
-                               {
-                                       char *name = NULL;
-                                       if ( m_decklink->GetModelName( (const char**) &name ) == S_OK )
-                                       {
-                                               const char *format = "device.%d";
-                                               char *key = (char*) calloc( 1, strlen( format ) + 1 );
-
-                                               sprintf( key, format, i );
-                                               mlt_properties_set( properties, key, name );
-                                               free( key );
-                                               free( name );
-                                       }
-                                       SAFE_RELEASE( m_decklinkInput );
-                               }
-                               SAFE_RELEASE( m_decklink );
-                       }
-                       SAFE_RELEASE( decklinkIterator );
-                       mlt_properties_set_int( properties, "devices", i );
-                       return true;
-               }
-               catch ( const char *error )
-               {
-                       SAFE_RELEASE( decklinkIterator );
-                       mlt_log_error( getProducer(), "%s\n", error );
-                       return false;
-               }
-       }
-
        bool open( unsigned card =  0 )
        {
                IDeckLinkIterator* decklinkIterator = NULL;
@@ -178,7 +124,6 @@ public:
                        if ( !decklinkIterator )
                                throw "The DeckLink drivers are not installed.";
 #endif
-
                        // Connect to the Nth DeckLink instance
                        for ( unsigned i = 0; decklinkIterator->Next( &m_decklink ) == S_OK ; i++)
                        {
@@ -299,6 +244,8 @@ public:
                pthread_mutex_unlock( &m_mutex );
 
                m_decklinkInput->StopStreams();
+               m_decklinkInput->DisableVideoInput();
+               m_decklinkInput->DisableAudioInput();
 
                // Cleanup queue
                pthread_mutex_lock( &m_mutex );
@@ -309,12 +256,11 @@ public:
 
        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 );
+               mlt_frame frame = mlt_cache_get_frame( m_cache, position );
 
                // Allow the buffer to fill to the requested initial buffer level.
                if ( m_isBuffering )
@@ -339,13 +285,7 @@ public:
                        pthread_mutex_unlock( &m_mutex );
                }
 
-               if ( cached )
-               {
-                       // Copy cached frame instead of pulling from queue
-                       frame = mlt_frame_clone( (mlt_frame) mlt_cache_item_data( cached, NULL ), 0 );
-                       mlt_cache_item_close( cached );
-               }
-               else
+               if ( !frame )
                {
                        // Wait if queue is empty
                        pthread_mutex_lock( &m_mutex );
@@ -366,8 +306,10 @@ public:
 
                        // add to cache
                        if ( frame )
-                               mlt_cache_put( m_cache, (void*) position, mlt_frame_clone( frame, 1 ), 0,
-                                       (mlt_destructor) mlt_frame_close );
+                       {
+                               mlt_frame_set_position( frame, position );
+                               mlt_cache_put_frame( m_cache, frame );
+                       }
                }
 
                // Set frame timestamp and properties
@@ -416,6 +358,43 @@ public:
                        IDeckLinkVideoInputFrame* video,
                        IDeckLinkAudioInputPacket* audio )
        {
+               if( !m_reprio )
+               {
+                       mlt_properties properties = MLT_PRODUCER_PROPERTIES( getProducer() );
+
+                       if ( mlt_properties_get( properties, "priority" ) )
+                       {
+                               int r;
+                               pthread_t thread;
+                               pthread_attr_t tattr;
+                               struct sched_param param;
+
+                               pthread_attr_init(&tattr);
+                               pthread_attr_setschedpolicy(&tattr, SCHED_FIFO);
+
+                               if ( !strcmp( "max", mlt_properties_get( properties, "priority" ) ) )
+                                       param.sched_priority = sched_get_priority_max(SCHED_FIFO) - 1;
+                               else if ( !strcmp( "min", mlt_properties_get( properties, "priority" ) ) )
+                                       param.sched_priority = sched_get_priority_min(SCHED_FIFO) + 1;
+                               else
+                                       param.sched_priority = mlt_properties_get_int( properties, "priority" );
+
+                               pthread_attr_setschedparam(&tattr, &param);
+
+                               thread = pthread_self();
+
+                               r = pthread_setschedparam(thread, SCHED_FIFO, &param);
+                               if( r )
+                                       mlt_log_verbose( getProducer(),
+                                               "VideoInputFrameArrived: pthread_setschedparam returned %d\n", r);
+                               else
+                                       mlt_log_verbose( getProducer(),
+                                               "VideoInputFrameArrived: param.sched_priority=%d\n", param.sched_priority);
+                       };
+
+                       m_reprio = true;
+               };
+
                if ( mlt_properties_get_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "preview" ) &&
                        mlt_producer_get_speed( getProducer() ) == 0.0 && !mlt_deque_count( m_queue ))
                {
@@ -453,7 +432,7 @@ public:
                                                for ( int i = 1; i < m_vancLines + 1; i++ )
                                                {
                                                        if ( vanc->GetBufferForVerticalBlankingLine( i, &buffer ) == S_OK )
-                                                               swab( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() );
+                                                               swab2( (char*) buffer, (char*) image + ( i - 1 ) * video->GetRowBytes(), video->GetRowBytes() );
                                                        else
                                                                mlt_log_debug( getProducer(), "failed capture vanc line %d\n", i );
                                                }
@@ -466,7 +445,7 @@ public:
                                if ( image && buffer )
                                {
                                        size =  video->GetRowBytes() * video->GetHeight();
-                                       swab( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size );
+                                       swab2( (char*) buffer, (char*) image + m_vancLines * video->GetRowBytes(), size );
                                        mlt_frame_set_image( frame, (uint8_t*) image, size, mlt_pool_release );
                                }
                                else if ( image )
@@ -486,19 +465,16 @@ public:
                        IDeckLinkTimecode* timecode = 0;
                        if ( video->GetTimecode( bmdTimecodeVITC, &timecode ) == S_OK && timecode )
                        {
-                               const char* timecodeString = 0;
+                               DLString timecodeString = 0;
 
-#ifdef WIN32
-                               if ( timecode->GetString( (BSTR*) &timecodeString ) == S_OK )
-#else
                                if ( timecode->GetString( &timecodeString ) == S_OK )
-#endif
                                {
-                                       mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", timecodeString );
-                                       mlt_log_debug( getProducer(), "timecode %s\n", timecodeString );
+                                       char* s = getCString( timecodeString );
+                                       mlt_properties_set( MLT_FRAME_PROPERTIES( frame ), "meta.attr.vitc.markup", s );
+                                       mlt_log_debug( getProducer(), "timecode %s\n", s );
+                                       freeCString( s );
                                }
-                               if ( timecodeString )
-                                       free( (void*) timecodeString );
+                               freeDLString( timecodeString );
                                SAFE_RELEASE( timecode );
                        }
                }
@@ -550,7 +526,7 @@ public:
                        {
                                mlt_frame_close( frame );
                                mlt_properties_set_int( MLT_PRODUCER_PROPERTIES( getProducer() ), "dropped", ++m_dropped );
-                               mlt_log_warning( getProducer(), "frame dropped %d\n", m_dropped );
+                               mlt_log_warning( getProducer(), "buffer overrun, frame dropped %d\n", m_dropped );
                        }
                        pthread_mutex_unlock( &m_mutex );
                }
@@ -659,7 +635,6 @@ static int get_frame( mlt_producer producer, mlt_frame_ptr frame, int index )
                *frame = mlt_frame_init( MLT_PRODUCER_SERVICE(producer) );
 
        // Calculate the next timecode
-       mlt_frame_set_position( *frame, mlt_producer_position( producer ) );
        mlt_producer_prepare_next( producer );
 
        // Close DeckLink if at end
@@ -682,6 +657,53 @@ static void producer_close( mlt_producer producer )
 
 extern "C" {
 
+// Listen for the list_devices property to be set
+static void on_property_changed( void*, mlt_properties properties, const char *name )
+{
+       IDeckLinkIterator* decklinkIterator = NULL;
+       IDeckLink* decklink = NULL;
+       IDeckLinkInput* decklinkInput = NULL;
+       int i = 0;
+
+       if ( name && !strcmp( name, "list_devices" ) )
+               mlt_event_block( (mlt_event) mlt_properties_get_data( properties, "list-devices-event", NULL ) );
+       else
+               return;
+
+#ifdef WIN32
+       if ( FAILED( CoInitialize( NULL ) ) )
+               return;
+       if ( FAILED( CoCreateInstance( CLSID_CDeckLinkIterator, NULL, CLSCTX_ALL, IID_IDeckLinkIterator, (void**) &decklinkIterator ) ) )
+               return;
+#else
+       if ( !( decklinkIterator = CreateDeckLinkIteratorInstance() ) )
+               return;
+#endif
+       for ( ; decklinkIterator->Next( &decklink ) == S_OK; i++ )
+       {
+               if ( decklink->QueryInterface( IID_IDeckLinkInput, (void**) &decklinkInput ) == S_OK )
+               {
+                       DLString name = NULL;
+                       if ( decklink->GetModelName( &name ) == S_OK )
+                       {
+                               char *name_cstr = getCString( name );
+                               const char *format = "device.%d";
+                               char *key = (char*) calloc( 1, strlen( format ) + 1 );
+
+                               sprintf( key, format, i );
+                               mlt_properties_set( properties, key, name_cstr );
+                               free( key );
+                               freeDLString( name );
+                               freeCString( name_cstr );
+                       }
+                       SAFE_RELEASE( decklinkInput );
+               }
+               SAFE_RELEASE( decklink );
+       }
+       SAFE_RELEASE( decklinkIterator );
+       mlt_properties_set_int( properties, "devices", i );
+}
+
 /** Initialise the producer.
  */
 
@@ -694,8 +716,7 @@ mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type,
        // If allocated and initializes
        if ( decklink && !mlt_producer_init( producer, decklink ) )
        {
-               if ( decklink->listDevices( MLT_PRODUCER_PROPERTIES( producer ) ) &&
-                        decklink->open( arg? atoi( arg ) : 0 ) )
+               if ( decklink->open( arg? atoi( arg ) : 0 ) )
                {
                        mlt_properties properties = MLT_PRODUCER_PROPERTIES( producer );
 
@@ -717,6 +738,9 @@ mlt_producer producer_decklink_init( mlt_profile profile, mlt_service_type type,
                        mlt_properties_set_int( properties, "length", INT_MAX );
                        mlt_properties_set_int( properties, "out", INT_MAX - 1 );
                        mlt_properties_set( properties, "eof", "loop" );
+
+                       mlt_event event = mlt_events_listen( properties, properties, "property-changed", (mlt_listener) on_property_changed );
+                       mlt_properties_set_data( properties, "list-devices-event", event, 0, NULL, NULL );
                }
        }