]> git.sesse.net Git - mlt/blobdiff - src/modules/decklink/consumer_decklink.cpp
Initialize all decklink interface pointers and reset them upon release.
[mlt] / src / modules / decklink / consumer_decklink.cpp
index 3a6316e90070c0bc57cfce849d6d0746bcfc8295..288e52f2a3ea8e0f4bec4b65f6c7027ca6b13cc5 100644 (file)
@@ -33,6 +33,8 @@
 #include "DeckLinkAPI.h"
 #endif
 
+#define SAFE_RELEASE(V) if (V) { V->Release(); V = NULL; }
+
 static const unsigned PREROLL_MINIMUM = 3;
 
 class DeckLinkConsumer
@@ -64,8 +66,8 @@ private:
        IDeckLinkDisplayMode* getDisplayMode()
        {
                mlt_profile profile = mlt_service_profile( MLT_CONSUMER_SERVICE( getConsumer() ) );
-               IDeckLinkDisplayModeIterator* iter;
-               IDeckLinkDisplayMode* mode;
+               IDeckLinkDisplayModeIterator* iter = NULL;
+               IDeckLinkDisplayMode* mode = NULL;
                IDeckLinkDisplayMode* result = 0;
                
                if ( m_deckLinkOutput->GetDisplayModeIterator( &iter ) == S_OK )
@@ -83,7 +85,10 @@ private:
                                         && m_fps == mlt_profile_fps( profile )
                                         && ( m_height == profile->height || ( m_height == 486 && profile->height == 480 ) ) )
                                        result = mode;
+                               else
+                                       SAFE_RELEASE( mode );
                        }
+                       SAFE_RELEASE( iter );
                }
                
                return result;
@@ -92,17 +97,75 @@ private:
 public:
        mlt_consumer getConsumer()
                { return &m_consumer; }
-       
+
+       DeckLinkConsumer()
+       {
+               m_displayMode = NULL;
+               m_deckLinkKeyer = NULL;
+               m_deckLinkOutput = NULL;
+               m_deckLink = NULL;
+       }
+
        ~DeckLinkConsumer()
        {
-               if ( m_deckLinkKeyer )
-                       m_deckLinkKeyer->Release();
-               if ( m_deckLinkOutput )
-                       m_deckLinkOutput->Release();
-               if ( m_deckLink )
-                       m_deckLink->Release();
+               SAFE_RELEASE( m_displayMode );
+               SAFE_RELEASE( m_deckLinkKeyer );
+               SAFE_RELEASE( m_deckLinkOutput );
+               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_IDeckLinkOutput, (void**) &m_deckLinkOutput ) == 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 );
+                                               mlt_log_verbose( NULL, "[consumer decklink] %s = %s\n", key, name );
+                                               free( key );
+                                               free( name );
+                                       }
+                                       SAFE_RELEASE( m_deckLinkOutput );
+                               }
+                               SAFE_RELEASE( m_deckLink );
+                       }
+                       SAFE_RELEASE( decklinkIterator );
+                       mlt_properties_set_int( properties, "devices", i );
+                       mlt_log_verbose( NULL, "[consumer decklink] devices = %d\n", i );
+
+                       return true;
+               }
+               catch ( const char *error )
+               {
+                       SAFE_RELEASE( decklinkIterator );
+                       mlt_log_error( getConsumer(), "%s\n", error );
+                       return false;
+               }
+       }
+
        bool open( unsigned card = 0 )
        {
                unsigned i = 0;
@@ -129,30 +192,32 @@ public:
                        return false;
                }
 #endif
-               
+
                // Connect to the Nth DeckLink instance
-               do {
-                       if ( deckLinkIterator->Next( &m_deckLink ) != S_OK )
-                       {
-                               mlt_log_error( getConsumer(), "DeckLink card not found\n" );
-                               deckLinkIterator->Release();
-                               return false;
-                       }
-               } while ( ++i <= card );
-               deckLinkIterator->Release();
-               
+               for ( i = 0; deckLinkIterator->Next( &m_deckLink ) == S_OK ; i++)
+               {
+                       if( i == card )
+                               break;
+                       else
+                               SAFE_RELEASE( m_deckLink );
+               }
+               SAFE_RELEASE( deckLinkIterator );
+               if ( !m_deckLink )
+               {
+                       mlt_log_error( getConsumer(), "DeckLink card not found\n" );
+                       return false;
+               }
+
                // Obtain the audio/video output interface (IDeckLinkOutput)
                if ( m_deckLink->QueryInterface( IID_IDeckLinkOutput, (void**)&m_deckLinkOutput ) != S_OK )
                {
                        mlt_log_error( getConsumer(), "No DeckLink cards support output\n" );
-                       m_deckLink->Release();
-                       m_deckLink = 0;
+                       SAFE_RELEASE( m_deckLink );
                        return false;
                }
                
                // Get the keyer interface
                IDeckLinkAttributes *deckLinkAttributes = 0;
-               m_deckLinkKeyer = 0;
                if ( m_deckLink->QueryInterface( IID_IDeckLinkAttributes, (void**) &deckLinkAttributes ) == S_OK )
                {
 #ifdef WIN32
@@ -165,14 +230,12 @@ public:
                                if ( m_deckLink->QueryInterface( IID_IDeckLinkKeyer, (void**) &m_deckLinkKeyer ) != S_OK )
                                {
                                        mlt_log_error( getConsumer(), "Failed to get keyer\n" );
-                                       m_deckLinkOutput->Release();
-                                       m_deckLinkOutput = 0;
-                                       m_deckLink->Release();
-                                       m_deckLink = 0;
+                                       SAFE_RELEASE( m_deckLinkOutput );
+                                       SAFE_RELEASE( m_deckLink );
                                        return false;
                                }
                        }
-                       deckLinkAttributes->Release();
+                       SAFE_RELEASE( deckLinkAttributes );
                }
 
                // Provide this class as a delegate to the audio and video output interfaces
@@ -273,6 +336,7 @@ public:
        bool stop()
        {
                mlt_properties properties = MLT_CONSUMER_PROPERTIES( getConsumer() );
+               bool wasRunning = !!mlt_properties_get_int( properties, "running" );
 
                // set running state is 0
                mlt_properties_set_int( properties, "running", 0 );
@@ -287,13 +351,10 @@ public:
                }
 
                // release decklink frame
-               if ( m_decklinkFrame )
-                       m_decklinkFrame->Release();
-               m_decklinkFrame = NULL;
+               SAFE_RELEASE( m_decklinkFrame );
 
-               if ( m_prerollThread )
+               if ( wasRunning )
                        pthread_join( m_prerollThread, NULL );
-               m_prerollThread = 0;
 
                return true;
        }
@@ -379,8 +440,7 @@ public:
                        uint8_t* buffer = 0;
                        int stride = m_width * ( m_isKeyer? 4 : 2 );
 
-                       if ( m_decklinkFrame )
-                               m_decklinkFrame->Release();
+                       SAFE_RELEASE( m_decklinkFrame );
                        if ( createFrame( &m_decklinkFrame ) )
                                m_decklinkFrame->GetBytes( (void**) &buffer );
 
@@ -510,7 +570,7 @@ public:
                                r = pthread_setschedparam(thread, SCHED_FIFO, &param);
                                if( r )
                                        mlt_log_verbose( getConsumer(),
-                                               "ScheduledFrameCompleted: pthread_setschedparam retured %d\n", r);
+                                               "ScheduledFrameCompleted: pthread_setschedparam returned %d\n", r);
                                else
                                        mlt_log_verbose( getConsumer(),
                                                "ScheduledFrameCompleted: param.sched_priority=%d\n", param.sched_priority);
@@ -527,7 +587,7 @@ public:
                m_deckLinkOutput->GetBufferedAudioSampleFrameCount( &cnt );
                if ( cnt != m_acnt )
                {
-                       mlt_log_verbose( getConsumer(),
+                       mlt_log_debug( getConsumer(),
                                "ScheduledFrameCompleted: GetBufferedAudioSampleFrameCount %u -> %lu, m_count=%"PRIu64"\n",
                                m_acnt, cnt, m_count );
                        m_acnt = cnt;
@@ -656,7 +716,8 @@ mlt_consumer consumer_decklink_init( mlt_profile profile, mlt_service_type type,
        if ( decklink && !mlt_consumer_init( decklink->getConsumer(), decklink, profile ) )
        {
                // If initialises without error
-               if ( decklink->open( arg? atoi(arg) : 0 ) )
+               if ( decklink->listDevices( MLT_CONSUMER_PROPERTIES( decklink->getConsumer() ) ) &&
+                        decklink->open( arg? atoi(arg) : 0 ) )
                {
                        consumer = decklink->getConsumer();