]> git.sesse.net Git - vlc/blobdiff - modules/access/sdi.cpp
Implement semi-proper AddRef and Release.
[vlc] / modules / access / sdi.cpp
index e867f534ed5d6b8f4c47d0872abd276f1a4583b1..aae8cb6c27a10eaead26a64e278ebc1cadf2530e 100644 (file)
 static int  Open ( vlc_object_t * );
 static void Close( vlc_object_t * );
 
+#define CARD_INDEX_TEXT N_("Input card to use")
+#define CARD_INDEX_LONGTEXT N_( \
+    "SDI capture card to use, if multiple exist. " \
+    "The cards are numbered from 0." )
+
 #define MODE_TEXT N_("Desired input video mode")
 #define MODE_LONGTEXT N_( \
     "Desired input video mode for SDI captures. " \
@@ -69,6 +74,8 @@ vlc_module_begin ()
     set_category( CAT_INPUT )
     set_subcategory( SUBCAT_INPUT_ACCESS )
     
+    add_integer( "sdi-card-index", 0, NULL,
+                 CARD_INDEX_TEXT, CARD_INDEX_LONGTEXT, true )
     add_string( "sdi-mode", "pal ", NULL,
                  MODE_TEXT, MODE_LONGTEXT, true )
     add_integer( "sdi-caching", DEFAULT_PTS_DELAY / 1000, NULL,
@@ -118,17 +125,32 @@ struct demux_sys_t
 class DeckLinkCaptureDelegate : public IDeckLinkInputCallback
 {
 public:
-    DeckLinkCaptureDelegate( demux_t *p_demux ) : p_demux_(p_demux) {}
+    DeckLinkCaptureDelegate( demux_t *p_demux ) : m_ref_(1), p_demux_(p_demux) {}
 
-    // FIXME: These leak.
     virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, LPVOID *ppv) { return E_NOINTERFACE; }
-    virtual ULONG STDMETHODCALLTYPE AddRef(void) { return 1; }
-    virtual ULONG STDMETHODCALLTYPE Release(void) { return 1; }
+
+    // Note: AddRef() and Release() here are not thread safe.
+
+    virtual ULONG STDMETHODCALLTYPE AddRef(void)
+    {
+        return ++m_ref_;
+    }
+
+    virtual ULONG STDMETHODCALLTYPE Release(void)
+    {
+        if ( --m_ref_ == 0 )
+        {
+            delete this;
+            return 0;
+        }
+        return m_ref_;
+    }
 
     virtual HRESULT STDMETHODCALLTYPE VideoInputFormatChanged(BMDVideoInputFormatChangedEvents, IDeckLinkDisplayMode*, BMDDetectedVideoInputFormatFlags);
     virtual HRESULT STDMETHODCALLTYPE VideoInputFrameArrived(IDeckLinkVideoInputFrame*, IDeckLinkAudioInputPacket*);
 
 private:
+    int m_ref_;
     demux_t *p_demux_;
 };
 
@@ -208,9 +230,17 @@ HRESULT DeckLinkCaptureDelegate::VideoInputFrameArrived(IDeckLinkVideoInputFrame
     {
         vlc_mutex_lock( &p_sys->frame_lock );
         if( p_video_frame )
-            p_sys->p_video_frame = p_video_frame;  // FIXME: leak
+        {
+            if( p_sys->p_video_frame )
+                block_Release( p_sys->p_video_frame );
+            p_sys->p_video_frame = p_video_frame;
+        }
         if( p_audio_frame )
-            p_sys->p_audio_frame = p_audio_frame;  // FIXME: leak
+        {
+            if( p_sys->p_audio_frame )
+                block_Release( p_sys->p_audio_frame );
+            p_sys->p_audio_frame = p_audio_frame;
+        }
         vlc_cond_signal( &p_sys->has_frame );
         vlc_mutex_unlock( &p_sys->frame_lock );
     }
@@ -245,22 +275,46 @@ static int Open( vlc_object_t *p_this )
     if( !decklink_iterator )
     {
         msg_Err( p_demux, "DeckLink drivers not found." );
-        // FIXME: Leak here and several other error paths.
+        decklink_iterator->Release();
+        Close( p_this );
         return VLC_EGENERIC;
     }
 
     HRESULT result;
-    result = decklink_iterator->Next( &p_sys->p_card );
+
+    int i_card_index = var_CreateGetInteger( p_demux, "sdi-card-index" );
+    for( int i = 0; i <= i_card_index; ++i )
+    {
+        result = decklink_iterator->Next( &p_sys->p_card );
+        if( result != S_OK )
+            break;
+    }
+
+    decklink_iterator->Release();
 
     if( result != S_OK )
     {
-        msg_Err( p_demux, "No DeckLink PCI cards found" );
+        msg_Err( p_demux, "DeckLink PCI card %d not found", i_card_index );
+        Close( p_this );
         return VLC_EGENERIC;
     }
 
+    const char *psz_model_name;
+    result = p_sys->p_card->GetModelName( &psz_model_name );
+    
+    if( result != S_OK )
+    {
+        msg_Err( p_demux, "Could not get model name" );
+        Close( p_this );
+        return VLC_EGENERIC;
+    }
+
+    msg_Dbg( p_demux, "Opened DeckLink PCI card %d (%s)", i_card_index, psz_model_name );
+
     if( p_sys->p_card->QueryInterface( IID_IDeckLinkInput, (void**)&p_sys->p_input) != S_OK )
     {
         msg_Err( p_demux, "Card has no inputs" );
+        Close( p_this );
         return VLC_EGENERIC;
     }
    
@@ -269,6 +323,7 @@ static int Open( vlc_object_t *p_this )
     if( p_sys->p_card->QueryInterface( IID_IDeckLinkConfiguration, (void**)&p_config) != S_OK )
     {
         msg_Err( p_demux, "Failed to get configuration interface" );
+        Close( p_this );
         return VLC_EGENERIC;
     }
     
@@ -292,6 +347,9 @@ static int Open( vlc_object_t *p_this )
         {
             msg_Err( p_demux, "Invalid --sdi-video-connection specified; choose one of " \
                               "sdi, hdmi, opticalsdi, component, composite, or svideo." );
+            p_config->Release();
+            free( psz_tmp );
+            Close( p_this );
             return VLC_EGENERIC;
         }
         free( psz_tmp );
@@ -301,6 +359,8 @@ static int Open( vlc_object_t *p_this )
         if( result != S_OK )
         {
             msg_Err( p_demux, "Failed to set video input connection" );
+            p_config->Release();
+            Close( p_this );
             return VLC_EGENERIC;
         }
     } 
@@ -319,6 +379,7 @@ static int Open( vlc_object_t *p_this )
         {
             msg_Err( p_demux, "Invalid --sdi-audio-connection specified; choose one of " \
                               "embedded, aesebu, or analog." );
+            Close( p_this );
             return VLC_EGENERIC;
         }
         free( psz_tmp );
@@ -328,9 +389,13 @@ static int Open( vlc_object_t *p_this )
         if( result != S_OK )
         {
             msg_Err( p_demux, "Failed to set audio input connection" );
+            p_config->Release();
+            Close( p_this );
             return VLC_EGENERIC;
         }
-    } 
+    }
+
+    p_config->Release();
 
     // Get the list of display modes.
     IDeckLinkDisplayModeIterator *p_display_iterator;
@@ -338,12 +403,16 @@ static int Open( vlc_object_t *p_this )
     if( result != S_OK )
     {
         msg_Err( p_demux, "Failed to enumerate display modes" );
+        p_display_iterator->Release();
+        Close( p_this );
         return VLC_EGENERIC;
     }
     
     char *psz_display_mode = var_CreateGetString( p_demux, "sdi-mode" );
     if( !psz_display_mode || strlen( psz_display_mode ) == 0 || strlen( psz_display_mode ) > 4 ) {
         msg_Err( p_demux, "Missing or invalid --sdi-mode string" );
+        p_display_iterator->Release();
+        Close( p_this );
         return VLC_EGENERIC;
     }
 
@@ -377,6 +446,8 @@ static int Open( vlc_object_t *p_this )
         if( result != S_OK )
         {
             msg_Err( p_demux, "Failed to get display mode name" );
+            p_display_iterator->Release();
+            Close( p_this );
             return VLC_EGENERIC;
         }
 
@@ -385,6 +456,8 @@ static int Open( vlc_object_t *p_this )
         if( result != S_OK )
         {
             msg_Err( p_demux, "Failed to get frame rate" );
+            p_display_iterator->Release();
+            Close( p_this );
             return VLC_EGENERIC;
         }
 
@@ -428,11 +501,14 @@ static int Open( vlc_object_t *p_this )
         }
     }
 
+    p_display_iterator->Release();
+
     if( !b_found_mode )
     {
         msg_Err( p_demux, "Unknown SDI mode specified. " \
                           "Run VLC with -v --verbose-objects=-all,+sdi " \
                           "to get a list of supported modes." );
+        Close( p_this );
         return VLC_EGENERIC;
     }
 
@@ -440,6 +516,7 @@ static int Open( vlc_object_t *p_this )
     if( result != S_OK )
     {
         msg_Err( p_demux, "Failed to enable video input" );
+        Close( p_this );
         return VLC_EGENERIC;
     }
   
@@ -452,6 +529,7 @@ static int Open( vlc_object_t *p_this )
         if( result != S_OK )
         {
             msg_Err( p_demux, "Failed to enable audio input" );
+            Close( p_this );
             return VLC_EGENERIC;
         }
     }
@@ -463,6 +541,7 @@ static int Open( vlc_object_t *p_this )
     if( result != S_OK )
     {
         msg_Err( p_demux, "Failed to start streams" );
+        Close( p_this );
         return VLC_EGENERIC;
     }
 
@@ -475,7 +554,7 @@ static int Open( vlc_object_t *p_this )
     video_fmt.video.i_sar_den = 1;
     video_fmt.video.i_frame_rate = p_sys->i_fps_num;
     video_fmt.video.i_frame_rate_base = p_sys->i_fps_den;
-    video_fmt.i_bitrate = video_fmt.video.i_width * video_fmt.video.i_height * video_fmt.video.i_frame_rate * 2;
+    video_fmt.i_bitrate = video_fmt.video.i_width * video_fmt.video.i_height * video_fmt.video.i_frame_rate * 2 * 8;
     
     psz_tmp = var_CreateGetNonEmptyString( p_demux, "sdi-aspect-ratio" );
     if( psz_tmp )
@@ -519,6 +598,18 @@ static void Close( vlc_object_t *p_this )
     demux_t     *p_demux = (demux_t *)p_this;
     demux_sys_t *p_sys   = p_demux->p_sys;
 
+    if( p_sys->p_input )
+    {
+        p_sys->p_input->StopStreams();
+        p_sys->p_input->Release();
+    }
+
+    if( p_sys->p_card )
+        p_sys->p_card->Release();
+
+    if( p_sys->p_delegate )
+        p_sys->p_delegate->Release();
+
     free( p_sys );
 }